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

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"
1.1.1.4 ! root       31: #include "usb-desc.h"
1.1       root       32: 
                     33: /* Interface requests */
                     34: #define WACOM_GET_REPORT       0x2101
                     35: #define WACOM_SET_REPORT       0x2109
                     36: 
                     37: /* HID interface requests */
                     38: #define HID_GET_REPORT         0xa101
                     39: #define HID_GET_IDLE           0xa102
                     40: #define HID_GET_PROTOCOL       0xa103
                     41: #define HID_SET_IDLE           0x210a
                     42: #define HID_SET_PROTOCOL       0x210b
                     43: 
                     44: typedef struct USBWacomState {
                     45:     USBDevice dev;
                     46:     QEMUPutMouseEntry *eh_entry;
                     47:     int dx, dy, dz, buttons_state;
                     48:     int x, y;
                     49:     int mouse_grabbed;
                     50:     enum {
                     51:         WACOM_MODE_HID = 1,
                     52:         WACOM_MODE_WACOM = 2,
                     53:     } mode;
1.1.1.3   root       54:     uint8_t idle;
                     55:     int changed;
1.1       root       56: } USBWacomState;
                     57: 
1.1.1.4 ! root       58: enum {
        !            59:     STR_MANUFACTURER = 1,
        !            60:     STR_PRODUCT,
        !            61:     STR_SERIALNUMBER,
1.1       root       62: };
                     63: 
1.1.1.4 ! root       64: static const USBDescStrings desc_strings = {
        !            65:     [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
        !            66:     [STR_PRODUCT]          = "Wacom PenPartner",
        !            67:     [STR_SERIALNUMBER]     = "1",
        !            68: };
        !            69: 
        !            70: static const USBDescIface desc_iface_wacom = {
        !            71:     .bInterfaceNumber              = 0,
        !            72:     .bNumEndpoints                 = 1,
        !            73:     .bInterfaceClass               = USB_CLASS_HID,
        !            74:     .bInterfaceSubClass            = 0x01, /* boot */
        !            75:     .bInterfaceProtocol            = 0x02,
        !            76:     .ndesc                         = 1,
        !            77:     .descs = (USBDescOther[]) {
        !            78:         {
        !            79:             /* HID descriptor */
        !            80:             .data = (uint8_t[]) {
        !            81:                 0x09,          /*  u8  bLength */
        !            82:                 0x21,          /*  u8  bDescriptorType */
        !            83:                 0x01, 0x10,    /*  u16 HID_class */
        !            84:                 0x00,          /*  u8  country_code */
        !            85:                 0x01,          /*  u8  num_descriptors */
        !            86:                 0x22,          /*  u8  type: Report */
        !            87:                 0x6e, 0,       /*  u16 len */
        !            88:             },
        !            89:         },
        !            90:     },
        !            91:     .eps = (USBDescEndpoint[]) {
        !            92:         {
        !            93:             .bEndpointAddress      = USB_DIR_IN | 0x01,
        !            94:             .bmAttributes          = USB_ENDPOINT_XFER_INT,
        !            95:             .wMaxPacketSize        = 8,
        !            96:             .bInterval             = 0x0a,
        !            97:         },
        !            98:     },
        !            99: };
        !           100: 
        !           101: static const USBDescDevice desc_device_wacom = {
        !           102:     .bcdUSB                        = 0x0110,
        !           103:     .bMaxPacketSize0               = 8,
        !           104:     .bNumConfigurations            = 1,
        !           105:     .confs = (USBDescConfig[]) {
        !           106:         {
        !           107:             .bNumInterfaces        = 1,
        !           108:             .bConfigurationValue   = 1,
        !           109:             .bmAttributes          = 0x80,
        !           110:             .bMaxPower             = 40,
        !           111:             .ifs = &desc_iface_wacom,
        !           112:         },
        !           113:     },
        !           114: };
        !           115: 
        !           116: static const USBDesc desc_wacom = {
        !           117:     .id = {
        !           118:         .idVendor          = 0x056a,
        !           119:         .idProduct         = 0x0000,
        !           120:         .bcdDevice         = 0x4210,
        !           121:         .iManufacturer     = STR_MANUFACTURER,
        !           122:         .iProduct          = STR_PRODUCT,
        !           123:         .iSerialNumber     = STR_SERIALNUMBER,
        !           124:     },
        !           125:     .full = &desc_device_wacom,
        !           126:     .str  = desc_strings,
1.1       root      127: };
                    128: 
                    129: static void usb_mouse_event(void *opaque,
                    130:                             int dx1, int dy1, int dz1, int buttons_state)
                    131: {
                    132:     USBWacomState *s = opaque;
                    133: 
                    134:     s->dx += dx1;
                    135:     s->dy += dy1;
                    136:     s->dz += dz1;
                    137:     s->buttons_state = buttons_state;
1.1.1.3   root      138:     s->changed = 1;
1.1       root      139: }
                    140: 
                    141: static void usb_wacom_event(void *opaque,
                    142:                             int x, int y, int dz, int buttons_state)
                    143: {
                    144:     USBWacomState *s = opaque;
                    145: 
1.1.1.3   root      146:     /* scale to Penpartner resolution */
                    147:     s->x = (x * 5040 / 0x7FFF);
                    148:     s->y = (y * 3780 / 0x7FFF);
1.1       root      149:     s->dz += dz;
                    150:     s->buttons_state = buttons_state;
1.1.1.3   root      151:     s->changed = 1;
1.1       root      152: }
                    153: 
                    154: static inline int int_clamp(int val, int vmin, int vmax)
                    155: {
                    156:     if (val < vmin)
                    157:         return vmin;
                    158:     else if (val > vmax)
                    159:         return vmax;
                    160:     else
                    161:         return val;
                    162: }
                    163: 
                    164: static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
                    165: {
                    166:     int dx, dy, dz, b, l;
                    167: 
                    168:     if (!s->mouse_grabbed) {
                    169:         s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
                    170:                         "QEMU PenPartner tablet");
1.1.1.4 ! root      171:         qemu_activate_mouse_event_handler(s->eh_entry);
1.1       root      172:         s->mouse_grabbed = 1;
                    173:     }
                    174: 
                    175:     dx = int_clamp(s->dx, -128, 127);
                    176:     dy = int_clamp(s->dy, -128, 127);
                    177:     dz = int_clamp(s->dz, -128, 127);
                    178: 
                    179:     s->dx -= dx;
                    180:     s->dy -= dy;
                    181:     s->dz -= dz;
                    182: 
                    183:     b = 0;
                    184:     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
                    185:         b |= 0x01;
                    186:     if (s->buttons_state & MOUSE_EVENT_RBUTTON)
                    187:         b |= 0x02;
                    188:     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
                    189:         b |= 0x04;
                    190: 
                    191:     buf[0] = b;
                    192:     buf[1] = dx;
                    193:     buf[2] = dy;
                    194:     l = 3;
                    195:     if (len >= 4) {
                    196:         buf[3] = dz;
                    197:         l = 4;
                    198:     }
                    199:     return l;
                    200: }
                    201: 
                    202: static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
                    203: {
                    204:     int b;
                    205: 
                    206:     if (!s->mouse_grabbed) {
                    207:         s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
                    208:                         "QEMU PenPartner tablet");
1.1.1.4 ! root      209:         qemu_activate_mouse_event_handler(s->eh_entry);
1.1       root      210:         s->mouse_grabbed = 1;
                    211:     }
                    212: 
                    213:     b = 0;
                    214:     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
                    215:         b |= 0x01;
                    216:     if (s->buttons_state & MOUSE_EVENT_RBUTTON)
1.1.1.3   root      217:         b |= 0x40;
1.1       root      218:     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
1.1.1.3   root      219:         b |= 0x20; /* eraser */
1.1       root      220: 
                    221:     if (len < 7)
                    222:         return 0;
                    223: 
                    224:     buf[0] = s->mode;
1.1.1.3   root      225:     buf[5] = 0x00 | (b & 0xf0);
                    226:     buf[1] = s->x & 0xff;
                    227:     buf[2] = s->x >> 8;
                    228:     buf[3] = s->y & 0xff;
                    229:     buf[4] = s->y >> 8;
                    230:     if (b & 0x3f) {
1.1       root      231:         buf[6] = 0;
                    232:     } else {
                    233:         buf[6] = (unsigned char) -127;
                    234:     }
                    235: 
                    236:     return 7;
                    237: }
                    238: 
                    239: static void usb_wacom_handle_reset(USBDevice *dev)
                    240: {
                    241:     USBWacomState *s = (USBWacomState *) dev;
                    242: 
                    243:     s->dx = 0;
                    244:     s->dy = 0;
                    245:     s->dz = 0;
                    246:     s->x = 0;
                    247:     s->y = 0;
                    248:     s->buttons_state = 0;
                    249:     s->mode = WACOM_MODE_HID;
                    250: }
                    251: 
                    252: static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
                    253:                                     int index, int length, uint8_t *data)
                    254: {
                    255:     USBWacomState *s = (USBWacomState *) dev;
1.1.1.4 ! root      256:     int ret;
        !           257: 
        !           258:     ret = usb_desc_handle_control(dev, request, value, index, length, data);
        !           259:     if (ret >= 0) {
        !           260:         return ret;
        !           261:     }
1.1       root      262: 
1.1.1.4 ! root      263:     ret = 0;
1.1       root      264:     switch (request) {
                    265:     case DeviceRequest | USB_REQ_GET_INTERFACE:
                    266:         data[0] = 0;
                    267:         ret = 1;
                    268:         break;
                    269:     case DeviceOutRequest | USB_REQ_SET_INTERFACE:
                    270:         ret = 0;
                    271:         break;
                    272:     case WACOM_SET_REPORT:
1.1.1.4 ! root      273:         if (s->mouse_grabbed) {
        !           274:             qemu_remove_mouse_event_handler(s->eh_entry);
        !           275:             s->mouse_grabbed = 0;
        !           276:         }
1.1       root      277:         s->mode = data[0];
                    278:         ret = 0;
                    279:         break;
                    280:     case WACOM_GET_REPORT:
                    281:         data[0] = 0;
                    282:         data[1] = s->mode;
                    283:         ret = 2;
                    284:         break;
                    285:     /* USB HID requests */
                    286:     case HID_GET_REPORT:
                    287:         if (s->mode == WACOM_MODE_HID)
                    288:             ret = usb_mouse_poll(s, data, length);
                    289:         else if (s->mode == WACOM_MODE_WACOM)
                    290:             ret = usb_wacom_poll(s, data, length);
                    291:         break;
1.1.1.3   root      292:     case HID_GET_IDLE:
                    293:         ret = 1;
                    294:         data[0] = s->idle;
                    295:         break;
1.1       root      296:     case HID_SET_IDLE:
1.1.1.3   root      297:         s->idle = (uint8_t) (value >> 8);
1.1       root      298:         ret = 0;
                    299:         break;
                    300:     default:
                    301:         ret = USB_RET_STALL;
                    302:         break;
                    303:     }
                    304:     return ret;
                    305: }
                    306: 
                    307: static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
                    308: {
                    309:     USBWacomState *s = (USBWacomState *) dev;
                    310:     int ret = 0;
                    311: 
                    312:     switch (p->pid) {
                    313:     case USB_TOKEN_IN:
                    314:         if (p->devep == 1) {
1.1.1.3   root      315:             if (!(s->changed || s->idle))
                    316:                 return USB_RET_NAK;
                    317:             s->changed = 0;
1.1       root      318:             if (s->mode == WACOM_MODE_HID)
                    319:                 ret = usb_mouse_poll(s, p->data, p->len);
                    320:             else if (s->mode == WACOM_MODE_WACOM)
                    321:                 ret = usb_wacom_poll(s, p->data, p->len);
                    322:             break;
                    323:         }
                    324:         /* Fall through.  */
                    325:     case USB_TOKEN_OUT:
                    326:     default:
                    327:         ret = USB_RET_STALL;
                    328:         break;
                    329:     }
                    330:     return ret;
                    331: }
                    332: 
                    333: static void usb_wacom_handle_destroy(USBDevice *dev)
                    334: {
                    335:     USBWacomState *s = (USBWacomState *) dev;
                    336: 
1.1.1.4 ! root      337:     if (s->mouse_grabbed) {
        !           338:         qemu_remove_mouse_event_handler(s->eh_entry);
        !           339:         s->mouse_grabbed = 0;
        !           340:     }
1.1       root      341: }
                    342: 
1.1.1.3   root      343: static int usb_wacom_initfn(USBDevice *dev)
1.1       root      344: {
1.1.1.3   root      345:     USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
1.1.1.4 ! root      346:     usb_desc_init(dev);
1.1.1.3   root      347:     s->changed = 1;
                    348:     return 0;
                    349: }
1.1       root      350: 
1.1.1.3   root      351: static struct USBDeviceInfo wacom_info = {
                    352:     .product_desc   = "QEMU PenPartner Tablet",
                    353:     .qdev.name      = "usb-wacom-tablet",
                    354:     .qdev.desc      = "QEMU PenPartner Tablet",
                    355:     .usbdevice_name = "wacom-tablet",
1.1.1.4 ! root      356:     .usb_desc       = &desc_wacom,
1.1.1.3   root      357:     .qdev.size      = sizeof(USBWacomState),
                    358:     .init           = usb_wacom_initfn,
                    359:     .handle_packet  = usb_generic_handle_packet,
                    360:     .handle_reset   = usb_wacom_handle_reset,
                    361:     .handle_control = usb_wacom_handle_control,
                    362:     .handle_data    = usb_wacom_handle_data,
                    363:     .handle_destroy = usb_wacom_handle_destroy,
                    364: };
1.1       root      365: 
1.1.1.3   root      366: static void usb_wacom_register_devices(void)
                    367: {
                    368:     usb_qdev_register(&wacom_info);
1.1       root      369: }
1.1.1.3   root      370: 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.