Annotation of qemu/hw/usb/dev-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/hw.h"
        !            29: #include "console.h"
        !            30: #include "hw/usb.h"
        !            31: #include "hw/usb/desc.h"
        !            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;
        !            54:     uint8_t idle;
        !            55:     int changed;
        !            56: } USBWacomState;
        !            57: 
        !            58: enum {
        !            59:     STR_MANUFACTURER = 1,
        !            60:     STR_PRODUCT,
        !            61:     STR_SERIALNUMBER,
        !            62: };
        !            63: 
        !            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:             .nif = 1,
        !           112:             .ifs = &desc_iface_wacom,
        !           113:         },
        !           114:     },
        !           115: };
        !           116: 
        !           117: static const USBDesc desc_wacom = {
        !           118:     .id = {
        !           119:         .idVendor          = 0x056a,
        !           120:         .idProduct         = 0x0000,
        !           121:         .bcdDevice         = 0x4210,
        !           122:         .iManufacturer     = STR_MANUFACTURER,
        !           123:         .iProduct          = STR_PRODUCT,
        !           124:         .iSerialNumber     = STR_SERIALNUMBER,
        !           125:     },
        !           126:     .full = &desc_device_wacom,
        !           127:     .str  = desc_strings,
        !           128: };
        !           129: 
        !           130: static void usb_mouse_event(void *opaque,
        !           131:                             int dx1, int dy1, int dz1, int buttons_state)
        !           132: {
        !           133:     USBWacomState *s = opaque;
        !           134: 
        !           135:     s->dx += dx1;
        !           136:     s->dy += dy1;
        !           137:     s->dz += dz1;
        !           138:     s->buttons_state = buttons_state;
        !           139:     s->changed = 1;
        !           140: }
        !           141: 
        !           142: static void usb_wacom_event(void *opaque,
        !           143:                             int x, int y, int dz, int buttons_state)
        !           144: {
        !           145:     USBWacomState *s = opaque;
        !           146: 
        !           147:     /* scale to Penpartner resolution */
        !           148:     s->x = (x * 5040 / 0x7FFF);
        !           149:     s->y = (y * 3780 / 0x7FFF);
        !           150:     s->dz += dz;
        !           151:     s->buttons_state = buttons_state;
        !           152:     s->changed = 1;
        !           153: }
        !           154: 
        !           155: static inline int int_clamp(int val, int vmin, int vmax)
        !           156: {
        !           157:     if (val < vmin)
        !           158:         return vmin;
        !           159:     else if (val > vmax)
        !           160:         return vmax;
        !           161:     else
        !           162:         return val;
        !           163: }
        !           164: 
        !           165: static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
        !           166: {
        !           167:     int dx, dy, dz, b, l;
        !           168: 
        !           169:     if (!s->mouse_grabbed) {
        !           170:         s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
        !           171:                         "QEMU PenPartner tablet");
        !           172:         qemu_activate_mouse_event_handler(s->eh_entry);
        !           173:         s->mouse_grabbed = 1;
        !           174:     }
        !           175: 
        !           176:     dx = int_clamp(s->dx, -128, 127);
        !           177:     dy = int_clamp(s->dy, -128, 127);
        !           178:     dz = int_clamp(s->dz, -128, 127);
        !           179: 
        !           180:     s->dx -= dx;
        !           181:     s->dy -= dy;
        !           182:     s->dz -= dz;
        !           183: 
        !           184:     b = 0;
        !           185:     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
        !           186:         b |= 0x01;
        !           187:     if (s->buttons_state & MOUSE_EVENT_RBUTTON)
        !           188:         b |= 0x02;
        !           189:     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
        !           190:         b |= 0x04;
        !           191: 
        !           192:     buf[0] = b;
        !           193:     buf[1] = dx;
        !           194:     buf[2] = dy;
        !           195:     l = 3;
        !           196:     if (len >= 4) {
        !           197:         buf[3] = dz;
        !           198:         l = 4;
        !           199:     }
        !           200:     return l;
        !           201: }
        !           202: 
        !           203: static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
        !           204: {
        !           205:     int b;
        !           206: 
        !           207:     if (!s->mouse_grabbed) {
        !           208:         s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
        !           209:                         "QEMU PenPartner tablet");
        !           210:         qemu_activate_mouse_event_handler(s->eh_entry);
        !           211:         s->mouse_grabbed = 1;
        !           212:     }
        !           213: 
        !           214:     b = 0;
        !           215:     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
        !           216:         b |= 0x01;
        !           217:     if (s->buttons_state & MOUSE_EVENT_RBUTTON)
        !           218:         b |= 0x40;
        !           219:     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
        !           220:         b |= 0x20; /* eraser */
        !           221: 
        !           222:     if (len < 7)
        !           223:         return 0;
        !           224: 
        !           225:     buf[0] = s->mode;
        !           226:     buf[5] = 0x00 | (b & 0xf0);
        !           227:     buf[1] = s->x & 0xff;
        !           228:     buf[2] = s->x >> 8;
        !           229:     buf[3] = s->y & 0xff;
        !           230:     buf[4] = s->y >> 8;
        !           231:     if (b & 0x3f) {
        !           232:         buf[6] = 0;
        !           233:     } else {
        !           234:         buf[6] = (unsigned char) -127;
        !           235:     }
        !           236: 
        !           237:     return 7;
        !           238: }
        !           239: 
        !           240: static void usb_wacom_handle_reset(USBDevice *dev)
        !           241: {
        !           242:     USBWacomState *s = (USBWacomState *) dev;
        !           243: 
        !           244:     s->dx = 0;
        !           245:     s->dy = 0;
        !           246:     s->dz = 0;
        !           247:     s->x = 0;
        !           248:     s->y = 0;
        !           249:     s->buttons_state = 0;
        !           250:     s->mode = WACOM_MODE_HID;
        !           251: }
        !           252: 
        !           253: static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
        !           254:                int request, int value, int index, int length, uint8_t *data)
        !           255: {
        !           256:     USBWacomState *s = (USBWacomState *) dev;
        !           257:     int ret;
        !           258: 
        !           259:     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
        !           260:     if (ret >= 0) {
        !           261:         return ret;
        !           262:     }
        !           263: 
        !           264:     ret = 0;
        !           265:     switch (request) {
        !           266:     case WACOM_SET_REPORT:
        !           267:         if (s->mouse_grabbed) {
        !           268:             qemu_remove_mouse_event_handler(s->eh_entry);
        !           269:             s->mouse_grabbed = 0;
        !           270:         }
        !           271:         s->mode = data[0];
        !           272:         ret = 0;
        !           273:         break;
        !           274:     case WACOM_GET_REPORT:
        !           275:         data[0] = 0;
        !           276:         data[1] = s->mode;
        !           277:         ret = 2;
        !           278:         break;
        !           279:     /* USB HID requests */
        !           280:     case HID_GET_REPORT:
        !           281:         if (s->mode == WACOM_MODE_HID)
        !           282:             ret = usb_mouse_poll(s, data, length);
        !           283:         else if (s->mode == WACOM_MODE_WACOM)
        !           284:             ret = usb_wacom_poll(s, data, length);
        !           285:         break;
        !           286:     case HID_GET_IDLE:
        !           287:         ret = 1;
        !           288:         data[0] = s->idle;
        !           289:         break;
        !           290:     case HID_SET_IDLE:
        !           291:         s->idle = (uint8_t) (value >> 8);
        !           292:         ret = 0;
        !           293:         break;
        !           294:     default:
        !           295:         ret = USB_RET_STALL;
        !           296:         break;
        !           297:     }
        !           298:     return ret;
        !           299: }
        !           300: 
        !           301: static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
        !           302: {
        !           303:     USBWacomState *s = (USBWacomState *) dev;
        !           304:     uint8_t buf[p->iov.size];
        !           305:     int ret = 0;
        !           306: 
        !           307:     switch (p->pid) {
        !           308:     case USB_TOKEN_IN:
        !           309:         if (p->ep->nr == 1) {
        !           310:             if (!(s->changed || s->idle))
        !           311:                 return USB_RET_NAK;
        !           312:             s->changed = 0;
        !           313:             if (s->mode == WACOM_MODE_HID)
        !           314:                 ret = usb_mouse_poll(s, buf, p->iov.size);
        !           315:             else if (s->mode == WACOM_MODE_WACOM)
        !           316:                 ret = usb_wacom_poll(s, buf, p->iov.size);
        !           317:             usb_packet_copy(p, buf, ret);
        !           318:             break;
        !           319:         }
        !           320:         /* Fall through.  */
        !           321:     case USB_TOKEN_OUT:
        !           322:     default:
        !           323:         ret = USB_RET_STALL;
        !           324:         break;
        !           325:     }
        !           326:     return ret;
        !           327: }
        !           328: 
        !           329: static void usb_wacom_handle_destroy(USBDevice *dev)
        !           330: {
        !           331:     USBWacomState *s = (USBWacomState *) dev;
        !           332: 
        !           333:     if (s->mouse_grabbed) {
        !           334:         qemu_remove_mouse_event_handler(s->eh_entry);
        !           335:         s->mouse_grabbed = 0;
        !           336:     }
        !           337: }
        !           338: 
        !           339: static int usb_wacom_initfn(USBDevice *dev)
        !           340: {
        !           341:     USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
        !           342:     usb_desc_create_serial(dev);
        !           343:     usb_desc_init(dev);
        !           344:     s->changed = 1;
        !           345:     return 0;
        !           346: }
        !           347: 
        !           348: static const VMStateDescription vmstate_usb_wacom = {
        !           349:     .name = "usb-wacom",
        !           350:     .unmigratable = 1,
        !           351: };
        !           352: 
        !           353: static void usb_wacom_class_init(ObjectClass *klass, void *data)
        !           354: {
        !           355:     DeviceClass *dc = DEVICE_CLASS(klass);
        !           356:     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
        !           357: 
        !           358:     uc->product_desc   = "QEMU PenPartner Tablet";
        !           359:     uc->usb_desc       = &desc_wacom;
        !           360:     uc->init           = usb_wacom_initfn;
        !           361:     uc->handle_reset   = usb_wacom_handle_reset;
        !           362:     uc->handle_control = usb_wacom_handle_control;
        !           363:     uc->handle_data    = usb_wacom_handle_data;
        !           364:     uc->handle_destroy = usb_wacom_handle_destroy;
        !           365:     dc->desc = "QEMU PenPartner Tablet";
        !           366:     dc->vmsd = &vmstate_usb_wacom;
        !           367: }
        !           368: 
        !           369: static TypeInfo wacom_info = {
        !           370:     .name          = "usb-wacom-tablet",
        !           371:     .parent        = TYPE_USB_DEVICE,
        !           372:     .instance_size = sizeof(USBWacomState),
        !           373:     .class_init    = usb_wacom_class_init,
        !           374: };
        !           375: 
        !           376: static void usb_wacom_register_types(void)
        !           377: {
        !           378:     type_register_static(&wacom_info);
        !           379:     usb_legacy_register("usb-wacom-tablet", "wacom-tablet", NULL);
        !           380: }
        !           381: 
        !           382: type_init(usb_wacom_register_types)

unix.superglobalmegacorp.com

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