Annotation of qemu/hw/usb/dev-serial.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * FTDI FT232BM Device emulation
                      3:  *
                      4:  * Copyright (c) 2006 CodeSourcery.
                      5:  * Copyright (c) 2008 Samuel Thibault <[email protected]>
                      6:  * Written by Paul Brook, reused for FTDI by Samuel Thibault
                      7:  *
                      8:  * This code is licensed under the LGPL.
                      9:  */
                     10: 
                     11: #include "qemu-common.h"
                     12: #include "qemu-error.h"
                     13: #include "hw/usb.h"
                     14: #include "hw/usb/desc.h"
                     15: #include "qemu-char.h"
                     16: 
                     17: //#define DEBUG_Serial
                     18: 
                     19: #ifdef DEBUG_Serial
                     20: #define DPRINTF(fmt, ...) \
                     21: do { printf("usb-serial: " fmt , ## __VA_ARGS__); } while (0)
                     22: #else
                     23: #define DPRINTF(fmt, ...) do {} while(0)
                     24: #endif
                     25: 
                     26: #define RECV_BUF 384
                     27: 
                     28: /* Commands */
                     29: #define FTDI_RESET             0
                     30: #define FTDI_SET_MDM_CTRL      1
                     31: #define FTDI_SET_FLOW_CTRL     2
                     32: #define FTDI_SET_BAUD          3
                     33: #define FTDI_SET_DATA          4
                     34: #define FTDI_GET_MDM_ST                5
                     35: #define FTDI_SET_EVENT_CHR     6
                     36: #define FTDI_SET_ERROR_CHR     7
                     37: #define FTDI_SET_LATENCY       9
                     38: #define FTDI_GET_LATENCY       10
                     39: 
                     40: #define DeviceOutVendor        ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
                     41: #define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
                     42: 
                     43: /* RESET */
                     44: 
                     45: #define FTDI_RESET_SIO 0
                     46: #define FTDI_RESET_RX  1
                     47: #define FTDI_RESET_TX  2
                     48: 
                     49: /* SET_MDM_CTRL */
                     50: 
                     51: #define FTDI_DTR       1
                     52: #define FTDI_SET_DTR   (FTDI_DTR << 8)
                     53: #define FTDI_RTS       2
                     54: #define FTDI_SET_RTS   (FTDI_RTS << 8)
                     55: 
                     56: /* SET_FLOW_CTRL */
                     57: 
                     58: #define FTDI_RTS_CTS_HS                1
                     59: #define FTDI_DTR_DSR_HS                2
                     60: #define FTDI_XON_XOFF_HS       4
                     61: 
                     62: /* SET_DATA */
                     63: 
                     64: #define FTDI_PARITY    (0x7 << 8)
                     65: #define FTDI_ODD       (0x1 << 8)
                     66: #define FTDI_EVEN      (0x2 << 8)
                     67: #define FTDI_MARK      (0x3 << 8)
                     68: #define FTDI_SPACE     (0x4 << 8)
                     69: 
                     70: #define FTDI_STOP      (0x3 << 11)
                     71: #define FTDI_STOP1     (0x0 << 11)
                     72: #define FTDI_STOP15    (0x1 << 11)
                     73: #define FTDI_STOP2     (0x2 << 11)
                     74: 
                     75: /* GET_MDM_ST */
                     76: /* TODO: should be sent every 40ms */
                     77: #define FTDI_CTS  (1<<4)        // CTS line status
                     78: #define FTDI_DSR  (1<<5)        // DSR line status
                     79: #define FTDI_RI   (1<<6)        // RI line status
                     80: #define FTDI_RLSD (1<<7)        // Receive Line Signal Detect
                     81: 
                     82: /* Status */
                     83: 
                     84: #define FTDI_DR   (1<<0)        // Data Ready
                     85: #define FTDI_OE   (1<<1)        // Overrun Err
                     86: #define FTDI_PE   (1<<2)        // Parity Err
                     87: #define FTDI_FE   (1<<3)        // Framing Err
                     88: #define FTDI_BI   (1<<4)        // Break Interrupt
                     89: #define FTDI_THRE (1<<5)        // Transmitter Holding Register
                     90: #define FTDI_TEMT (1<<6)        // Transmitter Empty
                     91: #define FTDI_FIFO (1<<7)        // Error in FIFO
                     92: 
                     93: typedef struct {
                     94:     USBDevice dev;
                     95:     uint8_t recv_buf[RECV_BUF];
                     96:     uint16_t recv_ptr;
                     97:     uint16_t recv_used;
                     98:     uint8_t event_chr;
                     99:     uint8_t error_chr;
                    100:     uint8_t event_trigger;
                    101:     QEMUSerialSetParams params;
                    102:     int latency;        /* ms */
                    103:     CharDriverState *cs;
                    104: } USBSerialState;
                    105: 
                    106: enum {
                    107:     STR_MANUFACTURER = 1,
                    108:     STR_PRODUCT_SERIAL,
                    109:     STR_PRODUCT_BRAILLE,
                    110:     STR_SERIALNUMBER,
                    111: };
                    112: 
                    113: static const USBDescStrings desc_strings = {
                    114:     [STR_MANUFACTURER]    = "QEMU " QEMU_VERSION,
                    115:     [STR_PRODUCT_SERIAL]  = "QEMU USB SERIAL",
                    116:     [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE",
                    117:     [STR_SERIALNUMBER]    = "1",
                    118: };
                    119: 
                    120: static const USBDescIface desc_iface0 = {
                    121:     .bInterfaceNumber              = 0,
                    122:     .bNumEndpoints                 = 2,
                    123:     .bInterfaceClass               = 0xff,
                    124:     .bInterfaceSubClass            = 0xff,
                    125:     .bInterfaceProtocol            = 0xff,
                    126:     .eps = (USBDescEndpoint[]) {
                    127:         {
                    128:             .bEndpointAddress      = USB_DIR_IN | 0x01,
                    129:             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
                    130:             .wMaxPacketSize        = 64,
                    131:         },{
                    132:             .bEndpointAddress      = USB_DIR_OUT | 0x02,
                    133:             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
                    134:             .wMaxPacketSize        = 64,
                    135:         },
                    136:     }
                    137: };
                    138: 
                    139: static const USBDescDevice desc_device = {
                    140:     .bcdUSB                        = 0x0200,
                    141:     .bMaxPacketSize0               = 8,
                    142:     .bNumConfigurations            = 1,
                    143:     .confs = (USBDescConfig[]) {
                    144:         {
                    145:             .bNumInterfaces        = 1,
                    146:             .bConfigurationValue   = 1,
                    147:             .bmAttributes          = 0x80,
                    148:             .bMaxPower             = 50,
                    149:             .nif = 1,
                    150:             .ifs = &desc_iface0,
                    151:         },
                    152:     },
                    153: };
                    154: 
                    155: static const USBDesc desc_serial = {
                    156:     .id = {
                    157:         .idVendor          = 0x0403,
                    158:         .idProduct         = 0x6001,
                    159:         .bcdDevice         = 0x0400,
                    160:         .iManufacturer     = STR_MANUFACTURER,
                    161:         .iProduct          = STR_PRODUCT_SERIAL,
                    162:         .iSerialNumber     = STR_SERIALNUMBER,
                    163:     },
                    164:     .full = &desc_device,
                    165:     .str  = desc_strings,
                    166: };
                    167: 
                    168: static const USBDesc desc_braille = {
                    169:     .id = {
                    170:         .idVendor          = 0x0403,
                    171:         .idProduct         = 0xfe72,
                    172:         .bcdDevice         = 0x0400,
                    173:         .iManufacturer     = STR_MANUFACTURER,
                    174:         .iProduct          = STR_PRODUCT_BRAILLE,
                    175:         .iSerialNumber     = STR_SERIALNUMBER,
                    176:     },
                    177:     .full = &desc_device,
                    178:     .str  = desc_strings,
                    179: };
                    180: 
                    181: static void usb_serial_reset(USBSerialState *s)
                    182: {
                    183:     /* TODO: Set flow control to none */
                    184:     s->event_chr = 0x0d;
                    185:     s->event_trigger = 0;
                    186:     s->recv_ptr = 0;
                    187:     s->recv_used = 0;
                    188:     /* TODO: purge in char driver */
                    189: }
                    190: 
                    191: static void usb_serial_handle_reset(USBDevice *dev)
                    192: {
                    193:     USBSerialState *s = (USBSerialState *)dev;
                    194: 
                    195:     DPRINTF("Reset\n");
                    196: 
                    197:     usb_serial_reset(s);
                    198:     /* TODO: Reset char device, send BREAK? */
                    199: }
                    200: 
                    201: static uint8_t usb_get_modem_lines(USBSerialState *s)
                    202: {
                    203:     int flags;
                    204:     uint8_t ret;
                    205: 
                    206:     if (qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP)
                    207:         return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
                    208: 
                    209:     ret = 0;
                    210:     if (flags & CHR_TIOCM_CTS)
                    211:         ret |= FTDI_CTS;
                    212:     if (flags & CHR_TIOCM_DSR)
                    213:         ret |= FTDI_DSR;
                    214:     if (flags & CHR_TIOCM_RI)
                    215:         ret |= FTDI_RI;
                    216:     if (flags & CHR_TIOCM_CAR)
                    217:         ret |= FTDI_RLSD;
                    218: 
                    219:     return ret;
                    220: }
                    221: 
                    222: static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
                    223:                int request, int value, int index, int length, uint8_t *data)
                    224: {
                    225:     USBSerialState *s = (USBSerialState *)dev;
                    226:     int ret;
                    227: 
                    228:     DPRINTF("got control %x, value %x\n",request, value);
                    229:     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
                    230:     if (ret >= 0) {
                    231:         return ret;
                    232:     }
                    233: 
                    234:     ret = 0;
                    235:     switch (request) {
                    236:     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
                    237:         ret = 0;
                    238:         break;
                    239: 
                    240:         /* Class specific requests.  */
                    241:     case DeviceOutVendor | FTDI_RESET:
                    242:         switch (value) {
                    243:         case FTDI_RESET_SIO:
                    244:             usb_serial_reset(s);
                    245:             break;
                    246:         case FTDI_RESET_RX:
                    247:             s->recv_ptr = 0;
                    248:             s->recv_used = 0;
                    249:             /* TODO: purge from char device */
                    250:             break;
                    251:         case FTDI_RESET_TX:
                    252:             /* TODO: purge from char device */
                    253:             break;
                    254:         }
                    255:         break;
                    256:     case DeviceOutVendor | FTDI_SET_MDM_CTRL:
                    257:     {
                    258:         static int flags;
                    259:         qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
                    260:         if (value & FTDI_SET_RTS) {
                    261:             if (value & FTDI_RTS)
                    262:                 flags |= CHR_TIOCM_RTS;
                    263:             else
                    264:                 flags &= ~CHR_TIOCM_RTS;
                    265:         }
                    266:         if (value & FTDI_SET_DTR) {
                    267:             if (value & FTDI_DTR)
                    268:                 flags |= CHR_TIOCM_DTR;
                    269:             else
                    270:                 flags &= ~CHR_TIOCM_DTR;
                    271:         }
                    272:         qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
                    273:         break;
                    274:     }
                    275:     case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
                    276:         /* TODO: ioctl */
                    277:         break;
                    278:     case DeviceOutVendor | FTDI_SET_BAUD: {
                    279:         static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
                    280:         int subdivisor8 = subdivisors8[((value & 0xc000) >> 14)
                    281:                                      | ((index & 1) << 2)];
                    282:         int divisor = value & 0x3fff;
                    283: 
                    284:         /* chip special cases */
                    285:         if (divisor == 1 && subdivisor8 == 0)
                    286:             subdivisor8 = 4;
                    287:         if (divisor == 0 && subdivisor8 == 0)
                    288:             divisor = 1;
                    289: 
                    290:         s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
                    291:         qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
                    292:         break;
                    293:     }
                    294:     case DeviceOutVendor | FTDI_SET_DATA:
                    295:         switch (value & FTDI_PARITY) {
                    296:             case 0:
                    297:                 s->params.parity = 'N';
                    298:                 break;
                    299:             case FTDI_ODD:
                    300:                 s->params.parity = 'O';
                    301:                 break;
                    302:             case FTDI_EVEN:
                    303:                 s->params.parity = 'E';
                    304:                 break;
                    305:             default:
                    306:                 DPRINTF("unsupported parity %d\n", value & FTDI_PARITY);
                    307:                 goto fail;
                    308:         }
                    309:         switch (value & FTDI_STOP) {
                    310:             case FTDI_STOP1:
                    311:                 s->params.stop_bits = 1;
                    312:                 break;
                    313:             case FTDI_STOP2:
                    314:                 s->params.stop_bits = 2;
                    315:                 break;
                    316:             default:
                    317:                 DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
                    318:                 goto fail;
                    319:         }
                    320:         qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
                    321:         /* TODO: TX ON/OFF */
                    322:         break;
                    323:     case DeviceInVendor | FTDI_GET_MDM_ST:
                    324:         data[0] = usb_get_modem_lines(s) | 1;
                    325:         data[1] = 0;
                    326:         ret = 2;
                    327:         break;
                    328:     case DeviceOutVendor | FTDI_SET_EVENT_CHR:
                    329:         /* TODO: handle it */
                    330:         s->event_chr = value;
                    331:         break;
                    332:     case DeviceOutVendor | FTDI_SET_ERROR_CHR:
                    333:         /* TODO: handle it */
                    334:         s->error_chr = value;
                    335:         break;
                    336:     case DeviceOutVendor | FTDI_SET_LATENCY:
                    337:         s->latency = value;
                    338:         break;
                    339:     case DeviceInVendor | FTDI_GET_LATENCY:
                    340:         data[0] = s->latency;
                    341:         ret = 1;
                    342:         break;
                    343:     default:
                    344:     fail:
                    345:         DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
                    346:         ret = USB_RET_STALL;
                    347:         break;
                    348:     }
                    349:     return ret;
                    350: }
                    351: 
                    352: static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
                    353: {
                    354:     USBSerialState *s = (USBSerialState *)dev;
                    355:     int i, ret = 0;
                    356:     uint8_t devep = p->ep->nr;
                    357:     struct iovec *iov;
                    358:     uint8_t header[2];
                    359:     int first_len, len;
                    360: 
                    361:     switch (p->pid) {
                    362:     case USB_TOKEN_OUT:
                    363:         if (devep != 2)
                    364:             goto fail;
                    365:         for (i = 0; i < p->iov.niov; i++) {
                    366:             iov = p->iov.iov + i;
                    367:             qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len);
                    368:         }
                    369:         break;
                    370: 
                    371:     case USB_TOKEN_IN:
                    372:         if (devep != 1)
                    373:             goto fail;
                    374:         first_len = RECV_BUF - s->recv_ptr;
                    375:         len = p->iov.size;
                    376:         if (len <= 2) {
                    377:             ret = USB_RET_NAK;
                    378:             break;
                    379:         }
                    380:         header[0] = usb_get_modem_lines(s) | 1;
                    381:         /* We do not have the uart details */
                    382:         /* handle serial break */
                    383:         if (s->event_trigger && s->event_trigger & FTDI_BI) {
                    384:             s->event_trigger &= ~FTDI_BI;
                    385:             header[1] = FTDI_BI;
                    386:             usb_packet_copy(p, header, 2);
                    387:             ret = 2;
                    388:             break;
                    389:         } else {
                    390:             header[1] = 0;
                    391:         }
                    392:         len -= 2;
                    393:         if (len > s->recv_used)
                    394:             len = s->recv_used;
                    395:         if (!len) {
                    396:             ret = USB_RET_NAK;
                    397:             break;
                    398:         }
                    399:         if (first_len > len)
                    400:             first_len = len;
                    401:         usb_packet_copy(p, header, 2);
                    402:         usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
                    403:         if (len > first_len)
                    404:             usb_packet_copy(p, s->recv_buf, len - first_len);
                    405:         s->recv_used -= len;
                    406:         s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
                    407:         ret = len + 2;
                    408:         break;
                    409: 
                    410:     default:
                    411:         DPRINTF("Bad token\n");
                    412:     fail:
                    413:         ret = USB_RET_STALL;
                    414:         break;
                    415:     }
                    416: 
                    417:     return ret;
                    418: }
                    419: 
                    420: static void usb_serial_handle_destroy(USBDevice *dev)
                    421: {
                    422:     USBSerialState *s = (USBSerialState *)dev;
                    423: 
                    424:     qemu_chr_delete(s->cs);
                    425: }
                    426: 
                    427: static int usb_serial_can_read(void *opaque)
                    428: {
                    429:     USBSerialState *s = opaque;
                    430:     return RECV_BUF - s->recv_used;
                    431: }
                    432: 
                    433: static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
                    434: {
                    435:     USBSerialState *s = opaque;
                    436:     int first_size, start;
                    437: 
                    438:     /* room in the buffer? */
                    439:     if (size > (RECV_BUF - s->recv_used))
                    440:         size = RECV_BUF - s->recv_used;
                    441: 
                    442:     start = s->recv_ptr + s->recv_used;
                    443:     if (start < RECV_BUF) {
                    444:         /* copy data to end of buffer */
                    445:         first_size = RECV_BUF - start;
                    446:         if (first_size > size)
                    447:             first_size = size;
                    448: 
                    449:         memcpy(s->recv_buf + start, buf, first_size);
                    450: 
                    451:         /* wrap around to front if needed */
                    452:         if (size > first_size)
                    453:             memcpy(s->recv_buf, buf + first_size, size - first_size);
                    454:     } else {
                    455:         start -= RECV_BUF;
                    456:         memcpy(s->recv_buf + start, buf, size);
                    457:     }
                    458:     s->recv_used += size;
                    459: }
                    460: 
                    461: static void usb_serial_event(void *opaque, int event)
                    462: {
                    463:     USBSerialState *s = opaque;
                    464: 
                    465:     switch (event) {
                    466:         case CHR_EVENT_BREAK:
                    467:             s->event_trigger |= FTDI_BI;
                    468:             break;
                    469:         case CHR_EVENT_FOCUS:
                    470:             break;
                    471:         case CHR_EVENT_OPENED:
                    472:             usb_serial_reset(s);
                    473:             /* TODO: Reset USB port */
                    474:             break;
                    475:     }
                    476: }
                    477: 
                    478: static int usb_serial_initfn(USBDevice *dev)
                    479: {
                    480:     USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev);
                    481: 
                    482:     usb_desc_create_serial(dev);
                    483:     usb_desc_init(dev);
                    484: 
                    485:     if (!s->cs) {
                    486:         error_report("Property chardev is required");
                    487:         return -1;
                    488:     }
                    489: 
                    490:     qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
                    491:                           usb_serial_event, s);
                    492:     usb_serial_handle_reset(dev);
                    493:     return 0;
                    494: }
                    495: 
                    496: static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
                    497: {
                    498:     USBDevice *dev;
                    499:     CharDriverState *cdrv;
                    500:     uint32_t vendorid = 0, productid = 0;
                    501:     char label[32];
                    502:     static int index;
                    503: 
                    504:     while (*filename && *filename != ':') {
                    505:         const char *p;
                    506:         char *e;
                    507:         if (strstart(filename, "vendorid=", &p)) {
                    508:             vendorid = strtol(p, &e, 16);
                    509:             if (e == p || (*e && *e != ',' && *e != ':')) {
                    510:                 error_report("bogus vendor ID %s", p);
                    511:                 return NULL;
                    512:             }
                    513:             filename = e;
                    514:         } else if (strstart(filename, "productid=", &p)) {
                    515:             productid = strtol(p, &e, 16);
                    516:             if (e == p || (*e && *e != ',' && *e != ':')) {
                    517:                 error_report("bogus product ID %s", p);
                    518:                 return NULL;
                    519:             }
                    520:             filename = e;
                    521:         } else {
                    522:             error_report("unrecognized serial USB option %s", filename);
                    523:             return NULL;
                    524:         }
                    525:         while(*filename == ',')
                    526:             filename++;
                    527:     }
                    528:     if (!*filename) {
                    529:         error_report("character device specification needed");
                    530:         return NULL;
                    531:     }
                    532:     filename++;
                    533: 
                    534:     snprintf(label, sizeof(label), "usbserial%d", index++);
                    535:     cdrv = qemu_chr_new(label, filename, NULL);
                    536:     if (!cdrv)
                    537:         return NULL;
                    538: 
                    539:     dev = usb_create(bus, "usb-serial");
                    540:     if (!dev) {
                    541:         return NULL;
                    542:     }
                    543:     qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
                    544:     if (vendorid)
                    545:         qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);
                    546:     if (productid)
                    547:         qdev_prop_set_uint16(&dev->qdev, "productid", productid);
                    548:     qdev_init_nofail(&dev->qdev);
                    549: 
                    550:     return dev;
                    551: }
                    552: 
                    553: static USBDevice *usb_braille_init(USBBus *bus, const char *unused)
                    554: {
                    555:     USBDevice *dev;
                    556:     CharDriverState *cdrv;
                    557: 
                    558:     cdrv = qemu_chr_new("braille", "braille", NULL);
                    559:     if (!cdrv)
                    560:         return NULL;
                    561: 
                    562:     dev = usb_create(bus, "usb-braille");
                    563:     qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
                    564:     qdev_init_nofail(&dev->qdev);
                    565: 
                    566:     return dev;
                    567: }
                    568: 
                    569: static const VMStateDescription vmstate_usb_serial = {
                    570:     .name = "usb-serial",
                    571:     .unmigratable = 1,
                    572: };
                    573: 
                    574: static Property serial_properties[] = {
                    575:     DEFINE_PROP_CHR("chardev", USBSerialState, cs),
                    576:     DEFINE_PROP_END_OF_LIST(),
                    577: };
                    578: 
                    579: static void usb_serial_class_initfn(ObjectClass *klass, void *data)
                    580: {
                    581:     DeviceClass *dc = DEVICE_CLASS(klass);
                    582:     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
                    583: 
                    584:     uc->init = usb_serial_initfn;
                    585:     uc->product_desc   = "QEMU USB Serial";
                    586:     uc->usb_desc       = &desc_serial;
                    587:     uc->handle_reset   = usb_serial_handle_reset;
                    588:     uc->handle_control = usb_serial_handle_control;
                    589:     uc->handle_data    = usb_serial_handle_data;
                    590:     uc->handle_destroy = usb_serial_handle_destroy;
                    591:     dc->vmsd = &vmstate_usb_serial;
                    592:     dc->props = serial_properties;
                    593: }
                    594: 
                    595: static TypeInfo serial_info = {
                    596:     .name          = "usb-serial",
                    597:     .parent        = TYPE_USB_DEVICE,
                    598:     .instance_size = sizeof(USBSerialState),
                    599:     .class_init    = usb_serial_class_initfn,
                    600: };
                    601: 
                    602: static Property braille_properties[] = {
                    603:     DEFINE_PROP_CHR("chardev", USBSerialState, cs),
                    604:     DEFINE_PROP_END_OF_LIST(),
                    605: };
                    606: 
                    607: static void usb_braille_class_initfn(ObjectClass *klass, void *data)
                    608: {
                    609:     DeviceClass *dc = DEVICE_CLASS(klass);
                    610:     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
                    611: 
                    612:     uc->init           = usb_serial_initfn;
                    613:     uc->product_desc   = "QEMU USB Braille";
                    614:     uc->usb_desc       = &desc_braille;
                    615:     uc->handle_reset   = usb_serial_handle_reset;
                    616:     uc->handle_control = usb_serial_handle_control;
                    617:     uc->handle_data    = usb_serial_handle_data;
                    618:     uc->handle_destroy = usb_serial_handle_destroy;
                    619:     dc->vmsd = &vmstate_usb_serial;
                    620:     dc->props = braille_properties;
                    621: }
                    622: 
                    623: static TypeInfo braille_info = {
                    624:     .name          = "usb-braille",
                    625:     .parent        = TYPE_USB_DEVICE,
                    626:     .instance_size = sizeof(USBSerialState),
                    627:     .class_init    = usb_braille_class_initfn,
                    628: };
                    629: 
                    630: static void usb_serial_register_types(void)
                    631: {
                    632:     type_register_static(&serial_info);
                    633:     usb_legacy_register("usb-serial", "serial", usb_serial_init);
                    634:     type_register_static(&braille_info);
                    635:     usb_legacy_register("usb-braille", "braille", usb_braille_init);
                    636: }
                    637: 
                    638: type_init(usb_serial_register_types)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.