static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) { unsigned char *rep_data; int limit = 0, report_id = 2; int error = -ENOMEM; rep_data = kmalloc(4, GFP_KERNEL); if (!rep_data) return error; /* ask to report tablet data if it is 2FGT Tablet PC or * not a Tablet PC */ if (((features->type == TABLETPC2FG) || (features->type == MTSCREEN)) && features->device_type != BTN_TOOL_PEN) { do { rep_data[0] = 3; rep_data[1] = 4; rep_data[2] = 0; rep_data[3] = 0; report_id = 3; error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, report_id, rep_data, 4); if (error >= 0) error = usb_get_report(intf, WAC_HID_FEATURE_REPORT, report_id, rep_data, 4); } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES); } else if (features->type != TABLETPC && features->device_type == BTN_TOOL_PEN) { do { rep_data[0] = 2; rep_data[1] = 2; error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, report_id, rep_data, 2); if (error >= 0) error = usb_get_report(intf, WAC_HID_FEATURE_REPORT, report_id, rep_data, 2); } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES); } kfree(rep_data); return error < 0 ? error : 0; }
static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, struct wacom_features *features) { struct usb_device *dev = interface_to_usbdev(intf); char limit = 0; /* result has to be defined as int for some devices */ int result = 0; int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0; unsigned char *report; unsigned char *rep_data; report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); if (!report) return -ENOMEM; rep_data = kmalloc(2, GFP_KERNEL); if (!rep_data) { result = -ENOMEM; goto out1; } /* retrive report descriptors */ do { result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, HID_DEVICET_REPORT << 8, intf->altsetting[0].desc.bInterfaceNumber, /* interface */ report, hid_desc->wDescriptorLength, 5000); /* 5 secs */ } while (result < 0 && limit++ < WAC_MSG_RETRIES); /* No need to parse the Descriptor. It isn't an error though */ if (result < 0) goto out2; for (i = 0; i < hid_desc->wDescriptorLength; i++) { switch (report[i]) { case HID_USAGE_PAGE: switch (report[i + 1]) { case HID_USAGE_PAGE_DIGITIZER: usage = WCM_DIGITIZER; i++; break; case HID_USAGE_PAGE_DESKTOP: usage = WCM_DESKTOP; i++; break; } break; case HID_USAGE: switch (report[i + 1]) { case HID_USAGE_X: if (usage == WCM_DESKTOP) { if (finger) { features->device_type = BTN_TOOL_FINGER; if (features->type == TABLETPC2FG) { features->pktlen = WACOM_PKGLEN_TPC2FG; features->touch_max = 2; } if (features->type == MTSCREEN) features->pktlen = WACOM_PKGLEN_MTOUCH; if (features->type == BAMBOO_PT) { features->pktlen = WACOM_PKGLEN_BBTOUCH; features->touch_max = 2; features->x_phy = get_unaligned_le16(&report[i + 5]); features->x_max = get_unaligned_le16(&report[i + 8]); i += 15; } else { features->touch_max = 1; features->x_max = get_unaligned_le16(&report[i + 3]); features->x_phy = get_unaligned_le16(&report[i + 6]); features->unit = report[i + 9]; features->unitExpo = report[i + 11]; i += 12; } } else if (pen) { features->device_type = BTN_TOOL_PEN; features->x_max = get_unaligned_le16(&report[i + 3]); i += 4; } } break; case HID_USAGE_Y: if (usage == WCM_DESKTOP) { if (finger) { int type = features->type; features->device_type = BTN_TOOL_FINGER; if (type == TABLETPC2FG || type == MTSCREEN) { features->y_max = get_unaligned_le16(&report[i + 3]); features->y_phy = get_unaligned_le16(&report[i + 6]); i += 7; } else if (type == BAMBOO_PT) { features->y_phy = get_unaligned_le16(&report[i + 3]); features->y_max = get_unaligned_le16(&report[i + 6]); i += 12; } else { features->y_max = features->x_max; features->y_phy = get_unaligned_le16(&report[i + 3]); i += 4; } } else if (pen) { features->device_type = BTN_TOOL_PEN; features->y_max = get_unaligned_le16(&report[i + 3]); i += 4; } } break; case HID_USAGE_FINGER: finger = 1; i++; break; case HID_USAGE_STYLUS: pen = 1; i++; break; break; case HID_MT_CONTACTMAX: do { rep_data[0] = 12; result = usb_get_report(intf, WAC_HID_FEATURE_REPORT, rep_data[0], rep_data, 2); } while (result < 0 && limit++ < WAC_MSG_RETRIES); if ((result >= 0) && (rep_data[1] > 2)) features->touch_max = rep_data[1]; i++; } break; case HID_COLLECTION: /* reset UsagePage and Finger */ finger = usage = 0; break; } } out2: result = 0; kfree(rep_data); out1: kfree(report); return result; }
/** * iowarrior_ioctl */ static long iowarrior_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct iowarrior *dev = NULL; __u8 *buffer; __u8 __user *user_buffer; int retval; int io_res; /* checks for bytes read/written and copy_to/from_user results */ dev = file->private_data; if (dev == NULL) { return -ENODEV; } buffer = kzalloc(dev->report_size, GFP_KERNEL); if (!buffer) return -ENOMEM; /* lock this object */ mutex_lock(&iowarrior_mutex); mutex_lock(&dev->mutex); /* verify that the device wasn't unplugged */ if (!dev->present) { retval = -ENODEV; goto error_out; } dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd, arg); retval = 0; io_res = 0; switch (cmd) { case IOW_WRITE: if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { user_buffer = (__u8 __user *)arg; io_res = copy_from_user(buffer, user_buffer, dev->report_size); if (io_res) { retval = -EFAULT; } else { io_res = usb_set_report(dev->interface, 2, 0, buffer, dev->report_size); if (io_res < 0) retval = io_res; } } else { retval = -EINVAL; dev_err(&dev->interface->dev, "ioctl 'IOW_WRITE' is not supported for product=0x%x.\n", dev->product_id); } break; case IOW_READ: user_buffer = (__u8 __user *)arg; io_res = usb_get_report(dev->udev, dev->interface->cur_altsetting, 1, 0, buffer, dev->report_size); if (io_res < 0) retval = io_res; else { io_res = copy_to_user(user_buffer, buffer, dev->report_size); if (io_res) retval = -EFAULT; } break; case IOW_GETINFO: { /* Report available information for the device */ struct iowarrior_info info; /* needed for power consumption */ struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; memset(&info, 0, sizeof(info)); /* directly from the descriptor */ info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); info.product = dev->product_id; info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); /* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */ info.speed = le16_to_cpu(dev->udev->speed); info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; info.report_size = dev->report_size; /* serial number string has been read earlier 8 chars or empty string */ memcpy(info.serial, dev->chip_serial, sizeof(dev->chip_serial)); if (cfg_descriptor == NULL) { info.power = -1; /* no information available */ } else { /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */ info.power = cfg_descriptor->bMaxPower * 2; } io_res = copy_to_user((struct iowarrior_info __user *)arg, &info, sizeof(struct iowarrior_info)); if (io_res) retval = -EFAULT; break; } default: /* return that we did not understand this ioctl call */ retval = -ENOTTY; break; } error_out: /* unlock the device */ mutex_unlock(&dev->mutex); mutex_unlock(&iowarrior_mutex); kfree(buffer); return retval; }
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface = intf->cur_altsetting; struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; struct wacom_wac *wacom_wac; struct wacom_features *features; struct input_dev *input_dev; int error = -ENOMEM; char rep_data[2], limit = 0; struct hid_descriptor *hid_desc; wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL); input_dev = input_allocate_device(); if (!wacom || !input_dev || !wacom_wac) goto fail1; wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma); if (!wacom_wac->data) goto fail1; wacom->irq = usb_alloc_urb(0, GFP_KERNEL); if (!wacom->irq) goto fail2; wacom->usbdev = dev; wacom->dev = input_dev; wacom->intf = intf; mutex_init(&wacom->lock); usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); wacom_wac->features = features = get_wacom_feature(id); BUG_ON(features->pktlen > 10); input_dev->name = wacom_wac->features->name; wacom->wacom_wac = wacom_wac; usb_to_input_id(dev, &input_dev->id); input_dev->dev.parent = &intf->dev; input_set_drvdata(input_dev, wacom); input_dev->open = wacom_open; input_dev->close = wacom_close; endpoint = &intf->cur_altsetting->endpoint[0].desc; /* Initialize touch_x_max and touch_y_max in case it is not defined */ if (wacom_wac->features->type == TABLETPC) { features->touch_x_max = 1023; features->touch_y_max = 1023; } else { features->touch_x_max = 0; features->touch_y_max = 0; } /* TabletPC need to retrieve the physical and logical maximum from report descriptor */ if (wacom_wac->features->type == TABLETPC) { if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) { if (usb_get_extra_descriptor(&interface->endpoint[0], HID_DEVICET_REPORT, &hid_desc)) { printk("wacom: can not retrive extra class descriptor\n"); goto fail2; } } error = wacom_parse_hid(intf, hid_desc, wacom_wac); if (error) goto fail2; } input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS); input_set_abs_params(input_dev, ABS_X, 0, features->x_max, 4, 0); input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, 4, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 0); if (features->type == TABLETPC) { input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP); input_set_abs_params(input_dev, ABS_RX, 0, features->touch_x_max, 4, 0); input_set_abs_params(input_dev, ABS_RY, 0, features->touch_y_max, 4, 0); } input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); wacom_init_input_dev(input_dev, wacom_wac); usb_fill_int_urb(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), wacom_wac->data, wacom_wac->features->pktlen, wacom_sys_irq, wacom, endpoint->bInterval); wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; error = input_register_device(wacom->dev); if (error) goto fail3; /* * Ask the tablet to report tablet data if it is not a Tablet PC. * Repeat until it succeeds */ if (wacom_wac->features->type != TABLETPC) { do { rep_data[0] = 2; rep_data[1] = 2; error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, 2, rep_data, 2); if (error >= 0) error = usb_get_report(intf, WAC_HID_FEATURE_REPORT, 2, rep_data, 2); } while ((error < 0 || rep_data[1] != 2) && limit++ < 5); } usb_set_intfdata(intf, wacom); return 0; fail3: usb_free_urb(wacom->irq); fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma); fail1: input_free_device(input_dev); kfree(wacom); kfree(wacom_wac); return error; }
static long iowarrior_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct iowarrior *dev = NULL; __u8 *buffer; __u8 __user *user_buffer; int retval; int io_res; /* */ dev = file->private_data; if (dev == NULL) { return -ENODEV; } buffer = kzalloc(dev->report_size, GFP_KERNEL); if (!buffer) return -ENOMEM; /* */ mutex_lock(&iowarrior_mutex); mutex_lock(&dev->mutex); /* */ if (!dev->present) { retval = -ENODEV; goto error_out; } dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd, arg); retval = 0; io_res = 0; switch (cmd) { case IOW_WRITE: if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { user_buffer = (__u8 __user *)arg; io_res = copy_from_user(buffer, user_buffer, dev->report_size); if (io_res) { retval = -EFAULT; } else { io_res = usb_set_report(dev->interface, 2, 0, buffer, dev->report_size); if (io_res < 0) retval = io_res; } } else { retval = -EINVAL; dev_err(&dev->interface->dev, "ioctl 'IOW_WRITE' is not supported for product=0x%x.\n", dev->product_id); } break; case IOW_READ: user_buffer = (__u8 __user *)arg; io_res = usb_get_report(dev->udev, dev->interface->cur_altsetting, 1, 0, buffer, dev->report_size); if (io_res < 0) retval = io_res; else { io_res = copy_to_user(user_buffer, buffer, dev->report_size); if (io_res) retval = -EFAULT; } break; case IOW_GETINFO: { /* */ struct iowarrior_info info; /* */ struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; memset(&info, 0, sizeof(info)); /* */ info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); info.product = dev->product_id; info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); /* */ info.speed = le16_to_cpu(dev->udev->speed); info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; info.report_size = dev->report_size; /* */ memcpy(info.serial, dev->chip_serial, sizeof(dev->chip_serial)); if (cfg_descriptor == NULL) { info.power = -1; /* */ } else { /* */ info.power = cfg_descriptor->bMaxPower * 2; } io_res = copy_to_user((struct iowarrior_info __user *)arg, &info, sizeof(struct iowarrior_info)); if (io_res) retval = -EFAULT; break; } default: /* */ retval = -ENOTTY; break; } error_out: /* */ mutex_unlock(&dev->mutex); mutex_unlock(&iowarrior_mutex); kfree(buffer); return retval; }
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; struct wacom_wac *wacom_wac; struct input_dev *input_dev; int error = -ENOMEM; char rep_data[2], limit = 0; wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL); input_dev = input_allocate_device(); if (!wacom || !input_dev || !wacom_wac) goto fail1; wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma); if (!wacom_wac->data) goto fail1; wacom->irq = usb_alloc_urb(0, GFP_KERNEL); if (!wacom->irq) goto fail2; wacom->usbdev = dev; wacom->dev = input_dev; usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); wacom_wac->features = get_wacom_feature(id); BUG_ON(wacom_wac->features->pktlen > 10); input_dev->name = wacom_wac->features->name; wacom->wacom_wac = wacom_wac; usb_to_input_id(dev, &input_dev->id); input_dev->dev.parent = &intf->dev; input_set_drvdata(input_dev, wacom); input_dev->open = wacom_open; input_dev->close = wacom_close; input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS); input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0); input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0); input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); wacom_init_input_dev(input_dev, wacom_wac); endpoint = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), wacom_wac->data, wacom_wac->features->pktlen, wacom_sys_irq, wacom, endpoint->bInterval); wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; error = input_register_device(wacom->dev); if (error) goto fail3; /* Ask the tablet to report tablet data. Repeat until it succeeds */ do { rep_data[0] = 2; rep_data[1] = 2; usb_set_report(intf, 3, 2, rep_data, 2); usb_get_report(intf, 3, 2, rep_data, 2); } while (rep_data[1] != 2 && limit++ < 5); usb_set_intfdata(intf, wacom); return 0; fail3: usb_free_urb(wacom->irq); fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma); fail1: input_free_device(input_dev); kfree(wacom); kfree(wacom_wac); return error; }