static void hid_irq_in(struct urb *urb) { struct hid_device *hid = urb->context; struct usbhid_device *usbhid = hid->driver_data; int status; switch (urb->status) { case 0: /* success */ usbhid_mark_busy(usbhid); usbhid->retry_delay = 0; hid_input_report(urb->context, HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, 1); /* * autosuspend refused while keys are pressed * because most keyboards don't wake up when * a key is released */ if (hid_check_keys_pressed(hid)) set_bit(HID_KEYS_PRESSED, &usbhid->iofl); else clear_bit(HID_KEYS_PRESSED, &usbhid->iofl); break; case -EOVERFLOW: case -EPIPE: /* stall */ usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); set_bit((urb->status == -EPIPE)? HID_CLEAR_HALT:HID_RESET_PENDING, &usbhid->iofl); schedule_work(&usbhid->reset_work); return; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: /* unplug */ clear_bit(HID_IN_RUNNING, &usbhid->iofl); return; case -EILSEQ: /* protocol error or unplug */ case -EPROTO: /* protocol error or unplug */ case -ETIME: /* protocol error or unplug */ case -ETIMEDOUT: /* Should never happen, but... */ usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); hid_io_error(hid); return; default: /* error */ dev_warn(&urb->dev->dev, "input irq status %d " "received\n", urb->status); } status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { err_hid("can't resubmit intr, %s-%s/input%d, status %d", hid_to_usb_dev(hid)->bus->bus_name, hid_to_usb_dev(hid)->devpath, usbhid->ifnum, status); hid_io_error(hid); } } }
static void hid_irq_in(struct urb *urb) { struct hid_device *hid = urb->context; struct usbhid_device *usbhid = hid->driver_data; int status; switch (urb->status) { case 0: usbhid_mark_busy(usbhid); usbhid->retry_delay = 0; hid_input_report(urb->context, HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, 1); if (hid_check_keys_pressed(hid)) set_bit(HID_KEYS_PRESSED, &usbhid->iofl); else clear_bit(HID_KEYS_PRESSED, &usbhid->iofl); break; case -EPIPE: usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); set_bit(HID_CLEAR_HALT, &usbhid->iofl); schedule_work(&usbhid->reset_work); return; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: clear_bit(HID_IN_RUNNING, &usbhid->iofl); return; case -EILSEQ: case -EPROTO: case -ETIME: case -ETIMEDOUT: usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); hid_io_error(hid); return; default: dev_warn(&urb->dev->dev, "input irq status %d " "received\n", urb->status); } status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { err_hid("can't resubmit intr, %s-%s/input%d, status %d", hid_to_usb_dev(hid)->bus->bus_name, hid_to_usb_dev(hid)->devpath, usbhid->ifnum, status); hid_io_error(hid); } } }
int hid_ff_init(struct hid_device* hid) { struct hid_ff_initializer *init; int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor); int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct); for (init = inits; init->idVendor; init++) if (init->idVendor == vendor && init->idProduct == product) break; return init->init(hid); }
static int hid_submit_out(struct hid_device *hid) { struct hid_report *report; char *raw_report; struct usbhid_device *usbhid = hid->driver_data; int r; report = usbhid->out[usbhid->outtail].report; raw_report = usbhid->out[usbhid->outtail].raw_report; r = usb_autopm_get_interface_async(usbhid->intf); if (r < 0) return -1; /* * if the device hasn't been woken, we leave the output * to resume() */ if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) { usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); usbhid->urbout->dev = hid_to_usb_dev(hid); memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length); kfree(raw_report); dbg_hid("submitting out urb\n"); if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { hid_err(hid, "usb_submit_urb(out) failed\n"); usb_autopm_put_interface_async(usbhid->intf); return -1; } usbhid->last_out = jiffies; }
static int hid_submit_out(struct hid_device *hid) { struct hid_report *report; char *raw_report; struct usbhid_device *usbhid = hid->driver_data; report = usbhid->out[usbhid->outtail].report; raw_report = usbhid->out[usbhid->outtail].raw_report; if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) { usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); usbhid->urbout->dev = hid_to_usb_dev(hid); memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length); kfree(raw_report); dbg_hid("submitting out urb\n"); if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { err_hid("usb_submit_urb(out) failed"); return -1; } } else {
static int u2fzero_fill_in_urb(struct u2fzero_device *dev) { struct hid_device *hdev = dev->hdev; struct usb_device *udev; struct usbhid_device *usbhid = hdev->driver_data; unsigned int pipe_in; struct usb_host_endpoint *ep; if (dev->hdev->bus != BUS_USB) return -EINVAL; udev = hid_to_usb_dev(hdev); if (!usbhid->urbout || !usbhid->urbin) return -ENODEV; ep = usb_pipe_endpoint(udev, usbhid->urbin->pipe); if (!ep) return -ENODEV; dev->urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb) return -ENOMEM; pipe_in = (usbhid->urbin->pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); usb_fill_int_urb(dev->urb, udev, pipe_in, dev->buf_in, HID_REPORT_SIZE, u2fzero_read_callback, NULL, ep->desc.bInterval); return 0; }
/* Workqueue routine to reset the device or clear a halt */ static void hid_reset(struct work_struct *work) { struct usbhid_device *usbhid = container_of(work, struct usbhid_device, reset_work); struct hid_device *hid = usbhid->hid; int rc = 0; if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) { dev_dbg(&usbhid->intf->dev, "clear halt\n"); rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe); clear_bit(HID_CLEAR_HALT, &usbhid->iofl); hid_start_in(hid); } else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) { dev_dbg(&usbhid->intf->dev, "resetting device\n"); rc = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf); if (rc == 0) { rc = usb_reset_device(hid_to_usb_dev(hid)); usb_unlock_device(hid_to_usb_dev(hid)); } clear_bit(HID_RESET_PENDING, &usbhid->iofl); } switch (rc) { case 0: if (!test_bit(HID_IN_RUNNING, &usbhid->iofl)) hid_io_error(hid); break; default: hid_err(hid, "can't reset device, %s-%s/input%d, status %d\n", hid_to_usb_dev(hid)->bus->bus_name, hid_to_usb_dev(hid)->devpath, usbhid->ifnum, rc); /* FALLTHROUGH */ case -EHOSTUNREACH: case -ENODEV: case -EINTR: break; } }
/** * Enable fully-functional tablet mode and determine device parameters. * * @hdev: HID device */ static int huion_tablet_enable(struct hid_device *hdev) { int rc; struct usb_device *usb_dev = hid_to_usb_dev(hdev); struct huion_drvdata *drvdata = hid_get_drvdata(hdev); __le16 buf[6]; /* * Read string descriptor containing tablet parameters. The specific * string descriptor and data were discovered by sniffing the Windows * driver traffic. * NOTE: This enables fully-functional tablet mode. */ rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (USB_DT_STRING << 8) + 0x64, 0x0409, buf, sizeof(buf), USB_CTRL_GET_TIMEOUT); if (rc == -EPIPE) hid_warn(hdev, "device parameters not found\n"); else if (rc < 0) hid_warn(hdev, "failed to get device parameters: %d\n", rc); else if (rc != sizeof(buf)) hid_warn(hdev, "invalid device parameters\n"); else { s32 params[HUION_PH_ID_NUM]; s32 resolution; __u8 *p; s32 v; /* Extract device parameters */ params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]); params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]); params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]); resolution = le16_to_cpu(buf[5]); if (resolution == 0) { params[HUION_PH_ID_X_PM] = 0; params[HUION_PH_ID_Y_PM] = 0; } else { params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] * 1000 / resolution; params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] * 1000 / resolution; } /* Allocate fixed report descriptor */ drvdata->rdesc = devm_kmalloc(&hdev->dev, sizeof(huion_tablet_rdesc_template), GFP_KERNEL); if (drvdata->rdesc == NULL) { hid_err(hdev, "failed to allocate fixed rdesc\n"); return -ENOMEM; } drvdata->rsize = sizeof(huion_tablet_rdesc_template); /* Format fixed report descriptor */ memcpy(drvdata->rdesc, huion_tablet_rdesc_template, drvdata->rsize); for (p = drvdata->rdesc; p <= drvdata->rdesc + drvdata->rsize - 4;) { if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D && p[3] < sizeof(params)) { v = params[p[3]]; put_unaligned(cpu_to_le32(v), (s32 *)p); p += 4; } else { p++; } } } return 0; }
static void hid_irq_in(struct urb *urb) { struct hid_device *hid = urb->context; struct usbhid_device *usbhid = hid->driver_data; int status; switch (urb->status) { case 0: /* success */ usbhid_mark_busy(usbhid); usbhid->retry_delay = 0; #if defined(CONFIG_TOUCHSCREEN_NEXIO_USB) if((hid->vendor == NEXIO_USB_TOUCH_VENDOR) && (hid->product == NEXIO_USB_TOUCH_PRODUCT)) { if(nexio_touch_driver_open) { nexio_touch_report_data(urb->transfer_buffer, urb->actual_length); } } else #endif #if defined(CONFIG_TOUCHSCREEN_EGALAX_USB) if((hid->vendor == EGALAX_USB_TOUCH_VENDOR) && (hid->product == EGALAX_USB_TOUCH_PRODUCT)) { if(egalax_touch_driver_open) { egalax_touch_report_data(urb->transfer_buffer, urb->actual_length); } } else #endif { hid_input_report(urb->context, HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, 1); /* * autosuspend refused while keys are pressed * because most keyboards don't wake up when * a key is released */ if (hid_check_keys_pressed(hid)) set_bit(HID_KEYS_PRESSED, &usbhid->iofl); else clear_bit(HID_KEYS_PRESSED, &usbhid->iofl); } break; case -EPIPE: /* stall */ usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); set_bit(HID_CLEAR_HALT, &usbhid->iofl); schedule_work(&usbhid->reset_work); return; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: /* unplug */ clear_bit(HID_IN_RUNNING, &usbhid->iofl); return; case -EILSEQ: /* protocol error or unplug */ case -EPROTO: /* protocol error or unplug */ case -ETIME: /* protocol error or unplug */ case -ETIMEDOUT: /* Should never happen, but... */ usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); hid_io_error(hid); return; default: /* error */ hid_warn(urb->dev, "input irq status %d received\n", urb->status); } status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n", hid_to_usb_dev(hid)->bus->bus_name, hid_to_usb_dev(hid)->devpath, usbhid->ifnum, status); hid_io_error(hid); } } }
/* * Certain Logitech keyboards send in report #3 keys which are far * above the logical maximum described in descriptor. This extends * the original value of 0x28c of logical maximum to 0x104d */ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { struct lg_drv_data *drv_data = hid_get_drvdata(hdev); struct usb_device_descriptor *udesc; __u16 bcdDevice, rev_maj, rev_min; if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && rdesc[84] == 0x8c && rdesc[85] == 0x02) { hid_info(hdev, "fixing up Logitech keyboard report descriptor\n"); rdesc[84] = rdesc[89] = 0x4d; rdesc[85] = rdesc[90] = 0x10; } if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && rdesc[32] == 0x81 && rdesc[33] == 0x06 && rdesc[49] == 0x81 && rdesc[50] == 0x06) { hid_info(hdev, "fixing up rel/abs in Logitech report descriptor\n"); rdesc[33] = rdesc[50] = 0x02; } switch (hdev->product) { /* Several wheels report as this id when operating in emulation mode. */ case USB_DEVICE_ID_LOGITECH_WHEEL: udesc = &(hid_to_usb_dev(hdev)->descriptor); if (!udesc) { hid_err(hdev, "NULL USB device descriptor\n"); break; } bcdDevice = le16_to_cpu(udesc->bcdDevice); rev_maj = bcdDevice >> 8; rev_min = bcdDevice & 0xff; /* Update the report descriptor for only the Driving Force wheel */ if (rev_maj == 1 && rev_min == 2 && *rsize == DF_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Driving Force report descriptor\n"); rdesc = df_rdesc_fixed; *rsize = sizeof(df_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: if (*rsize == MOMO_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Momo Force (Red) report descriptor\n"); rdesc = momo_rdesc_fixed; *rsize = sizeof(momo_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2: if (*rsize == MOMO2_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Momo Racing Force (Black) report descriptor\n"); rdesc = momo2_rdesc_fixed; *rsize = sizeof(momo2_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL: if (*rsize == FV_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Formula Vibration report descriptor\n"); rdesc = fv_rdesc_fixed; *rsize = sizeof(fv_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: if (*rsize == DFP_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Driving Force Pro report descriptor\n"); rdesc = dfp_rdesc_fixed; *rsize = sizeof(dfp_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_WII_WHEEL: if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B && rdesc[47] == 0x05 && rdesc[48] == 0x09) { hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n"); rdesc[41] = 0x05; rdesc[42] = 0x09; rdesc[47] = 0x95; rdesc[48] = 0x0B; } break; } return rdesc; }