symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/usb-wacom.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * Wacom PenPartner USB tablet emulation.
       
     3  *
       
     4  * Copyright (c) 2006 Openedhand Ltd.
       
     5  * Author: Andrzej Zaborowski <balrog@zabor.org>
       
     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 }