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

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;
        !            53: } USBWacomState;
        !            54: 
        !            55: static const uint8_t qemu_wacom_dev_descriptor[] = {
        !            56:     0x12,      /*  u8 bLength; */
        !            57:     0x01,      /*  u8 bDescriptorType; Device */
        !            58:     0x10, 0x10,        /*  u16 bcdUSB; v1.10 */
        !            59: 
        !            60:     0x00,      /*  u8  bDeviceClass; */
        !            61:     0x00,      /*  u8  bDeviceSubClass; */
        !            62:     0x00,      /*  u8  bDeviceProtocol; [ low/full speeds only ] */
        !            63:     0x08,      /*  u8  bMaxPacketSize0; 8 Bytes */
        !            64: 
        !            65:     0x6a, 0x05,        /*  u16 idVendor; */
        !            66:     0x00, 0x00,        /*  u16 idProduct; */
        !            67:     0x10, 0x42,        /*  u16 bcdDevice */
        !            68: 
        !            69:     0x01,      /*  u8  iManufacturer; */
        !            70:     0x02,      /*  u8  iProduct; */
        !            71:     0x00,      /*  u8  iSerialNumber; */
        !            72:     0x01,      /*  u8  bNumConfigurations; */
        !            73: };
        !            74: 
        !            75: static const uint8_t qemu_wacom_config_descriptor[] = {
        !            76:     /* one configuration */
        !            77:     0x09,      /*  u8  bLength; */
        !            78:     0x02,      /*  u8  bDescriptorType; Configuration */
        !            79:     0x22, 0x00,        /*  u16 wTotalLength; */
        !            80:     0x01,      /*  u8  bNumInterfaces; (1) */
        !            81:     0x01,      /*  u8  bConfigurationValue; */
        !            82:     0x00,      /*  u8  iConfiguration; */
        !            83:     0x80,      /*  u8  bmAttributes;
        !            84:                                 Bit 7: must be set,
        !            85:                                     6: Self-powered,
        !            86:                                     5: Remote wakeup,
        !            87:                                     4..0: resvd */
        !            88:     40,                /*  u8  MaxPower; */
        !            89: 
        !            90:     /* one interface */
        !            91:     0x09,      /*  u8  if_bLength; */
        !            92:     0x04,      /*  u8  if_bDescriptorType; Interface */
        !            93:     0x00,      /*  u8  if_bInterfaceNumber; */
        !            94:     0x00,      /*  u8  if_bAlternateSetting; */
        !            95:     0x01,      /*  u8  if_bNumEndpoints; */
        !            96:     0x03,      /*  u8  if_bInterfaceClass; HID */
        !            97:     0x01,      /*  u8  if_bInterfaceSubClass; Boot */
        !            98:     0x02,      /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
        !            99:     0x00,      /*  u8  if_iInterface; */
        !           100: 
        !           101:     /* HID descriptor */
        !           102:     0x09,      /*  u8  bLength; */
        !           103:     0x21,      /*  u8  bDescriptorType; */
        !           104:     0x01, 0x10,        /*  u16 HID_class */
        !           105:     0x00,      /*  u8  country_code */
        !           106:     0x01,      /*  u8  num_descriptors */
        !           107:     0x22,      /*  u8  type; Report */
        !           108:     0x6e, 0x00,        /*  u16 len */
        !           109: 
        !           110:     /* one endpoint (status change endpoint) */
        !           111:     0x07,      /*  u8  ep_bLength; */
        !           112:     0x05,      /*  u8  ep_bDescriptorType; Endpoint */
        !           113:     0x81,      /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
        !           114:     0x03,      /*  u8  ep_bmAttributes; Interrupt */
        !           115:     0x08, 0x00,        /*  u16 ep_wMaxPacketSize; */
        !           116:     0x0a,      /*  u8  ep_bInterval; */
        !           117: };
        !           118: 
        !           119: static void usb_mouse_event(void *opaque,
        !           120:                             int dx1, int dy1, int dz1, int buttons_state)
        !           121: {
        !           122:     USBWacomState *s = opaque;
        !           123: 
        !           124:     s->dx += dx1;
        !           125:     s->dy += dy1;
        !           126:     s->dz += dz1;
        !           127:     s->buttons_state = buttons_state;
        !           128: }
        !           129: 
        !           130: static void usb_wacom_event(void *opaque,
        !           131:                             int x, int y, int dz, int buttons_state)
        !           132: {
        !           133:     USBWacomState *s = opaque;
        !           134: 
        !           135:     s->x = x;
        !           136:     s->y = y;
        !           137:     s->dz += dz;
        !           138:     s->buttons_state = buttons_state;
        !           139: }
        !           140: 
        !           141: static inline int int_clamp(int val, int vmin, int vmax)
        !           142: {
        !           143:     if (val < vmin)
        !           144:         return vmin;
        !           145:     else if (val > vmax)
        !           146:         return vmax;
        !           147:     else
        !           148:         return val;
        !           149: }
        !           150: 
        !           151: static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
        !           152: {
        !           153:     int dx, dy, dz, b, l;
        !           154: 
        !           155:     if (!s->mouse_grabbed) {
        !           156:         s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
        !           157:                         "QEMU PenPartner tablet");
        !           158:         s->mouse_grabbed = 1;
        !           159:     }
        !           160: 
        !           161:     dx = int_clamp(s->dx, -128, 127);
        !           162:     dy = int_clamp(s->dy, -128, 127);
        !           163:     dz = int_clamp(s->dz, -128, 127);
        !           164: 
        !           165:     s->dx -= dx;
        !           166:     s->dy -= dy;
        !           167:     s->dz -= dz;
        !           168: 
        !           169:     b = 0;
        !           170:     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
        !           171:         b |= 0x01;
        !           172:     if (s->buttons_state & MOUSE_EVENT_RBUTTON)
        !           173:         b |= 0x02;
        !           174:     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
        !           175:         b |= 0x04;
        !           176: 
        !           177:     buf[0] = b;
        !           178:     buf[1] = dx;
        !           179:     buf[2] = dy;
        !           180:     l = 3;
        !           181:     if (len >= 4) {
        !           182:         buf[3] = dz;
        !           183:         l = 4;
        !           184:     }
        !           185:     return l;
        !           186: }
        !           187: 
        !           188: static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
        !           189: {
        !           190:     int b;
        !           191: 
        !           192:     if (!s->mouse_grabbed) {
        !           193:         s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
        !           194:                         "QEMU PenPartner tablet");
        !           195:         s->mouse_grabbed = 1;
        !           196:     }
        !           197: 
        !           198:     b = 0;
        !           199:     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
        !           200:         b |= 0x01;
        !           201:     if (s->buttons_state & MOUSE_EVENT_RBUTTON)
        !           202:         b |= 0x02;
        !           203:     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
        !           204:         b |= 0x04;
        !           205: 
        !           206:     if (len < 7)
        !           207:         return 0;
        !           208: 
        !           209:     buf[0] = s->mode;
        !           210:     buf[5] = 0x00;
        !           211:     if (b) {
        !           212:         buf[1] = s->x & 0xff;
        !           213:         buf[2] = s->x >> 8;
        !           214:         buf[3] = s->y & 0xff;
        !           215:         buf[4] = s->y >> 8;
        !           216:         buf[6] = 0;
        !           217:     } else {
        !           218:         buf[1] = 0;
        !           219:         buf[2] = 0;
        !           220:         buf[3] = 0;
        !           221:         buf[4] = 0;
        !           222:         buf[6] = (unsigned char) -127;
        !           223:     }
        !           224: 
        !           225:     return 7;
        !           226: }
        !           227: 
        !           228: static void usb_wacom_handle_reset(USBDevice *dev)
        !           229: {
        !           230:     USBWacomState *s = (USBWacomState *) dev;
        !           231: 
        !           232:     s->dx = 0;
        !           233:     s->dy = 0;
        !           234:     s->dz = 0;
        !           235:     s->x = 0;
        !           236:     s->y = 0;
        !           237:     s->buttons_state = 0;
        !           238:     s->mode = WACOM_MODE_HID;
        !           239: }
        !           240: 
        !           241: static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
        !           242:                                     int index, int length, uint8_t *data)
        !           243: {
        !           244:     USBWacomState *s = (USBWacomState *) dev;
        !           245:     int ret = 0;
        !           246: 
        !           247:     switch (request) {
        !           248:     case DeviceRequest | USB_REQ_GET_STATUS:
        !           249:         data[0] = (1 << USB_DEVICE_SELF_POWERED) |
        !           250:             (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
        !           251:         data[1] = 0x00;
        !           252:         ret = 2;
        !           253:         break;
        !           254:     case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
        !           255:         if (value == USB_DEVICE_REMOTE_WAKEUP) {
        !           256:             dev->remote_wakeup = 0;
        !           257:         } else {
        !           258:             goto fail;
        !           259:         }
        !           260:         ret = 0;
        !           261:         break;
        !           262:     case DeviceOutRequest | USB_REQ_SET_FEATURE:
        !           263:         if (value == USB_DEVICE_REMOTE_WAKEUP) {
        !           264:             dev->remote_wakeup = 1;
        !           265:         } else {
        !           266:             goto fail;
        !           267:         }
        !           268:         ret = 0;
        !           269:         break;
        !           270:     case DeviceOutRequest | USB_REQ_SET_ADDRESS:
        !           271:         dev->addr = value;
        !           272:         ret = 0;
        !           273:         break;
        !           274:     case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
        !           275:         switch (value >> 8) {
        !           276:         case USB_DT_DEVICE:
        !           277:             memcpy(data, qemu_wacom_dev_descriptor,
        !           278:                    sizeof(qemu_wacom_dev_descriptor));
        !           279:             ret = sizeof(qemu_wacom_dev_descriptor);
        !           280:             break;
        !           281:         case USB_DT_CONFIG:
        !           282:                    memcpy(data, qemu_wacom_config_descriptor,
        !           283:                    sizeof(qemu_wacom_config_descriptor));
        !           284:             ret = sizeof(qemu_wacom_config_descriptor);
        !           285:             break;
        !           286:         case USB_DT_STRING:
        !           287:             switch (value & 0xff) {
        !           288:             case 0:
        !           289:                 /* language ids */
        !           290:                 data[0] = 4;
        !           291:                 data[1] = 3;
        !           292:                 data[2] = 0x09;
        !           293:                 data[3] = 0x04;
        !           294:                 ret = 4;
        !           295:                 break;
        !           296:             case 1:
        !           297:                 /* serial number */
        !           298:                 ret = set_usb_string(data, "1");
        !           299:                 break;
        !           300:             case 2:
        !           301:                ret = set_usb_string(data, "Wacom PenPartner");
        !           302:                 break;
        !           303:             case 3:
        !           304:                 /* vendor description */
        !           305:                 ret = set_usb_string(data, "QEMU " QEMU_VERSION);
        !           306:                 break;
        !           307:             case 4:
        !           308:                 ret = set_usb_string(data, "Wacom Tablet");
        !           309:                 break;
        !           310:             case 5:
        !           311:                 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
        !           312:                 break;
        !           313:             default:
        !           314:                 goto fail;
        !           315:             }
        !           316:             break;
        !           317:         default:
        !           318:             goto fail;
        !           319:         }
        !           320:         break;
        !           321:     case DeviceRequest | USB_REQ_GET_CONFIGURATION:
        !           322:         data[0] = 1;
        !           323:         ret = 1;
        !           324:         break;
        !           325:     case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
        !           326:         ret = 0;
        !           327:         break;
        !           328:     case DeviceRequest | USB_REQ_GET_INTERFACE:
        !           329:         data[0] = 0;
        !           330:         ret = 1;
        !           331:         break;
        !           332:     case DeviceOutRequest | USB_REQ_SET_INTERFACE:
        !           333:         ret = 0;
        !           334:         break;
        !           335:     case WACOM_SET_REPORT:
        !           336:         qemu_remove_mouse_event_handler(s->eh_entry);
        !           337:         s->mouse_grabbed = 0;
        !           338:         s->mode = data[0];
        !           339:         ret = 0;
        !           340:         break;
        !           341:     case WACOM_GET_REPORT:
        !           342:         data[0] = 0;
        !           343:         data[1] = s->mode;
        !           344:         ret = 2;
        !           345:         break;
        !           346:     /* USB HID requests */
        !           347:     case HID_GET_REPORT:
        !           348:         if (s->mode == WACOM_MODE_HID)
        !           349:             ret = usb_mouse_poll(s, data, length);
        !           350:         else if (s->mode == WACOM_MODE_WACOM)
        !           351:             ret = usb_wacom_poll(s, data, length);
        !           352:         break;
        !           353:     case HID_SET_IDLE:
        !           354:         ret = 0;
        !           355:         break;
        !           356:     default:
        !           357:     fail:
        !           358:         ret = USB_RET_STALL;
        !           359:         break;
        !           360:     }
        !           361:     return ret;
        !           362: }
        !           363: 
        !           364: static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
        !           365: {
        !           366:     USBWacomState *s = (USBWacomState *) dev;
        !           367:     int ret = 0;
        !           368: 
        !           369:     switch (p->pid) {
        !           370:     case USB_TOKEN_IN:
        !           371:         if (p->devep == 1) {
        !           372:             if (s->mode == WACOM_MODE_HID)
        !           373:                 ret = usb_mouse_poll(s, p->data, p->len);
        !           374:             else if (s->mode == WACOM_MODE_WACOM)
        !           375:                 ret = usb_wacom_poll(s, p->data, p->len);
        !           376:             break;
        !           377:         }
        !           378:         /* Fall through.  */
        !           379:     case USB_TOKEN_OUT:
        !           380:     default:
        !           381:         ret = USB_RET_STALL;
        !           382:         break;
        !           383:     }
        !           384:     return ret;
        !           385: }
        !           386: 
        !           387: static void usb_wacom_handle_destroy(USBDevice *dev)
        !           388: {
        !           389:     USBWacomState *s = (USBWacomState *) dev;
        !           390: 
        !           391:     qemu_remove_mouse_event_handler(s->eh_entry);
        !           392:     qemu_free(s);
        !           393: }
        !           394: 
        !           395: USBDevice *usb_wacom_init(void)
        !           396: {
        !           397:     USBWacomState *s;
        !           398: 
        !           399:     s = qemu_mallocz(sizeof(USBWacomState));
        !           400:     if (!s)
        !           401:         return NULL;
        !           402:     s->dev.speed = USB_SPEED_FULL;
        !           403:     s->dev.handle_packet = usb_generic_handle_packet;
        !           404: 
        !           405:     s->dev.handle_reset = usb_wacom_handle_reset;
        !           406:     s->dev.handle_control = usb_wacom_handle_control;
        !           407:     s->dev.handle_data = usb_wacom_handle_data;
        !           408:     s->dev.handle_destroy = usb_wacom_handle_destroy;
        !           409: 
        !           410:     pstrcpy(s->dev.devname, sizeof(s->dev.devname),
        !           411:             "QEMU PenPartner Tablet");
        !           412: 
        !           413:     return (USBDevice *) s;
        !           414: }

unix.superglobalmegacorp.com

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