/* * QEMU Chihiro USB Devices * * Copyright (c) 2016 espes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #include "qemu/osdep.h" #include "hw/hw.h" #include "ui/console.h" #include "hw/usb.h" #include "hw/usb/desc.h" // #define DEBUG_CUSB #ifdef DEBUG_CUSB #define DPRINTF(s, ...) printf("chihiro-usb: " s, ## __VA_ARGS__) #else #define DPRINTF(...) #endif typedef struct ChihiroUSBState { USBDevice dev; } ChihiroUSBState; enum chihiro_usb_strings { STRING_SERIALNUMBER, STRING_MANUFACTURER, STRING_PRODUCT, }; static const USBDescStrings chihiro_usb_stringtable = { [STRING_SERIALNUMBER] = "\x00", [STRING_MANUFACTURER] = "SEGA", [STRING_PRODUCT] = "BASEBD" // different for qc? }; static const USBDescIface desc_iface_chihiro_an2131qc = { .bInterfaceNumber = 0, .bNumEndpoints = 10, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 0x00, .bInterfaceProtocol = 0x00, .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | 0x01, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_OUT | 0x02, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_OUT | 0x03, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_OUT | 0x04, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_OUT | 0x05, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_IN | 0x01, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_IN | 0x02, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_IN | 0x03, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_IN | 0x04, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_IN | 0x05, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, }, }; static const USBDescDevice desc_device_chihiro_an2131qc = { .bcdUSB = 0x0100, .bMaxPacketSize0 = 0x40, .bNumConfigurations = 1, .confs = (USBDescConfig[]) { { .bNumInterfaces = 1, .bConfigurationValue = 1, .bmAttributes = 0x80, .bMaxPower = 0x96, .nif = 1, .ifs = &desc_iface_chihiro_an2131qc, }, }, }; static const USBDesc desc_chihiro_an2131qc = { .id = { .idVendor = 0x0CA3, .idProduct = 0x0002, .bcdDevice = 0x0108, .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, .iSerialNumber = STRING_SERIALNUMBER, }, .full = &desc_device_chihiro_an2131qc, .str = chihiro_usb_stringtable, }; static const USBDescIface desc_iface_chihiro_an2131sc = { .bInterfaceNumber = 0, .bNumEndpoints = 6, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 0x00, .bInterfaceProtocol = 0x00, .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | 0x01, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_OUT | 0x02, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_OUT | 0x03, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_IN | 0x01, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_IN | 0x02, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, { .bEndpointAddress = USB_DIR_IN | 0x03, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = 0x0040, .bInterval = 0, }, }, }; static const USBDescDevice desc_device_chihiro_an2131sc = { .bcdUSB = 0x0100, .bMaxPacketSize0 = 0x40, .bNumConfigurations = 1, .confs = (USBDescConfig[]) { { .bNumInterfaces = 1, .bConfigurationValue = 1, .bmAttributes = 0x80, .bMaxPower = 0x96, .nif = 1, .ifs = &desc_iface_chihiro_an2131sc, }, }, }; static const USBDesc desc_chihiro_an2131sc = { .id = { .idVendor = 0x0CA3, .idProduct = 0x0003, .bcdDevice = 0x0110, .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, .iSerialNumber = STRING_SERIALNUMBER, }, .full = &desc_device_chihiro_an2131sc, .str = chihiro_usb_stringtable, }; static void handle_reset(USBDevice *dev) { DPRINTF("usb reset\n"); } static void handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { DPRINTF("handle control %d %d %d %d\n", request, value, index, length); int ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { DPRINTF("handled by usb_desc_handle_control: %d\n", ret); return; } } static void handle_data(USBDevice *dev, USBPacket *p) { DPRINTF("handle_data 0x%x %d 0x%zx\n", p->pid, p->ep->nr, p->iov.size); } static void chihiro_an2131qc_realize(USBDevice *dev, Error **errp) { // ChihiroUSBState *s = DO_UPCAST(ChihiroUSBState, dev, dev); usb_desc_init(dev); } static void chihiro_an2131qc_unrealize(USBDevice *dev) { } static void chihiro_an2131qc_class_initfn(ObjectClass *klass, void *data) { // DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); uc->realize = chihiro_an2131qc_realize; uc->unrealize = chihiro_an2131qc_unrealize; uc->product_desc = "Chihiro an2131qc"; uc->usb_desc = &desc_chihiro_an2131qc; uc->handle_reset = handle_reset; uc->handle_control = handle_control; uc->handle_data = handle_data; uc->handle_attach = usb_desc_attach; //dc->vmsd = &vmstate_usb_kbd; } static const TypeInfo chihiro_an2131qc_info = { .name = "chihiro-an2131qc", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(ChihiroUSBState), .class_init = chihiro_an2131qc_class_initfn, }; static void chihiro_an2131sc_realize(USBDevice *dev, Error **errp) { // ChihiroUSBState *s = DO_UPCAST(ChihiroUSBState, dev, dev); usb_desc_init(dev); } static void chihiro_an2131sc_unrealize(USBDevice *dev) { } static void chihiro_an2131sc_class_initfn(ObjectClass *klass, void *data) { // DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); uc->realize = chihiro_an2131sc_realize; uc->unrealize = chihiro_an2131sc_unrealize; uc->product_desc = "Chihiro an2131sc"; uc->usb_desc = &desc_chihiro_an2131sc; uc->handle_reset = handle_reset; uc->handle_control = handle_control; uc->handle_data = handle_data; uc->handle_attach = usb_desc_attach; //dc->vmsd = &vmstate_usb_kbd; } static const TypeInfo chihiro_an2131sc_info = { .name = "chihiro-an2131sc", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(ChihiroUSBState), .class_init = chihiro_an2131sc_class_initfn, }; static void chihiro_usb_register_types(void) { type_register_static(&chihiro_an2131qc_info); type_register_static(&chihiro_an2131sc_info); } type_init(chihiro_usb_register_types)