Annotation of qemu/hw/usb-wacom.c, revision 1.1.1.3

1.1       root        1: /*
                      2:  * Wacom PenPartner USB tablet emulation.
                      3:  *
                      4:  * Copyright (c) 2006 Openedhand Ltd.
                      5:  * Author: Andrzej Zaborowski <[email protected]>
                      6:  *
                      7:  * Based on hw/usb-hid.c:
                      8:  * Copyright (c) 2005 Fabrice Bellard
                      9:  *
                     10:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                     11:  * of this software and associated documentation files (the "Software"), to deal
                     12:  * in the Software without restriction, including without limitation the rights
                     13:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     14:  * copies of the Software, and to permit persons to whom the Software is
                     15:  * furnished to do so, subject to the following conditions:
                     16:  *
                     17:  * The above copyright notice and this permission notice shall be included in
                     18:  * all copies or substantial portions of the Software.
                     19:  *
                     20:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     21:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     22:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     23:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     24:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     25:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     26:  * THE SOFTWARE.
                     27:  */
                     28: #include "hw.h"
                     29: #include "console.h"
                     30: #include "usb.h"
                     31: 
                     32: /* Interface requests */
                     33: #define WACOM_GET_REPORT       0x2101
                     34: #define WACOM_SET_REPORT       0x2109
                     35: 
                     36: /* HID interface requests */
                     37: #define HID_GET_REPORT         0xa101
                     38: #define HID_GET_IDLE           0xa102
                     39: #define HID_GET_PROTOCOL       0xa103
                     40: #define HID_SET_IDLE           0x210a
                     41: #define HID_SET_PROTOCOL       0x210b
                     42: 
                     43: typedef struct USBWacomState {
                     44:     USBDevice dev;
                     45:     QEMUPutMouseEntry *eh_entry;
                     46:     int dx, dy, dz, buttons_state;
                     47:     int x, y;
                     48:     int mouse_grabbed;
                     49:     enum {
                     50:         WACOM_MODE_HID = 1,
                     51:         WACOM_MODE_WACOM = 2,
                     52:     } mode;
1.1.1.3 ! root       53:     uint8_t idle;
        !            54:     int changed;
1.1       root       55: } USBWacomState;
                     56: 
                     57: static const uint8_t qemu_wacom_dev_descriptor[] = {
                     58:     0x12,      /*  u8 bLength; */
                     59:     0x01,      /*  u8 bDescriptorType; Device */
                     60:     0x10, 0x10,        /*  u16 bcdUSB; v1.10 */
                     61: 
                     62:     0x00,      /*  u8  bDeviceClass; */
                     63:     0x00,      /*  u8  bDeviceSubClass; */
                     64:     0x00,      /*  u8  bDeviceProtocol; [ low/full speeds only ] */
                     65:     0x08,      /*  u8  bMaxPacketSize0; 8 Bytes */
                     66: 
                     67:     0x6a, 0x05,        /*  u16 idVendor; */
                     68:     0x00, 0x00,        /*  u16 idProduct; */
                     69:     0x10, 0x42,        /*  u16 bcdDevice */
                     70: 
                     71:     0x01,      /*  u8  iManufacturer; */
                     72:     0x02,      /*  u8  iProduct; */
                     73:     0x00,      /*  u8  iSerialNumber; */
                     74:     0x01,      /*  u8  bNumConfigurations; */
                     75: };
                     76: 
                     77: static const uint8_t qemu_wacom_config_descriptor[] = {
                     78:     /* one configuration */
                     79:     0x09,      /*  u8  bLength; */
                     80:     0x02,      /*  u8  bDescriptorType; Configuration */
                     81:     0x22, 0x00,        /*  u16 wTotalLength; */
                     82:     0x01,      /*  u8  bNumInterfaces; (1) */
                     83:     0x01,      /*  u8  bConfigurationValue; */
                     84:     0x00,      /*  u8  iConfiguration; */
                     85:     0x80,      /*  u8  bmAttributes;
                     86:                                 Bit 7: must be set,
                     87:                                     6: Self-powered,
                     88:                                     5: Remote wakeup,
                     89:                                     4..0: resvd */
                     90:     40,                /*  u8  MaxPower; */
                     91: 
                     92:     /* one interface */
                     93:     0x09,      /*  u8  if_bLength; */
                     94:     0x04,      /*  u8  if_bDescriptorType; Interface */
                     95:     0x00,      /*  u8  if_bInterfaceNumber; */
                     96:     0x00,      /*  u8  if_bAlternateSetting; */
                     97:     0x01,      /*  u8  if_bNumEndpoints; */
                     98:     0x03,      /*  u8  if_bInterfaceClass; HID */
                     99:     0x01,      /*  u8  if_bInterfaceSubClass; Boot */
                    100:     0x02,      /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
                    101:     0x00,      /*  u8  if_iInterface; */
                    102: 
                    103:     /* HID descriptor */
                    104:     0x09,      /*  u8  bLength; */
                    105:     0x21,      /*  u8  bDescriptorType; */
                    106:     0x01, 0x10,        /*  u16 HID_class */
                    107:     0x00,      /*  u8  country_code */
                    108:     0x01,      /*  u8  num_descriptors */
                    109:     0x22,      /*  u8  type; Report */
                    110:     0x6e, 0x00,        /*  u16 len */
                    111: 
                    112:     /* one endpoint (status change endpoint) */
                    113:     0x07,      /*  u8  ep_bLength; */
                    114:     0x05,      /*  u8  ep_bDescriptorType; Endpoint */
                    115:     0x81,      /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
                    116:     0x03,      /*  u8  ep_bmAttributes; Interrupt */
                    117:     0x08, 0x00,        /*  u16 ep_wMaxPacketSize; */
                    118:     0x0a,      /*  u8  ep_bInterval; */
                    119: };
                    120: 
                    121: static void usb_mouse_event(void *opaque,
                    122:                             int dx1, int dy1, int dz1, int buttons_state)
                    123: {
                    124:     USBWacomState *s = opaque;
                    125: 
                    126:     s->dx += dx1;
                    127:     s->dy += dy1;
                    128:     s->dz += dz1;
                    129:     s->buttons_state = buttons_state;
1.1.1.3 ! root      130:     s->changed = 1;
1.1       root      131: }
                    132: 
                    133: static void usb_wacom_event(void *opaque,
                    134:                             int x, int y, int dz, int buttons_state)
                    135: {
                    136:     USBWacomState *s = opaque;
                    137: 
1.1.1.3 ! root      138:     /* scale to Penpartner resolution */
        !           139:     s->x = (x * 5040 / 0x7FFF);
        !           140:     s->y = (y * 3780 / 0x7FFF);
1.1       root      141:     s->dz += dz;
                    142:     s->buttons_state = buttons_state;
1.1.1.3 ! root      143:     s->changed = 1;
1.1       root      144: }
                    145: 
                    146: static inline int int_clamp(int val, int vmin, int vmax)
                    147: {
                    148:     if (val < vmin)
                    149:         return vmin;
                    150:     else if (val > vmax)
                    151:         return vmax;
                    152:     else
                    153:         return val;
                    154: }
                    155: 
                    156: static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
                    157: {
                    158:     int dx, dy, dz, b, l;
                    159: 
                    160:     if (!s->mouse_grabbed) {
                    161:         s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
                    162:                         "QEMU PenPartner tablet");
                    163:         s->mouse_grabbed = 1;
                    164:     }
                    165: 
                    166:     dx = int_clamp(s->dx, -128, 127);
                    167:     dy = int_clamp(s->dy, -128, 127);
                    168:     dz = int_clamp(s->dz, -128, 127);
                    169: 
                    170:     s->dx -= dx;
                    171:     s->dy -= dy;
                    172:     s->dz -= dz;
                    173: 
                    174:     b = 0;
                    175:     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
                    176:         b |= 0x01;
                    177:     if (s->buttons_state & MOUSE_EVENT_RBUTTON)
                    178:         b |= 0x02;
                    179:     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
                    180:         b |= 0x04;
                    181: 
                    182:     buf[0] = b;
                    183:     buf[1] = dx;
                    184:     buf[2] = dy;
                    185:     l = 3;
                    186:     if (len >= 4) {
                    187:         buf[3] = dz;
                    188:         l = 4;
                    189:     }
                    190:     return l;
                    191: }
                    192: 
                    193: static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
                    194: {
                    195:     int b;
                    196: 
                    197:     if (!s->mouse_grabbed) {
                    198:         s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
                    199:                         "QEMU PenPartner tablet");
                    200:         s->mouse_grabbed = 1;
                    201:     }
                    202: 
                    203:     b = 0;
                    204:     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
                    205:         b |= 0x01;
                    206:     if (s->buttons_state & MOUSE_EVENT_RBUTTON)
1.1.1.3 ! root      207:         b |= 0x40;
1.1       root      208:     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
1.1.1.3 ! root      209:         b |= 0x20; /* eraser */
1.1       root      210: 
                    211:     if (len < 7)
                    212:         return 0;
                    213: 
                    214:     buf[0] = s->mode;
1.1.1.3 ! root      215:     buf[5] = 0x00 | (b & 0xf0);
        !           216:     buf[1] = s->x & 0xff;
        !           217:     buf[2] = s->x >> 8;
        !           218:     buf[3] = s->y & 0xff;
        !           219:     buf[4] = s->y >> 8;
        !           220:     if (b & 0x3f) {
1.1       root      221:         buf[6] = 0;
                    222:     } else {
                    223:         buf[6] = (unsigned char) -127;
                    224:     }
                    225: 
                    226:     return 7;
                    227: }
                    228: 
                    229: static void usb_wacom_handle_reset(USBDevice *dev)
                    230: {
                    231:     USBWacomState *s = (USBWacomState *) dev;
                    232: 
                    233:     s->dx = 0;
                    234:     s->dy = 0;
                    235:     s->dz = 0;
                    236:     s->x = 0;
                    237:     s->y = 0;
                    238:     s->buttons_state = 0;
                    239:     s->mode = WACOM_MODE_HID;
                    240: }
                    241: 
                    242: static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
                    243:                                     int index, int length, uint8_t *data)
                    244: {
                    245:     USBWacomState *s = (USBWacomState *) dev;
                    246:     int ret = 0;
                    247: 
                    248:     switch (request) {
                    249:     case DeviceRequest | USB_REQ_GET_STATUS:
                    250:         data[0] = (1 << USB_DEVICE_SELF_POWERED) |
                    251:             (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
                    252:         data[1] = 0x00;
                    253:         ret = 2;
                    254:         break;
                    255:     case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
                    256:         if (value == USB_DEVICE_REMOTE_WAKEUP) {
                    257:             dev->remote_wakeup = 0;
                    258:         } else {
                    259:             goto fail;
                    260:         }
                    261:         ret = 0;
                    262:         break;
                    263:     case DeviceOutRequest | USB_REQ_SET_FEATURE:
                    264:         if (value == USB_DEVICE_REMOTE_WAKEUP) {
                    265:             dev->remote_wakeup = 1;
                    266:         } else {
                    267:             goto fail;
                    268:         }
                    269:         ret = 0;
                    270:         break;
                    271:     case DeviceOutRequest | USB_REQ_SET_ADDRESS:
                    272:         dev->addr = value;
                    273:         ret = 0;
                    274:         break;
                    275:     case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
                    276:         switch (value >> 8) {
                    277:         case USB_DT_DEVICE:
                    278:             memcpy(data, qemu_wacom_dev_descriptor,
                    279:                    sizeof(qemu_wacom_dev_descriptor));
                    280:             ret = sizeof(qemu_wacom_dev_descriptor);
                    281:             break;
                    282:         case USB_DT_CONFIG:
                    283:                    memcpy(data, qemu_wacom_config_descriptor,
                    284:                    sizeof(qemu_wacom_config_descriptor));
                    285:             ret = sizeof(qemu_wacom_config_descriptor);
                    286:             break;
                    287:         case USB_DT_STRING:
                    288:             switch (value & 0xff) {
                    289:             case 0:
                    290:                 /* language ids */
                    291:                 data[0] = 4;
                    292:                 data[1] = 3;
                    293:                 data[2] = 0x09;
                    294:                 data[3] = 0x04;
                    295:                 ret = 4;
                    296:                 break;
                    297:             case 1:
                    298:                 /* serial number */
                    299:                 ret = set_usb_string(data, "1");
                    300:                 break;
                    301:             case 2:
                    302:                ret = set_usb_string(data, "Wacom PenPartner");
                    303:                 break;
                    304:             case 3:
                    305:                 /* vendor description */
                    306:                 ret = set_usb_string(data, "QEMU " QEMU_VERSION);
                    307:                 break;
                    308:             case 4:
                    309:                 ret = set_usb_string(data, "Wacom Tablet");
                    310:                 break;
                    311:             case 5:
                    312:                 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
                    313:                 break;
                    314:             default:
                    315:                 goto fail;
                    316:             }
                    317:             break;
                    318:         default:
                    319:             goto fail;
                    320:         }
                    321:         break;
                    322:     case DeviceRequest | USB_REQ_GET_CONFIGURATION:
                    323:         data[0] = 1;
                    324:         ret = 1;
                    325:         break;
                    326:     case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
                    327:         ret = 0;
                    328:         break;
                    329:     case DeviceRequest | USB_REQ_GET_INTERFACE:
                    330:         data[0] = 0;
                    331:         ret = 1;
                    332:         break;
                    333:     case DeviceOutRequest | USB_REQ_SET_INTERFACE:
                    334:         ret = 0;
                    335:         break;
                    336:     case WACOM_SET_REPORT:
                    337:         qemu_remove_mouse_event_handler(s->eh_entry);
                    338:         s->mouse_grabbed = 0;
                    339:         s->mode = data[0];
                    340:         ret = 0;
                    341:         break;
                    342:     case WACOM_GET_REPORT:
                    343:         data[0] = 0;
                    344:         data[1] = s->mode;
                    345:         ret = 2;
                    346:         break;
                    347:     /* USB HID requests */
                    348:     case HID_GET_REPORT:
                    349:         if (s->mode == WACOM_MODE_HID)
                    350:             ret = usb_mouse_poll(s, data, length);
                    351:         else if (s->mode == WACOM_MODE_WACOM)
                    352:             ret = usb_wacom_poll(s, data, length);
                    353:         break;
1.1.1.3 ! root      354:     case HID_GET_IDLE:
        !           355:         ret = 1;
        !           356:         data[0] = s->idle;
        !           357:         break;
1.1       root      358:     case HID_SET_IDLE:
1.1.1.3 ! root      359:         s->idle = (uint8_t) (value >> 8);
1.1       root      360:         ret = 0;
                    361:         break;
                    362:     default:
                    363:     fail:
                    364:         ret = USB_RET_STALL;
                    365:         break;
                    366:     }
                    367:     return ret;
                    368: }
                    369: 
                    370: static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
                    371: {
                    372:     USBWacomState *s = (USBWacomState *) dev;
                    373:     int ret = 0;
                    374: 
                    375:     switch (p->pid) {
                    376:     case USB_TOKEN_IN:
                    377:         if (p->devep == 1) {
1.1.1.3 ! root      378:             if (!(s->changed || s->idle))
        !           379:                 return USB_RET_NAK;
        !           380:             s->changed = 0;
1.1       root      381:             if (s->mode == WACOM_MODE_HID)
                    382:                 ret = usb_mouse_poll(s, p->data, p->len);
                    383:             else if (s->mode == WACOM_MODE_WACOM)
                    384:                 ret = usb_wacom_poll(s, p->data, p->len);
                    385:             break;
                    386:         }
                    387:         /* Fall through.  */
                    388:     case USB_TOKEN_OUT:
                    389:     default:
                    390:         ret = USB_RET_STALL;
                    391:         break;
                    392:     }
                    393:     return ret;
                    394: }
                    395: 
                    396: static void usb_wacom_handle_destroy(USBDevice *dev)
                    397: {
                    398:     USBWacomState *s = (USBWacomState *) dev;
                    399: 
                    400:     qemu_remove_mouse_event_handler(s->eh_entry);
                    401: }
                    402: 
1.1.1.3 ! root      403: static int usb_wacom_initfn(USBDevice *dev)
1.1       root      404: {
1.1.1.3 ! root      405:     USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
1.1       root      406:     s->dev.speed = USB_SPEED_FULL;
1.1.1.3 ! root      407:     s->changed = 1;
        !           408:     return 0;
        !           409: }
1.1       root      410: 
1.1.1.3 ! root      411: static struct USBDeviceInfo wacom_info = {
        !           412:     .product_desc   = "QEMU PenPartner Tablet",
        !           413:     .qdev.name      = "usb-wacom-tablet",
        !           414:     .qdev.desc      = "QEMU PenPartner Tablet",
        !           415:     .usbdevice_name = "wacom-tablet",
        !           416:     .qdev.size      = sizeof(USBWacomState),
        !           417:     .init           = usb_wacom_initfn,
        !           418:     .handle_packet  = usb_generic_handle_packet,
        !           419:     .handle_reset   = usb_wacom_handle_reset,
        !           420:     .handle_control = usb_wacom_handle_control,
        !           421:     .handle_data    = usb_wacom_handle_data,
        !           422:     .handle_destroy = usb_wacom_handle_destroy,
        !           423: };
1.1       root      424: 
1.1.1.3 ! root      425: static void usb_wacom_register_devices(void)
        !           426: {
        !           427:     usb_qdev_register(&wacom_info);
1.1       root      428: }
1.1.1.3 ! root      429: device_init(usb_wacom_register_devices)

unix.superglobalmegacorp.com

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