Annotation of qemu/hw/usb/dev-bluetooth.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU Bluetooth HCI USB Transport Layer v1.0
        !             3:  *
        !             4:  * Copyright (C) 2007 OpenMoko, Inc.
        !             5:  * Copyright (C) 2008 Andrzej Zaborowski  <[email protected]>
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or
        !             8:  * modify it under the terms of the GNU General Public License as
        !             9:  * published by the Free Software Foundation; either version 2 or
        !            10:  * (at your option) version 3 of the License.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful,
        !            13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            15:  * GNU General Public License for more details.
        !            16:  *
        !            17:  * You should have received a copy of the GNU General Public License along
        !            18:  * with this program; if not, see <http://www.gnu.org/licenses/>.
        !            19:  */
        !            20: 
        !            21: #include "qemu-common.h"
        !            22: #include "hw/usb.h"
        !            23: #include "hw/usb/desc.h"
        !            24: #include "net.h"
        !            25: #include "hw/bt.h"
        !            26: 
        !            27: struct USBBtState {
        !            28:     USBDevice dev;
        !            29:     struct HCIInfo *hci;
        !            30: 
        !            31:     int config;
        !            32: 
        !            33: #define CFIFO_LEN_MASK 255
        !            34: #define DFIFO_LEN_MASK 4095
        !            35:     struct usb_hci_in_fifo_s {
        !            36:         uint8_t data[(DFIFO_LEN_MASK + 1) * 2];
        !            37:         struct {
        !            38:             uint8_t *data;
        !            39:             int len;
        !            40:         } fifo[CFIFO_LEN_MASK + 1];
        !            41:         int dstart, dlen, dsize, start, len;
        !            42:     } evt, acl, sco;
        !            43: 
        !            44:     struct usb_hci_out_fifo_s {
        !            45:         uint8_t data[4096];
        !            46:        int len;
        !            47:     } outcmd, outacl, outsco;
        !            48: };
        !            49: 
        !            50: #define USB_EVT_EP     1
        !            51: #define USB_ACL_EP     2
        !            52: #define USB_SCO_EP     3
        !            53: 
        !            54: enum {
        !            55:     STR_MANUFACTURER = 1,
        !            56:     STR_SERIALNUMBER,
        !            57: };
        !            58: 
        !            59: static const USBDescStrings desc_strings = {
        !            60:     [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
        !            61:     [STR_SERIALNUMBER]     = "1",
        !            62: };
        !            63: 
        !            64: static const USBDescIface desc_iface_bluetooth[] = {
        !            65:     {
        !            66:         .bInterfaceNumber              = 0,
        !            67:         .bNumEndpoints                 = 3,
        !            68:         .bInterfaceClass               = 0xe0, /* Wireless */
        !            69:         .bInterfaceSubClass            = 0x01, /* Radio Frequency */
        !            70:         .bInterfaceProtocol            = 0x01, /* Bluetooth */
        !            71:         .eps = (USBDescEndpoint[]) {
        !            72:             {
        !            73:                 .bEndpointAddress      = USB_DIR_IN | USB_EVT_EP,
        !            74:                 .bmAttributes          = USB_ENDPOINT_XFER_INT,
        !            75:                 .wMaxPacketSize        = 0x10,
        !            76:                 .bInterval             = 0x02,
        !            77:             },
        !            78:             {
        !            79:                 .bEndpointAddress      = USB_DIR_OUT | USB_ACL_EP,
        !            80:                 .bmAttributes          = USB_ENDPOINT_XFER_BULK,
        !            81:                 .wMaxPacketSize        = 0x40,
        !            82:                 .bInterval             = 0x0a,
        !            83:             },
        !            84:             {
        !            85:                 .bEndpointAddress      = USB_DIR_IN | USB_ACL_EP,
        !            86:                 .bmAttributes          = USB_ENDPOINT_XFER_BULK,
        !            87:                 .wMaxPacketSize        = 0x40,
        !            88:                 .bInterval             = 0x0a,
        !            89:             },
        !            90:         },
        !            91:     },{
        !            92:         .bInterfaceNumber              = 1,
        !            93:         .bAlternateSetting             = 0,
        !            94:         .bNumEndpoints                 = 2,
        !            95:         .bInterfaceClass               = 0xe0, /* Wireless */
        !            96:         .bInterfaceSubClass            = 0x01, /* Radio Frequency */
        !            97:         .bInterfaceProtocol            = 0x01, /* Bluetooth */
        !            98:         .eps = (USBDescEndpoint[]) {
        !            99:             {
        !           100:                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
        !           101:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           102:                 .wMaxPacketSize        = 0,
        !           103:                 .bInterval             = 0x01,
        !           104:             },
        !           105:             {
        !           106:                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
        !           107:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           108:                 .wMaxPacketSize        = 0,
        !           109:                 .bInterval             = 0x01,
        !           110:             },
        !           111:         },
        !           112:     },{
        !           113:         .bInterfaceNumber              = 1,
        !           114:         .bAlternateSetting             = 1,
        !           115:         .bNumEndpoints                 = 2,
        !           116:         .bInterfaceClass               = 0xe0, /* Wireless */
        !           117:         .bInterfaceSubClass            = 0x01, /* Radio Frequency */
        !           118:         .bInterfaceProtocol            = 0x01, /* Bluetooth */
        !           119:         .eps = (USBDescEndpoint[]) {
        !           120:             {
        !           121:                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
        !           122:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           123:                 .wMaxPacketSize        = 0x09,
        !           124:                 .bInterval             = 0x01,
        !           125:             },
        !           126:             {
        !           127:                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
        !           128:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           129:                 .wMaxPacketSize        = 0x09,
        !           130:                 .bInterval             = 0x01,
        !           131:             },
        !           132:         },
        !           133:     },{
        !           134:         .bInterfaceNumber              = 1,
        !           135:         .bAlternateSetting             = 2,
        !           136:         .bNumEndpoints                 = 2,
        !           137:         .bInterfaceClass               = 0xe0, /* Wireless */
        !           138:         .bInterfaceSubClass            = 0x01, /* Radio Frequency */
        !           139:         .bInterfaceProtocol            = 0x01, /* Bluetooth */
        !           140:         .eps = (USBDescEndpoint[]) {
        !           141:             {
        !           142:                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
        !           143:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           144:                 .wMaxPacketSize        = 0x11,
        !           145:                 .bInterval             = 0x01,
        !           146:             },
        !           147:             {
        !           148:                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
        !           149:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           150:                 .wMaxPacketSize        = 0x11,
        !           151:                 .bInterval             = 0x01,
        !           152:             },
        !           153:         },
        !           154:     },{
        !           155:         .bInterfaceNumber              = 1,
        !           156:         .bAlternateSetting             = 3,
        !           157:         .bNumEndpoints                 = 2,
        !           158:         .bInterfaceClass               = 0xe0, /* Wireless */
        !           159:         .bInterfaceSubClass            = 0x01, /* Radio Frequency */
        !           160:         .bInterfaceProtocol            = 0x01, /* Bluetooth */
        !           161:         .eps = (USBDescEndpoint[]) {
        !           162:             {
        !           163:                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
        !           164:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           165:                 .wMaxPacketSize        = 0x19,
        !           166:                 .bInterval             = 0x01,
        !           167:             },
        !           168:             {
        !           169:                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
        !           170:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           171:                 .wMaxPacketSize        = 0x19,
        !           172:                 .bInterval             = 0x01,
        !           173:             },
        !           174:         },
        !           175:     },{
        !           176:         .bInterfaceNumber              = 1,
        !           177:         .bAlternateSetting             = 4,
        !           178:         .bNumEndpoints                 = 2,
        !           179:         .bInterfaceClass               = 0xe0, /* Wireless */
        !           180:         .bInterfaceSubClass            = 0x01, /* Radio Frequency */
        !           181:         .bInterfaceProtocol            = 0x01, /* Bluetooth */
        !           182:         .eps = (USBDescEndpoint[]) {
        !           183:             {
        !           184:                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
        !           185:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           186:                 .wMaxPacketSize        = 0x21,
        !           187:                 .bInterval             = 0x01,
        !           188:             },
        !           189:             {
        !           190:                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
        !           191:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           192:                 .wMaxPacketSize        = 0x21,
        !           193:                 .bInterval             = 0x01,
        !           194:             },
        !           195:         },
        !           196:     },{
        !           197:         .bInterfaceNumber              = 1,
        !           198:         .bAlternateSetting             = 5,
        !           199:         .bNumEndpoints                 = 2,
        !           200:         .bInterfaceClass               = 0xe0, /* Wireless */
        !           201:         .bInterfaceSubClass            = 0x01, /* Radio Frequency */
        !           202:         .bInterfaceProtocol            = 0x01, /* Bluetooth */
        !           203:         .eps = (USBDescEndpoint[]) {
        !           204:             {
        !           205:                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
        !           206:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           207:                 .wMaxPacketSize        = 0x31,
        !           208:                 .bInterval             = 0x01,
        !           209:             },
        !           210:             {
        !           211:                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
        !           212:                 .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
        !           213:                 .wMaxPacketSize        = 0x31,
        !           214:                 .bInterval             = 0x01,
        !           215:             },
        !           216:         },
        !           217:     }
        !           218: };
        !           219: 
        !           220: static const USBDescDevice desc_device_bluetooth = {
        !           221:     .bcdUSB                        = 0x0110,
        !           222:     .bDeviceClass                  = 0xe0, /* Wireless */
        !           223:     .bDeviceSubClass               = 0x01, /* Radio Frequency */
        !           224:     .bDeviceProtocol               = 0x01, /* Bluetooth */
        !           225:     .bMaxPacketSize0               = 64,
        !           226:     .bNumConfigurations            = 1,
        !           227:     .confs = (USBDescConfig[]) {
        !           228:         {
        !           229:             .bNumInterfaces        = 2,
        !           230:             .bConfigurationValue   = 1,
        !           231:             .bmAttributes          = 0xc0,
        !           232:             .bMaxPower             = 0,
        !           233:             .nif = ARRAY_SIZE(desc_iface_bluetooth),
        !           234:             .ifs = desc_iface_bluetooth,
        !           235:         },
        !           236:     },
        !           237: };
        !           238: 
        !           239: static const USBDesc desc_bluetooth = {
        !           240:     .id = {
        !           241:         .idVendor          = 0x0a12,
        !           242:         .idProduct         = 0x0001,
        !           243:         .bcdDevice         = 0x1958,
        !           244:         .iManufacturer     = STR_MANUFACTURER,
        !           245:         .iProduct          = 0,
        !           246:         .iSerialNumber     = STR_SERIALNUMBER,
        !           247:     },
        !           248:     .full = &desc_device_bluetooth,
        !           249:     .str  = desc_strings,
        !           250: };
        !           251: 
        !           252: static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo)
        !           253: {
        !           254:     fifo->dstart = 0;
        !           255:     fifo->dlen = 0;
        !           256:     fifo->dsize = DFIFO_LEN_MASK + 1;
        !           257:     fifo->start = 0;
        !           258:     fifo->len = 0;
        !           259: }
        !           260: 
        !           261: static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo,
        !           262:                 const uint8_t *data, int len)
        !           263: {
        !           264:     int off = fifo->dstart + fifo->dlen;
        !           265:     uint8_t *buf;
        !           266: 
        !           267:     fifo->dlen += len;
        !           268:     if (off <= DFIFO_LEN_MASK) {
        !           269:         if (off + len > DFIFO_LEN_MASK + 1 &&
        !           270:                         (fifo->dsize = off + len) > (DFIFO_LEN_MASK + 1) * 2) {
        !           271:             fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
        !           272:             exit(-1);
        !           273:         }
        !           274:         buf = fifo->data + off;
        !           275:     } else {
        !           276:         if (fifo->dlen > fifo->dsize) {
        !           277:             fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
        !           278:             exit(-1);
        !           279:         }
        !           280:         buf = fifo->data + off - fifo->dsize;
        !           281:     }
        !           282: 
        !           283:     off = (fifo->start + fifo->len ++) & CFIFO_LEN_MASK;
        !           284:     fifo->fifo[off].data = memcpy(buf, data, len);
        !           285:     fifo->fifo[off].len = len;
        !           286: }
        !           287: 
        !           288: static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
        !           289:                 USBPacket *p)
        !           290: {
        !           291:     int len;
        !           292: 
        !           293:     if (likely(!fifo->len))
        !           294:         return USB_RET_STALL;
        !           295: 
        !           296:     len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
        !           297:     usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
        !           298:     if (len == p->iov.size) {
        !           299:         fifo->fifo[fifo->start].len -= len;
        !           300:         fifo->fifo[fifo->start].data += len;
        !           301:     } else {
        !           302:         fifo->start ++;
        !           303:         fifo->start &= CFIFO_LEN_MASK;
        !           304:         fifo->len --;
        !           305:     }
        !           306: 
        !           307:     fifo->dstart += len;
        !           308:     fifo->dlen -= len;
        !           309:     if (fifo->dstart >= fifo->dsize) {
        !           310:         fifo->dstart = 0;
        !           311:         fifo->dsize = DFIFO_LEN_MASK + 1;
        !           312:     }
        !           313: 
        !           314:     return len;
        !           315: }
        !           316: 
        !           317: static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
        !           318:                 struct usb_hci_out_fifo_s *fifo,
        !           319:                 void (*send)(struct HCIInfo *, const uint8_t *, int),
        !           320:                 int (*complete)(const uint8_t *, int),
        !           321:                 USBPacket *p)
        !           322: {
        !           323:     usb_packet_copy(p, fifo->data + fifo->len, p->iov.size);
        !           324:     fifo->len += p->iov.size;
        !           325:     if (complete(fifo->data, fifo->len)) {
        !           326:         send(s->hci, fifo->data, fifo->len);
        !           327:         fifo->len = 0;
        !           328:     }
        !           329: 
        !           330:     /* TODO: do we need to loop? */
        !           331: }
        !           332: 
        !           333: static int usb_bt_hci_cmd_complete(const uint8_t *data, int len)
        !           334: {
        !           335:     len -= HCI_COMMAND_HDR_SIZE;
        !           336:     return len >= 0 &&
        !           337:             len >= ((struct hci_command_hdr *) data)->plen;
        !           338: }
        !           339: 
        !           340: static int usb_bt_hci_acl_complete(const uint8_t *data, int len)
        !           341: {
        !           342:     len -= HCI_ACL_HDR_SIZE;
        !           343:     return len >= 0 &&
        !           344:             len >= le16_to_cpu(((struct hci_acl_hdr *) data)->dlen);
        !           345: }
        !           346: 
        !           347: static int usb_bt_hci_sco_complete(const uint8_t *data, int len)
        !           348: {
        !           349:     len -= HCI_SCO_HDR_SIZE;
        !           350:     return len >= 0 &&
        !           351:             len >= ((struct hci_sco_hdr *) data)->dlen;
        !           352: }
        !           353: 
        !           354: static void usb_bt_handle_reset(USBDevice *dev)
        !           355: {
        !           356:     struct USBBtState *s = (struct USBBtState *) dev->opaque;
        !           357: 
        !           358:     usb_bt_fifo_reset(&s->evt);
        !           359:     usb_bt_fifo_reset(&s->acl);
        !           360:     usb_bt_fifo_reset(&s->sco);
        !           361:     s->outcmd.len = 0;
        !           362:     s->outacl.len = 0;
        !           363:     s->outsco.len = 0;
        !           364: }
        !           365: 
        !           366: static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
        !           367:                int request, int value, int index, int length, uint8_t *data)
        !           368: {
        !           369:     struct USBBtState *s = (struct USBBtState *) dev->opaque;
        !           370:     int ret;
        !           371: 
        !           372:     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
        !           373:     if (ret >= 0) {
        !           374:         switch (request) {
        !           375:         case DeviceRequest | USB_REQ_GET_CONFIGURATION:
        !           376:             s->config = 0;
        !           377:             break;
        !           378:         case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
        !           379:             s->config = 1;
        !           380:             usb_bt_fifo_reset(&s->evt);
        !           381:             usb_bt_fifo_reset(&s->acl);
        !           382:             usb_bt_fifo_reset(&s->sco);
        !           383:             break;
        !           384:         }
        !           385:         return ret;
        !           386:     }
        !           387: 
        !           388:     ret = 0;
        !           389:     switch (request) {
        !           390:     case InterfaceRequest | USB_REQ_GET_STATUS:
        !           391:     case EndpointRequest | USB_REQ_GET_STATUS:
        !           392:         data[0] = 0x00;
        !           393:         data[1] = 0x00;
        !           394:         ret = 2;
        !           395:         break;
        !           396:     case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE:
        !           397:     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
        !           398:         goto fail;
        !           399:     case InterfaceOutRequest | USB_REQ_SET_FEATURE:
        !           400:     case EndpointOutRequest | USB_REQ_SET_FEATURE:
        !           401:         goto fail;
        !           402:         break;
        !           403:     case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
        !           404:         if (s->config)
        !           405:             usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
        !           406:                             usb_bt_hci_cmd_complete, p);
        !           407:         break;
        !           408:     default:
        !           409:     fail:
        !           410:         ret = USB_RET_STALL;
        !           411:         break;
        !           412:     }
        !           413:     return ret;
        !           414: }
        !           415: 
        !           416: static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
        !           417: {
        !           418:     struct USBBtState *s = (struct USBBtState *) dev->opaque;
        !           419:     int ret = 0;
        !           420: 
        !           421:     if (!s->config)
        !           422:         goto fail;
        !           423: 
        !           424:     switch (p->pid) {
        !           425:     case USB_TOKEN_IN:
        !           426:         switch (p->ep->nr) {
        !           427:         case USB_EVT_EP:
        !           428:             ret = usb_bt_fifo_dequeue(&s->evt, p);
        !           429:             break;
        !           430: 
        !           431:         case USB_ACL_EP:
        !           432:             ret = usb_bt_fifo_dequeue(&s->acl, p);
        !           433:             break;
        !           434: 
        !           435:         case USB_SCO_EP:
        !           436:             ret = usb_bt_fifo_dequeue(&s->sco, p);
        !           437:             break;
        !           438: 
        !           439:         default:
        !           440:             goto fail;
        !           441:         }
        !           442:         break;
        !           443: 
        !           444:     case USB_TOKEN_OUT:
        !           445:         switch (p->ep->nr) {
        !           446:         case USB_ACL_EP:
        !           447:             usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
        !           448:                             usb_bt_hci_acl_complete, p);
        !           449:             break;
        !           450: 
        !           451:         case USB_SCO_EP:
        !           452:             usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send,
        !           453:                             usb_bt_hci_sco_complete, p);
        !           454:             break;
        !           455: 
        !           456:         default:
        !           457:             goto fail;
        !           458:         }
        !           459:         break;
        !           460: 
        !           461:     default:
        !           462:     fail:
        !           463:         ret = USB_RET_STALL;
        !           464:         break;
        !           465:     }
        !           466: 
        !           467:     return ret;
        !           468: }
        !           469: 
        !           470: static void usb_bt_out_hci_packet_event(void *opaque,
        !           471:                 const uint8_t *data, int len)
        !           472: {
        !           473:     struct USBBtState *s = (struct USBBtState *) opaque;
        !           474: 
        !           475:     usb_bt_fifo_enqueue(&s->evt, data, len);
        !           476: }
        !           477: 
        !           478: static void usb_bt_out_hci_packet_acl(void *opaque,
        !           479:                 const uint8_t *data, int len)
        !           480: {
        !           481:     struct USBBtState *s = (struct USBBtState *) opaque;
        !           482: 
        !           483:     usb_bt_fifo_enqueue(&s->acl, data, len);
        !           484: }
        !           485: 
        !           486: static void usb_bt_handle_destroy(USBDevice *dev)
        !           487: {
        !           488:     struct USBBtState *s = (struct USBBtState *) dev->opaque;
        !           489: 
        !           490:     s->hci->opaque = NULL;
        !           491:     s->hci->evt_recv = NULL;
        !           492:     s->hci->acl_recv = NULL;
        !           493: }
        !           494: 
        !           495: static int usb_bt_initfn(USBDevice *dev)
        !           496: {
        !           497:     usb_desc_create_serial(dev);
        !           498:     usb_desc_init(dev);
        !           499:     return 0;
        !           500: }
        !           501: 
        !           502: USBDevice *usb_bt_init(USBBus *bus, HCIInfo *hci)
        !           503: {
        !           504:     USBDevice *dev;
        !           505:     struct USBBtState *s;
        !           506: 
        !           507:     if (!hci)
        !           508:         return NULL;
        !           509:     dev = usb_create_simple(bus, "usb-bt-dongle");
        !           510:     if (!dev) {
        !           511:         return NULL;
        !           512:     }
        !           513:     s = DO_UPCAST(struct USBBtState, dev, dev);
        !           514:     s->dev.opaque = s;
        !           515: 
        !           516:     s->hci = hci;
        !           517:     s->hci->opaque = s;
        !           518:     s->hci->evt_recv = usb_bt_out_hci_packet_event;
        !           519:     s->hci->acl_recv = usb_bt_out_hci_packet_acl;
        !           520: 
        !           521:     usb_bt_handle_reset(&s->dev);
        !           522: 
        !           523:     return dev;
        !           524: }
        !           525: 
        !           526: static const VMStateDescription vmstate_usb_bt = {
        !           527:     .name = "usb-bt",
        !           528:     .unmigratable = 1,
        !           529: };
        !           530: 
        !           531: static void usb_bt_class_initfn(ObjectClass *klass, void *data)
        !           532: {
        !           533:     DeviceClass *dc = DEVICE_CLASS(klass);
        !           534:     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
        !           535: 
        !           536:     uc->init           = usb_bt_initfn;
        !           537:     uc->product_desc   = "QEMU BT dongle";
        !           538:     uc->usb_desc       = &desc_bluetooth;
        !           539:     uc->handle_reset   = usb_bt_handle_reset;
        !           540:     uc->handle_control = usb_bt_handle_control;
        !           541:     uc->handle_data    = usb_bt_handle_data;
        !           542:     uc->handle_destroy = usb_bt_handle_destroy;
        !           543:     dc->vmsd = &vmstate_usb_bt;
        !           544: }
        !           545: 
        !           546: static TypeInfo bt_info = {
        !           547:     .name          = "usb-bt-dongle",
        !           548:     .parent        = TYPE_USB_DEVICE,
        !           549:     .instance_size = sizeof(struct USBBtState),
        !           550:     .class_init    = usb_bt_class_initfn,
        !           551: };
        !           552: 
        !           553: static void usb_bt_register_types(void)
        !           554: {
        !           555:     type_register_static(&bt_info);
        !           556: }
        !           557: 
        !           558: type_init(usb_bt_register_types)

unix.superglobalmegacorp.com

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