static int samsung_actionmouse_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { dbg_hid("samsung wireless actionmouse input mapping event [0x%x], [0x%x], %ld, %ld, [0x%x]\n", usage->hid, usage->hid & HID_USAGE, hi->input->evbit[0], hi->input->absbit[0], usage->hid & HID_USAGE_PAGE); if(((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) && ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)) return 0; switch (usage->hid & HID_USAGE) { case 0x301: samsung_kbd_mouse_map_key_clear(KEY_RECENT); break; default: return 0; } return 1; }
static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { /* Sent by the input layer to handle leds and Force Feedback */ struct hid_device *dj_hiddev = input_get_drvdata(dev); struct dj_device *dj_dev = dj_hiddev->driver_data; struct dj_receiver_dev *djrcv_dev = dev_get_drvdata(dj_hiddev->dev.parent); struct hid_device *dj_rcv_hiddev = djrcv_dev->hdev; struct hid_report_enum *output_report_enum; struct hid_field *field; struct hid_report *report; unsigned char data[8]; int offset; dbg_hid("%s: %s, type:%d | code:%d | value:%d\n", __func__, dev->phys, type, code, value); if (type != EV_LED) return -1; offset = hidinput_find_field(dj_hiddev, type, code, &field); if (offset == -1) { dev_warn(&dev->dev, "event field not found\n"); return -1; } hid_set_field(field, offset, value); hid_output_report(field->report, &data[0]); output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT]; report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT]; hid_set_field(report->field[0], 0, dj_dev->device_index); hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS); hid_set_field(report->field[0], 2, data[1]); usbhid_submit_report(dj_rcv_hiddev, report, USB_DIR_OUT); return 0; }
static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) { struct hid_field *field; if (report->maxfield == HID_MAX_FIELDS) { dbg_hid("too many fields in report\n"); return NULL; } if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + values * sizeof(unsigned), GFP_KERNEL))) return NULL; field->index = report->maxfield++; report->field[field->index] = field; field->usage = (struct hid_usage *)(field + 1); field->value = (unsigned *)(field->usage + usages); field->report = report; return field; }
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 void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, struct dj_report *dj_report) { /* Called in delayed work context */ struct hid_device *djrcv_hdev = djrcv_dev->hdev; struct usb_interface *intf = to_usb_interface(djrcv_hdev->dev.parent); struct usb_device *usbdev = interface_to_usbdev(intf); struct hid_device *dj_hiddev; struct dj_device *dj_dev; /* Device index goes from 1 to 6, we need 3 bytes to store the * semicolon, the index, and a null terminator */ unsigned char tmpstr[3]; if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & SPFUNCTION_DEVICE_LIST_EMPTY) { dbg_hid("%s: device list is empty\n", __func__); return; } <<<<<<< HEAD
static void picolcd_remove(struct hid_device *hdev) { struct picolcd_data *data = hid_get_drvdata(hdev); unsigned long flags; dbg_hid(PICOLCD_NAME " hardware remove...\n"); spin_lock_irqsave(&data->lock, flags); data->status |= PICOLCD_FAILED; spin_unlock_irqrestore(&data->lock, flags); picolcd_exit_devfs(data); device_remove_file(&hdev->dev, &dev_attr_operation_mode); device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); hid_hw_close(hdev); hid_hw_stop(hdev); /* Shortcut potential pending reply that will never arrive */ spin_lock_irqsave(&data->lock, flags); if (data->pending) complete(&data->pending->ready); spin_unlock_irqrestore(&data->lock, flags); /* Cleanup LED */ picolcd_exit_leds(data); /* Clean up the framebuffer */ picolcd_exit_backlight(data); picolcd_exit_lcd(data); picolcd_exit_framebuffer(data); /* Cleanup input */ picolcd_exit_cir(data); picolcd_exit_keys(data); hid_set_drvdata(hdev, NULL); mutex_destroy(&data->mutex); /* Finally, clean up the picolcd data itself */ kfree(data); }
static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct usb_interface *iface = to_usb_interface(hdev->dev.parent); __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber; unsigned int connect_mask = HID_CONNECT_DEFAULT; struct lg_drv_data *drv_data; int ret; /* G29 only work with the 1st interface */ if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) && (iface_num != 0)) { dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num); return -ENODEV; } drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL); if (!drv_data) { hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); return -ENOMEM; } drv_data->quirks = id->driver_data; hid_set_drvdata(hdev, (void *)drv_data); if (drv_data->quirks & LG_NOGET) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_parse(hdev); if (ret) { hid_err(hdev, "parse failed\n"); goto err_free; } if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4)) connect_mask &= ~HID_CONNECT_FF; ret = hid_hw_start(hdev, connect_mask); if (ret) { hid_err(hdev, "hw start failed\n"); goto err_free; } /* Setup wireless link with Logitech Wii wheel */ if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT); if (ret >= 0) { /* insert a little delay of 10 jiffies ~ 40ms */ wait_queue_head_t wait; init_waitqueue_head (&wait); wait_event_interruptible_timeout(wait, 0, msecs_to_jiffies(40)); /* Select random Address */ buf[1] = 0xB2; get_random_bytes(&buf[2], 2); ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT); } } if (drv_data->quirks & LG_FF) ret = lgff_init(hdev); else if (drv_data->quirks & LG_FF2) ret = lg2ff_init(hdev); else if (drv_data->quirks & LG_FF3) ret = lg3ff_init(hdev); else if (drv_data->quirks & LG_FF4) ret = lg4ff_init(hdev); if (ret) goto err_free; return 0; err_free: kfree(drv_data); return ret; }
struct hid_device *hid_parse_report(__u8 *start, unsigned size) { struct hid_device *device; struct hid_parser *parser; struct hid_item item; __u8 *end; unsigned i; static int (*dispatch_type[])(struct hid_parser *parser, struct hid_item *item) = { hid_parser_main, hid_parser_global, hid_parser_local, hid_parser_reserved }; if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL))) return NULL; if (!(device->collection = kzalloc(sizeof(struct hid_collection) * HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) { kfree(device); return NULL; } device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; for (i = 0; i < HID_REPORT_TYPES; i++) INIT_LIST_HEAD(&device->report_enum[i].report_list); if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) { kfree(device->collection); kfree(device); return NULL; } memcpy(device->rdesc, start, size); device->rsize = size; if (!(parser = vmalloc(sizeof(struct hid_parser)))) { kfree(device->rdesc); kfree(device->collection); kfree(device); return NULL; } memset(parser, 0, sizeof(struct hid_parser)); parser->device = device; end = start + size; while ((start = fetch_item(start, end, &item)) != NULL) { if (item.format != HID_ITEM_FORMAT_SHORT) { dbg_hid("unexpected long global item\n"); hid_free_device(device); vfree(parser); return NULL; } if (dispatch_type[item.type](parser, &item)) { dbg_hid("item %u %u %u %u parsing failed\n", item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); hid_free_device(device); vfree(parser); return NULL; } if (start == end) { if (parser->collection_stack_ptr) { dbg_hid("unbalanced collection at end of report description\n"); hid_free_device(device); vfree(parser); return NULL; } if (parser->local.delimiter_depth) { dbg_hid("unbalanced delimiter at end of report description\n"); hid_free_device(device); vfree(parser); return NULL; } vfree(parser); return device; } } dbg_hid("item fetching failed at offset %d\n", (int)(end - start)); hid_free_device(device); vfree(parser); return NULL; }
static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) { dbg_hid("reserved item type, tag 0x%x\n", item->tag); return 0; }
static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) { __u32 data; unsigned n; if (item->size == 0) { dbg_hid("item data expected for local item\n"); return -1; } data = item_udata(item); switch (item->tag) { case HID_LOCAL_ITEM_TAG_DELIMITER: if (data) { /* * We treat items before the first delimiter * as global to all usage sets (branch 0). * In the moment we process only these global * items and the first delimiter set. */ if (parser->local.delimiter_depth != 0) { dbg_hid("nested delimiters\n"); return -1; } parser->local.delimiter_depth++; parser->local.delimiter_branch++; } else { if (parser->local.delimiter_depth < 1) { dbg_hid("bogus close delimiter\n"); return -1; } parser->local.delimiter_depth--; } return 1; case HID_LOCAL_ITEM_TAG_USAGE: if (parser->local.delimiter_branch > 1) { dbg_hid("alternative usage ignored\n"); return 0; } if (item->size <= 2) data = (parser->global.usage_page << 16) + data; return hid_add_usage(parser, data); case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: if (parser->local.delimiter_branch > 1) { dbg_hid("alternative usage ignored\n"); return 0; } if (item->size <= 2) data = (parser->global.usage_page << 16) + data; parser->local.usage_minimum = data; return 0; case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: if (parser->local.delimiter_branch > 1) { dbg_hid("alternative usage ignored\n"); return 0; } if (item->size <= 2) data = (parser->global.usage_page << 16) + data; for (n = parser->local.usage_minimum; n <= data; n++) if (hid_add_usage(parser, n)) { dbg_hid("hid_add_usage failed\n"); return -1; } return 0; default: dbg_hid("unknown local item tag 0x%x\n", item->tag); return 0; } return 0; }
static int picolcd_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct picolcd_data *data; int error = -ENOMEM; dbg_hid(PICOLCD_NAME " hardware probe...\n"); /* * Let's allocate the picolcd data structure, set some reasonable * defaults, and associate it with the device */ data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL); if (data == NULL) { hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n"); error = -ENOMEM; goto err_no_cleanup; } spin_lock_init(&data->lock); mutex_init(&data->mutex); data->hdev = hdev; data->opmode_delay = 5000; if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) data->status |= PICOLCD_BOOTLOADER; hid_set_drvdata(hdev, data); /* Parse the device reports and start it up */ error = hid_parse(hdev); if (error) { hid_err(hdev, "device report parse failed\n"); goto err_cleanup_data; } error = hid_hw_start(hdev, 0); if (error) { hid_err(hdev, "hardware start failed\n"); goto err_cleanup_data; } error = hid_hw_open(hdev); if (error) { hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n"); goto err_cleanup_hid_hw; } error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay); if (error) { hid_err(hdev, "failed to create sysfs attributes\n"); goto err_cleanup_hid_ll; } error = device_create_file(&hdev->dev, &dev_attr_operation_mode); if (error) { hid_err(hdev, "failed to create sysfs attributes\n"); goto err_cleanup_sysfs1; } if (data->status & PICOLCD_BOOTLOADER) error = picolcd_probe_bootloader(hdev, data); else error = picolcd_probe_lcd(hdev, data); if (error) goto err_cleanup_sysfs2; dbg_hid(PICOLCD_NAME " activated and initialized\n"); return 0; err_cleanup_sysfs2: device_remove_file(&hdev->dev, &dev_attr_operation_mode); err_cleanup_sysfs1: device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); err_cleanup_hid_ll: hid_hw_close(hdev); err_cleanup_hid_hw: hid_hw_stop(hdev); err_cleanup_data: kfree(data); err_no_cleanup: hid_set_drvdata(hdev, NULL); return error; }
static int logi_dj_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); struct dj_report *dj_report = (struct dj_report *) data; unsigned long flags; dbg_hid("%s, size:%d\n", __func__, size); /* Here we receive all data coming from iface 2, there are 4 cases: * * 1) Data should continue its normal processing i.e. data does not * come from the DJ collection, in which case we do nothing and * return 0, so hid-core can continue normal processing (will forward * to associated hidraw device) * * 2) Data is from DJ collection, and is intended for this driver i. e. * data contains arrival, departure, etc notifications, in which case * we queue them for delayed processing by the work queue. We return 1 * to hid-core as no further processing is required from it. * * 3) Data is from DJ collection, and informs a connection change, * if the change means rf link loss, then we must send a null report * to the upper layer to discard potentially pressed keys that may be * repeated forever by the input layer. Return 1 to hid-core as no * further processing is required. * * 4) Data is from DJ collection and is an actual input event from * a paired DJ device in which case we forward it to the correct hid * device (via hid_input_report() ) and return 1 so hid-core does not do * anything else with it. */ /* case 1) */ if (data[0] != REPORT_ID_DJ_SHORT) return false; if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { /* * Device index is wrong, bail out. * This driver can ignore safely the receiver notifications, * so ignore those reports too. */ if (dj_report->device_index != DJ_RECEIVER_INDEX) dev_err(&hdev->dev, "%s: invalid device index:%d\n", __func__, dj_report->device_index); return false; } spin_lock_irqsave(&djrcv_dev->lock, flags); switch (dj_report->report_type) { case REPORT_TYPE_NOTIF_DEVICE_PAIRED: case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: logi_dj_recv_queue_notification(djrcv_dev, dj_report); break; case REPORT_TYPE_NOTIF_CONNECTION_STATUS: if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] == STATUS_LINKLOSS) { logi_dj_recv_forward_null_report(djrcv_dev, dj_report); } break; default: logi_dj_recv_forward_report(djrcv_dev, dj_report); } spin_unlock_irqrestore(&djrcv_dev->lock, flags); return true; }
static int logi_dj_ll_start(struct hid_device *hid) { dbg_hid("%s\n", __func__); return 0; }
static void logi_dj_ll_close(struct hid_device *hid) { dbg_hid("%s:%s\n", __func__, hid->phys); }
static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, struct dj_report *dj_report) { /* Called in delayed work context */ struct hid_device *djrcv_hdev = djrcv_dev->hdev; struct usb_interface *intf = to_usb_interface(djrcv_hdev->dev.parent); struct usb_device *usbdev = interface_to_usbdev(intf); struct hid_device *dj_hiddev; struct dj_device *dj_dev; /* Device index goes from 1 to 6, we need 3 bytes to store the * semicolon, the index, and a null terminator */ unsigned char tmpstr[3]; if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & SPFUNCTION_DEVICE_LIST_EMPTY) { dbg_hid("%s: device list is empty\n", __func__); return; } if (djrcv_dev->paired_dj_devices[dj_report->device_index]) { /* The device is already known. No need to reallocate it. */ dbg_hid("%s: device is already known\n", __func__); return; } dj_hiddev = hid_allocate_device(); if (IS_ERR(dj_hiddev)) { dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", __func__); return; } dj_hiddev->ll_driver = &logi_dj_ll_driver; dj_hiddev->hid_output_raw_report = logi_dj_output_hidraw_report; dj_hiddev->dev.parent = &djrcv_hdev->dev; dj_hiddev->bus = BUS_USB; dj_hiddev->vendor = le16_to_cpu(usbdev->descriptor.idVendor); dj_hiddev->product = le16_to_cpu(usbdev->descriptor.idProduct); snprintf(dj_hiddev->name, sizeof(dj_hiddev->name), "Logitech Unifying Device. Wireless PID:%02x%02x", dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB], dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_LSB]); usb_make_path(usbdev, dj_hiddev->phys, sizeof(dj_hiddev->phys)); snprintf(tmpstr, sizeof(tmpstr), ":%d", dj_report->device_index); strlcat(dj_hiddev->phys, tmpstr, sizeof(dj_hiddev->phys)); dj_dev = kzalloc(sizeof(struct dj_device), GFP_KERNEL); if (!dj_dev) { dev_err(&djrcv_hdev->dev, "%s: failed allocating dj_device\n", __func__); goto dj_device_allocate_fail; } dj_dev->reports_supported = le32_to_cpu( dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]); dj_dev->hdev = dj_hiddev; dj_dev->dj_receiver_dev = djrcv_dev; dj_dev->device_index = dj_report->device_index; dj_hiddev->driver_data = dj_dev; djrcv_dev->paired_dj_devices[dj_report->device_index] = dj_dev; if (hid_add_device(dj_hiddev)) { dev_err(&djrcv_hdev->dev, "%s: failed adding dj_device\n", __func__); goto hid_add_device_fail; } return; hid_add_device_fail: djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL; kfree(dj_dev); dj_device_allocate_fail: hid_destroy_device(dj_hiddev); }
static int samsung_kbd_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { if (!(HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE) || HID_UP_KEYBOARD == (usage->hid & HID_USAGE_PAGE))) return 0; dbg_hid("samsung wireless keyboard input mapping event [0x%x]\n", usage->hid & HID_USAGE); if (HID_UP_KEYBOARD == (usage->hid & HID_USAGE_PAGE)) { switch (usage->hid & HID_USAGE) { /*set_bit(EV_REP, hi->input->evbit);*/ /* SS_BLUETOOTH(js80.hong) 2012.03.17 */ /* Only for UK keyboard */ /* key found */ case 0x32: samsung_kbd_mouse_map_key_clear(KEY_KBDILLUMTOGGLE); break; case 0x64: samsung_kbd_mouse_map_key_clear(KEY_BACKSLASH); break; default: return 0; } } if (HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE)) { switch (usage->hid & HID_USAGE) { /* report 2 */ /* MENU */ case 0x040: samsung_kbd_mouse_map_key_clear(KEY_MENU); break; case 0x18a: samsung_kbd_mouse_map_key_clear(KEY_MAIL); break; case 0x196: samsung_kbd_mouse_map_key_clear(KEY_WWW); break; case 0x19e: samsung_kbd_mouse_map_key_clear(KEY_SCREENLOCK); break; case 0x221: samsung_kbd_mouse_map_key_clear(KEY_SEARCH); break; case 0x223: samsung_kbd_mouse_map_key_clear(KEY_HOMEPAGE); break; /* RECENTAPPS */ case 0x301: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY1); break; /* APPLICATION */ case 0x302: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY2); break; /* Voice search */ case 0x305: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY4); break; /* QPANEL on/off */ case 0x306: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY5); break; /* SIP on/off */ case 0x307: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY3); break; /* LANG */ case 0x308: samsung_kbd_mouse_map_key_clear(KEY_LANGUAGE); break; case 0x30a: samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSDOWN); break; case 0x30b: samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSUP); break; default: return 0; } } return 1; }
static int g15_probe(struct hid_device *hdev, const struct hid_device_id *id) { unsigned long irq_flags; int error; struct gcommon_data *gdata; struct g15_data *g15data; int i; int led_num; struct usb_interface *intf; struct usb_device *usbdev; struct list_head *feature_report_list = &hdev->report_enum[HID_FEATURE_REPORT].report_list; struct list_head *output_report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report; char *led_name; dev_dbg(&hdev->dev, "Logitech G15 HID hardware probe..."); /* Get the usb device to send the start report on */ intf = to_usb_interface(hdev->dev.parent); usbdev = interface_to_usbdev(intf); /* * Let's allocate the g15 data structure, set some reasonable * defaults, and associate it with the device */ gdata = kzalloc(sizeof(struct gcommon_data), GFP_KERNEL); if (gdata == NULL) { dev_err(&hdev->dev, "can't allocate space for Logitech G15 device attributes\n"); error = -ENOMEM; goto err_no_cleanup; } g15data = kzalloc(sizeof(struct g15_data), GFP_KERNEL); if (g15data == NULL) { dev_err(&hdev->dev, "can't allocate space for Logitech G15 device attributes\n"); error = -ENOMEM; goto err_cleanup_gdata; } gdata->data = g15data; spin_lock_init(&gdata->lock); init_completion(&g15data->ready); gdata->hdev = hdev; hid_set_drvdata(hdev, gdata); dbg_hid("Preparing to parse " G15_NAME " hid reports\n"); /* Parse the device reports and start it up */ error = hid_parse(hdev); if (error) { dev_err(&hdev->dev, G15_NAME " device report parse failed\n"); error = -EINVAL; goto err_cleanup_g15data; } error = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_HIDINPUT_FORCE); if (error) { dev_err(&hdev->dev, G15_NAME " hardware start failed\n"); error = -EINVAL; goto err_cleanup_g15data; } dbg_hid(G15_NAME " claimed: %d\n", hdev->claimed); error = hdev->ll_driver->open(hdev); if (error) { dev_err(&hdev->dev, G15_NAME " failed to open input interrupt pipe for key and joystick events\n"); error = -EINVAL; goto err_cleanup_g15data; } /* Set up the input device for the key I/O */ gdata->input_dev = input_allocate_device(); if (gdata->input_dev == NULL) { dev_err(&hdev->dev, G15_NAME " error initializing the input device"); error = -ENOMEM; goto err_cleanup_g15data; } input_set_drvdata(gdata->input_dev, gdata); gdata->input_dev->name = G15_NAME; gdata->input_dev->phys = hdev->phys; gdata->input_dev->uniq = hdev->uniq; gdata->input_dev->id.bustype = hdev->bus; gdata->input_dev->id.vendor = hdev->vendor; gdata->input_dev->id.product = hdev->product; gdata->input_dev->id.version = hdev->version; gdata->input_dev->dev.parent = hdev->dev.parent; gdata->input_dev->keycode = gdata->input_data.keycode; gdata->input_dev->keycodemax = G15_KEYMAP_SIZE; gdata->input_dev->keycodesize = sizeof(int); gdata->input_dev->setkeycode = ginput_setkeycode; gdata->input_dev->getkeycode = ginput_getkeycode; input_set_capability(gdata->input_dev, EV_KEY, KEY_UNKNOWN); gdata->input_dev->evbit[0] |= BIT_MASK(EV_REP); gdata->input_data.notify_keymap_switched = g15_notify_keymap_switched; error = ginput_alloc(gdata, G15_KEYS); if (error) { dev_err(&hdev->dev, G15_NAME " error allocating memory for the input device"); goto err_cleanup_input_dev; } g15_initialize_keymap(gdata); error = input_register_device(gdata->input_dev); if (error) { dev_err(&hdev->dev, G15_NAME " error registering the input device"); error = -EINVAL; goto err_cleanup_input_dev_data; } dbg_hid(KERN_INFO G15_NAME " allocated framebuffer\n"); dbg_hid(KERN_INFO G15_NAME " allocated deferred IO structure\n"); if (list_empty(feature_report_list)) { dev_err(&hdev->dev, "no feature report found\n"); error = -ENODEV; goto err_cleanup_input_dev_reg; } dbg_hid(G15_NAME " feature report found\n"); list_for_each_entry(report, feature_report_list, list) { switch (report->id) { case 0x02: /* G15 has only one feature report 0x02 */ g15data->feature_report_4 = g15data->led_report = g15data->start_input_report = g15data->backlight_report = report; break; default: break; } dbg_hid(G15_NAME " Feature report: id=%u type=%u size=%u maxfield=%u report_count=%u\n", report->id, report->type, report->size, report->maxfield, report->field[0]->report_count); } if (list_empty(output_report_list)) { dev_err(&hdev->dev, "no output report found\n"); error = -ENODEV; goto err_cleanup_input_dev_reg; } dbg_hid(G15_NAME " output report found\n"); list_for_each_entry(report, output_report_list, list) { dbg_hid(G15_NAME " output report %d found size=%u maxfield=%u\n", report->id, report->size, report->maxfield); if (report->maxfield > 0) { dbg_hid(G15_NAME " offset=%u size=%u count=%u type=%u\n", report->field[0]->report_offset, report->field[0]->report_size, report->field[0]->report_count, report->field[0]->report_type); } switch (report->id) { case 0x03: g15data->output_report_3 = report; break; } }
static int g19_probe(struct hid_device *hdev, const struct hid_device_id *id) { unsigned long irq_flags; int error; struct g19_data *data; int i; int led_num; struct usb_interface *intf; struct usb_device *usbdev; struct list_head *feature_report_list = &hdev->report_enum[HID_FEATURE_REPORT].report_list; struct hid_report *report; char *led_name; dev_dbg(&hdev->dev, "Logitech G19 HID hardware probe..."); /* Get the usb device to send the start report on */ intf = to_usb_interface(hdev->dev.parent); usbdev = interface_to_usbdev(intf); /* * Let's allocate the g19 data structure, set some reasonable * defaults, and associate it with the device */ data = kzalloc(sizeof(struct g19_data), GFP_KERNEL); if (data == NULL) { dev_err(&hdev->dev, "can't allocate space for Logitech G19 device attributes\n"); error = -ENOMEM; goto err_no_cleanup; } spin_lock_init(&data->lock); init_completion(&data->ready); data->hdev = hdev; data->ep1_urb = usb_alloc_urb(0, GFP_KERNEL); if (data->ep1_urb == NULL) { dev_err(&hdev->dev, G19_NAME ": ERROR: can't alloc ep1 urb stuff\n"); error = -ENOMEM; goto err_cleanup_data; } hid_set_drvdata(hdev, data); dbg_hid("Preparing to parse " G19_NAME " hid reports\n"); /* Parse the device reports and start it up */ error = hid_parse(hdev); if (error) { dev_err(&hdev->dev, G19_NAME " device report parse failed\n"); error = -EINVAL; goto err_cleanup_ep1_urb; } error = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_HIDINPUT_FORCE); if (error) { dev_err(&hdev->dev, G19_NAME " hardware start failed\n"); error = -EINVAL; goto err_cleanup_ep1_urb; } dbg_hid(G19_NAME " claimed: %d\n", hdev->claimed); error = hdev->ll_driver->open(hdev); if (error) { dev_err(&hdev->dev, G19_NAME " failed to open input interrupt pipe for key and joystick events\n"); error = -EINVAL; goto err_cleanup_ep1_urb; } /* Set up the input device for the key I/O */ data->input_dev = input_allocate_device(); if (data->input_dev == NULL) { dev_err(&hdev->dev, G19_NAME " error initializing the input device"); error = -ENOMEM; goto err_cleanup_ep1_urb; } input_set_drvdata(data->input_dev, hdev); data->input_dev->name = G19_NAME; data->input_dev->phys = hdev->phys; data->input_dev->uniq = hdev->uniq; data->input_dev->id.bustype = hdev->bus; data->input_dev->id.vendor = hdev->vendor; data->input_dev->id.product = hdev->product; data->input_dev->id.version = hdev->version; data->input_dev->dev.parent = hdev->dev.parent; data->input_dev->keycode = data->keycode; data->input_dev->keycodemax = G19_KEYMAP_SIZE; data->input_dev->keycodesize = sizeof(int); data->input_dev->setkeycode = g19_input_setkeycode; data->input_dev->getkeycode = g19_input_getkeycode; input_set_capability(data->input_dev, EV_KEY, KEY_UNKNOWN); data->input_dev->evbit[0] |= BIT_MASK(EV_REP); g19_initialize_keymap(data); error = input_register_device(data->input_dev); if (error) { dev_err(&hdev->dev, G19_NAME " error registering the input device"); error = -EINVAL; goto err_cleanup_input_dev; } if (list_empty(feature_report_list)) { dev_err(&hdev->dev, "no feature report found\n"); error = -ENODEV; goto err_cleanup_input_dev_reg; } dbg_hid(G19_NAME " feature report found\n"); list_for_each_entry(report, feature_report_list, list) { switch (report->id) { case 0x04: data->feature_report_4 = report; break; case 0x05: data->led_report = report; break; case 0x06: data->start_input_report = report; break; case 0x07: data->backlight_report = report; break; default: break; } dbg_hid(G19_NAME " Feature report: id=%u type=%u size=%u maxfield=%u report_count=%u\n", report->id, report->type, report->size, report->maxfield, report->field[0]->report_count); } dbg_hid("Found all reports\n"); /* Create the LED structures */ for (i = 0; i < LED_COUNT; i++) { data->led_cdev[i] = kzalloc(sizeof(struct led_classdev), GFP_KERNEL); if (data->led_cdev[i] == NULL) { dev_err(&hdev->dev, G19_NAME " error allocating memory for led %d", i); error = -ENOMEM; goto err_cleanup_led_structs; } /* Set the accessor functions by copying from template*/ *(data->led_cdev[i]) = g19_led_cdevs[i]; /* * Allocate memory for the LED name * * Since led_classdev->name is a const char* we'll use an * intermediate until the name is formatted with sprintf(). */ led_name = kzalloc(sizeof(char)*20, GFP_KERNEL); if (led_name == NULL) { dev_err(&hdev->dev, G19_NAME " error allocating memory for led %d name", i); error = -ENOMEM; goto err_cleanup_led_structs; } switch (i) { case G19_LED_M1: case G19_LED_M2: case G19_LED_M3: sprintf(led_name, "g19_%d:orange:m%d", hdev->minor, i+1); break; case G19_LED_MR: sprintf(led_name, "g19_%d:red:mr", hdev->minor); break; case G19_LED_BL_R: sprintf(led_name, "g19_%d:red:bl", hdev->minor); break; case G19_LED_BL_G: sprintf(led_name, "g19_%d:green:bl", hdev->minor); break; case G19_LED_BL_B: sprintf(led_name, "g19_%d:blue:bl", hdev->minor); break; case G19_LED_BL_SCREEN: sprintf(led_name, "g19_%d:white:screen", hdev->minor); break; } data->led_cdev[i]->name = led_name; } for (i = 0; i < LED_COUNT; i++) { led_num = i; error = led_classdev_register(&hdev->dev, data->led_cdev[i]); if (error < 0) { dev_err(&hdev->dev, G19_NAME " error registering led %d", i); error = -EINVAL; goto err_cleanup_registered_leds; } } data->gfb_data = gfb_probe(hdev, GFB_PANEL_TYPE_320_240_16); if (data->gfb_data == NULL) { dev_err(&hdev->dev, G19_NAME " error registering framebuffer\n"); goto err_cleanup_registered_leds; } dbg_hid("Waiting for G19 to activate\n"); /* Add the sysfs attributes */ error = sysfs_create_group(&(hdev->dev.kobj), &g19_attr_group); if (error) { dev_err(&hdev->dev, G19_NAME " failed to create sysfs group attributes\n"); goto err_cleanup_registered_leds; } /* * Wait here for stage 1 (substages 1-3) to complete */ wait_for_completion_timeout(&data->ready, HZ); /* Protect data->ready_stages before checking whether we're ready to proceed */ spin_lock_irqsave(&data->lock, irq_flags); if (data->ready_stages != G19_READY_STAGE_1) { dev_warn(&hdev->dev, G19_NAME " hasn't completed stage 1 yet, forging ahead with initialization\n"); /* Force the stage */ data->ready_stages = G19_READY_STAGE_1; } init_completion(&data->ready); data->ready_stages |= G19_READY_SUBSTAGE_4; spin_unlock_irqrestore(&data->lock, irq_flags); /* * Send the init report, then follow with the input report to trigger * report 6 and wait for us to get a response. */ g19_feature_report_4_send(hdev, G19_REPORT_4_INIT); usbhid_submit_report(hdev, data->start_input_report, USB_DIR_IN); wait_for_completion_timeout(&data->ready, HZ); /* Protect data->ready_stages before checking whether we're ready to proceed */ spin_lock_irqsave(&data->lock, irq_flags); if (data->ready_stages != G19_READY_STAGE_2) { dev_warn(&hdev->dev, G19_NAME " hasn't completed stage 2 yet, forging ahead with initialization\n"); /* Force the stage */ data->ready_stages = G19_READY_STAGE_2; } init_completion(&data->ready); data->ready_stages |= G19_READY_SUBSTAGE_6; spin_unlock_irqrestore(&data->lock, irq_flags); /* * Clear the LEDs */ g19_led_send(hdev); data->rgb[0] = G19_DEFAULT_RED; data->rgb[1] = G19_DEFAULT_GREEN; data->rgb[2] = G19_DEFAULT_BLUE; g19_rgb_send(hdev); data->screen_bl = G19_DEFAULT_BRIGHTNESS; g19_screen_bl_send(hdev); /* * Send the finalize report, then follow with the input report to trigger * report 6 and wait for us to get a response. */ g19_feature_report_4_send(hdev, G19_REPORT_4_FINALIZE); usbhid_submit_report(hdev, data->start_input_report, USB_DIR_IN); usbhid_submit_report(hdev, data->start_input_report, USB_DIR_IN); wait_for_completion_timeout(&data->ready, HZ); /* Protect data->ready_stages before checking whether we're ready to proceed */ spin_lock_irqsave(&data->lock, irq_flags); if (data->ready_stages != G19_READY_STAGE_3) { dev_warn(&hdev->dev, G19_NAME " hasn't completed stage 3 yet, forging ahead with initialization\n"); /* Force the stage */ data->ready_stages = G19_READY_STAGE_3; } else { dbg_hid(G19_NAME " stage 3 complete\n"); } spin_unlock_irqrestore(&data->lock, irq_flags); g19_set_keymap_switching(hdev, 1); g19_ep1_read(hdev); dbg_hid("G19 activated and initialized\n"); /* Everything went well */ return 0; err_cleanup_registered_leds: for (i = 0; i < led_num; i++) led_classdev_unregister(data->led_cdev[i]); err_cleanup_led_structs: for (i = 0; i < LED_COUNT; i++) { if (data->led_cdev[i] != NULL) { if (data->led_cdev[i]->name != NULL) kfree(data->led_cdev[i]->name); kfree(data->led_cdev[i]); } } err_cleanup_input_dev_reg: input_unregister_device(data->input_dev); err_cleanup_input_dev: input_free_device(data->input_dev); err_cleanup_ep1_urb: usb_free_urb(data->ep1_urb); err_cleanup_data: /* Make sure we clean up the allocated data structure */ kfree(data); err_no_cleanup: hid_set_drvdata(hdev, NULL); return error; }
static int read_feature_reports(struct gcore_data *gdata) { struct hid_device *hdev = gdata->hdev; struct g510_data *g510data = gdata->data; struct list_head *feature_report_list = &hdev->report_enum[HID_FEATURE_REPORT].report_list; struct list_head *output_report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report; if (list_empty(feature_report_list)) { dev_err(&hdev->dev, "no feature report found\n"); return -ENODEV; } dbg_hid(G510_NAME " feature report found\n"); list_for_each_entry(report, feature_report_list, list) { switch (report->id) { case 0x04: g510data->feature_report_4 = report; break; case 0x02: g510data->led_report = report; break; case 0x06: g510data->start_input_report = report; break; case 0x05: g510data->backlight_report = report; break; default: break; } dbg_hid("%s Feature report: id=%u type=%u size=%u maxfield=%u report_count=%u\n", gdata->name, report->id, report->type, report->size, report->maxfield, report->field[0]->report_count); } if (list_empty(output_report_list)) { dev_err(&hdev->dev, "no output report found\n"); return -ENODEV; } dbg_hid("%s output report found\n", gdata->name); list_for_each_entry(report, output_report_list, list) { dbg_hid("%s output report %d found size=%u maxfield=%u\n", gdata->name, report->id, report->size, report->maxfield); if (report->maxfield > 0) { dbg_hid("%s offset=%u size=%u count=%u type=%u\n", gdata->name, report->field[0]->report_offset, report->field[0]->report_size, report->field[0]->report_count, report->field[0]->report_type); } switch (report->id) { case 0x03: g510data->output_report_3 = report; break; } }
static int g19_probe(struct hid_device *hdev, const struct hid_device_id *id) { int error; struct gcore_data *gdata; struct g19_data *g19data; dev_dbg(&hdev->dev, "Logitech G19 HID hardware probe..."); gdata = gcore_alloc_data(G19_NAME, hdev); if (gdata == NULL) { dev_err(&hdev->dev, G19_NAME " can't allocate space for device attributes\n"); error = -ENOMEM; goto err_no_cleanup; } g19data = kzalloc(sizeof(struct g19_data), GFP_KERNEL); if (g19data == NULL) { error = -ENOMEM; goto err_cleanup_gdata; } gdata->data = g19data; init_completion(&g19data->ready); g19data->ep1_urb = usb_alloc_urb(0, GFP_KERNEL); if (g19data->ep1_urb == NULL) { dev_err(&hdev->dev, "%s: ERROR: can't alloc ep1 urb stuff\n", gdata->name); error = -ENOMEM; goto err_cleanup_g19data; } error = gcore_hid_open(gdata); if (error) { dev_err(&hdev->dev, "%s error opening hid device\n", gdata->name); goto err_cleanup_ep1_urb; } error = gcore_input_probe(gdata, g19_default_keymap, ARRAY_SIZE(g19_default_keymap)); if (error) { dev_err(&hdev->dev, "%s error registering input device\n", gdata->name); goto err_cleanup_hid; } error = read_feature_reports(gdata); if (error) { dev_err(&hdev->dev, "%s error reading feature reports\n", gdata->name); goto err_cleanup_input; } error = gcore_leds_probe(gdata, g19_led_cdevs, ARRAY_SIZE(g19_led_cdevs)); if (error) { dev_err(&hdev->dev, "%s error registering leds\n", gdata->name); goto err_cleanup_input; } gdata->gfb_data = gfb_probe(hdev, GFB_PANEL_TYPE_320_240_16); if (gdata->gfb_data == NULL) { dev_err(&hdev->dev, "%s error registering framebuffer\n", gdata->name); goto err_cleanup_leds; } error = sysfs_create_group(&(hdev->dev.kobj), &g19_attr_group); if (error) { dev_err(&hdev->dev, "%s failed to create sysfs group attributes\n", gdata->name); goto err_cleanup_gfb; } wait_ready(gdata); /* * Clear the LEDs */ g19data->backlight_rgb[0] = G19_DEFAULT_RED; g19data->backlight_rgb[1] = G19_DEFAULT_GREEN; g19data->backlight_rgb[2] = G19_DEFAULT_BLUE; g19data->screen_bl = G19_DEFAULT_BRIGHTNESS; g19_led_bl_send(hdev); g19_led_mbtns_send(hdev); g19_led_screen_bl_send(hdev); send_finalize_report(gdata); error = g19_ep1_read(hdev); if (error) { dev_err(&hdev->dev, "%s failed to read ep1\n", gdata->name); goto err_cleanup_sysfs; } dbg_hid("G19 activated and initialized\n"); /* Everything went well */ return 0; err_cleanup_sysfs: sysfs_remove_group(&(hdev->dev.kobj), &g19_attr_group); err_cleanup_gfb: gfb_remove(gdata->gfb_data); err_cleanup_leds: gcore_leds_remove(gdata); err_cleanup_input: gcore_input_remove(gdata); err_cleanup_hid: gcore_hid_close(gdata); err_cleanup_ep1_urb: usb_free_urb(g19data->ep1_urb); err_cleanup_g19data: kfree(g19data); err_cleanup_gdata: gcore_free_data(gdata); err_no_cleanup: hid_set_drvdata(hdev, NULL); return error; }
static int zc_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { int i; struct zc_device *zc = hid_get_drvdata(hdev); zc->input_ep81 = hi->input; if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) return 0; dbg_hid("zynacron input mapping event [0x%x]\n", usage->hid & HID_USAGE); switch (usage->hid & HID_USAGE) { /* report 2 */ case 0x10: zc_map_key_clear(KEY_MODE); break; case 0x30: zc_map_key_clear(KEY_SCREEN); break; case 0x70: zc_map_key_clear(KEY_INFO); break; /* report 3 */ case 0x04: zc_map_key_clear(KEY_RADIO); break; /* report 4 */ case 0x0d: zc_map_key_clear(KEY_PVR); break; case 0x25: zc_map_key_clear(KEY_TV); break; case 0x47: zc_map_key_clear(KEY_AUDIO); break; case 0x49: zc_map_key_clear(KEY_AUX); break; case 0x4a: zc_map_key_clear(KEY_VIDEO); break; case 0x48: zc_map_key_clear(KEY_DVD); break; case 0x24: zc_map_key_clear(KEY_MENU); break; case 0x32: zc_map_key_clear(KEY_TEXT); break; default: return 0; } for (i = 0; i < 4; i++) zc->last_key[i] = 0; return 1; }
static int nvidia_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { unsigned id; struct nvidia_tp_loc *loc = (struct nvidia_tp_loc *)hid_get_drvdata(hdev); u8 action; u16 x, y; int press = 0; int release = 0; signed short relx, rely; signed short relx_raw, rely_raw; if (!report) return 1; id = report->id; if (!loc) return 1; /* If not valid touch events, let generic driver to handle this */ if (id != TOUCH_REPORT_ID) return 0; /* If driver is in disabled mode, * don't report anything to generic * driver */ if (loc->mode == DISABLED_MODE) return 1; action = (data[1] & TOUCH_ACTION_MASK) >> TOUCH_ACTION_SHFT; x = data[2]; y = data[4]; if (!loc->action && action) press = 1; else if (loc->action && !action) release = 1; else if (!loc->action && !action) return 1;/* Double release, don't do anything */ relx_raw = x - loc->x; rely_raw = y - loc->y; relx = scale_rel(relx_raw, loc->speed, XSCALE); rely = scale_rel(rely_raw, (loc->speed), YSCALE); loc->action = action; dbg_hid("%u %u %u rel %d %d\n", action, x, y, (s8)relx, (s8)rely); loc->x = x; loc->y = y; if (!press) { /* * Not a press event, we * need to report it to input subsystem * * If driver is in absolute mode, report * raw absolute data to generic driver * * If driver is in gesture mode, report * raw relative data to generic driver */ if (loc->mode == ABSOLUTE_MODE) { if (loc->tp_size == 8) { data[2] = x & 0xff; data[3] = y & 0xff; } /* otherwise we don't need to do anything */ return 0; } else if (loc->mode == GESTURE_MODE) { if (loc->tp_size == 8) { data[2] = relx_raw & 0xff; data[3] = rely_raw & 0xff; } else { data[2] = relx_raw & 0xff; data[3] = relx_raw >> 8; data[4] = rely_raw & 0xff; data[5] = rely_raw >> 8; } if (release) loc->release = 1; else loc->release = 0; return 0; } else { if (loc->tp_size == 8) { data[2] = relx & 0xff; data[3] = rely & 0xff; } else { data[2] = relx & 0xff; data[3] = relx >> 8; data[4] = rely & 0xff; data[5] = rely >> 8; } return 0; } } else {
static int logi_dj_ll_open(struct hid_device *hid) { dbg_hid("%s:%s\n", __func__, hid->phys); return 0; }
static void delayedwork_callback(struct work_struct *work) { struct dj_receiver_dev *djrcv_dev = container_of(work, struct dj_receiver_dev, work); struct dj_report dj_report; unsigned long flags; int count; int retval; dbg_hid("%s\n", __func__); spin_lock_irqsave(&djrcv_dev->lock, flags); count = kfifo_out(&djrcv_dev->notif_fifo, &dj_report, sizeof(struct dj_report)); if (count != sizeof(struct dj_report)) { dev_err(&djrcv_dev->hdev->dev, "%s: workitem triggered without " "notifications available\n", __func__); spin_unlock_irqrestore(&djrcv_dev->lock, flags); return; } if (!kfifo_is_empty(&djrcv_dev->notif_fifo)) { if (schedule_work(&djrcv_dev->work) == 0) { dbg_hid("%s: did not schedule the work item, was " "already queued\n", __func__); } } spin_unlock_irqrestore(&djrcv_dev->lock, flags); switch (dj_report.report_type) { case REPORT_TYPE_NOTIF_DEVICE_PAIRED: logi_dj_recv_add_djhid_device(djrcv_dev, &dj_report); break; case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); break; default: /* A normal report (i. e. not belonging to a pair/unpair notification) * arriving here, means that the report arrived but we did not have a * paired dj_device associated to the report's device_index, this * means that the original "device paired" notification corresponding * to this dj_device never arrived to this driver. The reason is that * hid-core discards all packets coming from a device while probe() is * executing. */ if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) { /* ok, we don't know the device, just re-ask the * receiver for the list of connected devices. */ retval = logi_dj_recv_query_paired_devices(djrcv_dev); if (!retval) { /* everything went fine, so just leave */ break; } dev_err(&djrcv_dev->hdev->dev, "%s:logi_dj_recv_query_paired_devices " "error:%d\n", __func__, retval); } dbg_hid("%s: unexpected report type\n", __func__); } }
static int logi_dj_ll_parse(struct hid_device *hid) { struct dj_device *djdev = hid->driver_data; int retval; dbg_hid("%s\n", __func__); djdev->hdev->version = 0x0111; djdev->hdev->country = 0x00; if (djdev->reports_supported & STD_KEYBOARD) { dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n", __func__, djdev->reports_supported); retval = hid_parse_report(hid, (u8 *) kbd_descriptor, sizeof(kbd_descriptor)); if (retval) { dbg_hid("%s: sending a kbd descriptor, hid_parse failed" " error: %d\n", __func__, retval); return retval; } } if (djdev->reports_supported & STD_MOUSE) { dbg_hid("%s: sending a mouse descriptor, reports_supported: " "%x\n", __func__, djdev->reports_supported); retval = hid_parse_report(hid, (u8 *) mse_descriptor, sizeof(mse_descriptor)); if (retval) { dbg_hid("%s: sending a mouse descriptor, hid_parse " "failed error: %d\n", __func__, retval); return retval; } } if (djdev->reports_supported & MULTIMEDIA) { dbg_hid("%s: sending a multimedia report descriptor: %x\n", __func__, djdev->reports_supported); retval = hid_parse_report(hid, (u8 *) consumer_descriptor, sizeof(consumer_descriptor)); if (retval) { dbg_hid("%s: sending a consumer_descriptor, hid_parse " "failed error: %d\n", __func__, retval); return retval; } } if (djdev->reports_supported & POWER_KEYS) { dbg_hid("%s: sending a power keys report descriptor: %x\n", __func__, djdev->reports_supported); retval = hid_parse_report(hid, (u8 *) syscontrol_descriptor, sizeof(syscontrol_descriptor)); if (retval) { dbg_hid("%s: sending a syscontrol_descriptor, " "hid_parse failed error: %d\n", __func__, retval); return retval; } } if (djdev->reports_supported & MEDIA_CENTER) { dbg_hid("%s: sending a media center report descriptor: %x\n", __func__, djdev->reports_supported); retval = hid_parse_report(hid, (u8 *) media_descriptor, sizeof(media_descriptor)); if (retval) { dbg_hid("%s: sending a media_descriptor, hid_parse " "failed error: %d\n", __func__, retval); return retval; } } if (djdev->reports_supported & KBD_LEDS) { dbg_hid("%s: need to send kbd leds report descriptor: %x\n", __func__, djdev->reports_supported); } return 0; }
static int logi_dj_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct dj_receiver_dev *djrcv_dev; int retval; if (is_dj_device((struct dj_device *)hdev->driver_data)) return -ENODEV; dbg_hid("%s called for ifnum %d\n", __func__, intf->cur_altsetting->desc.bInterfaceNumber); if (intf->cur_altsetting->desc.bInterfaceNumber != LOGITECH_DJ_INTERFACE_NUMBER) { dbg_hid("%s: ignoring ifnum %d\n", __func__, intf->cur_altsetting->desc.bInterfaceNumber); return -ENODEV; } djrcv_dev = kzalloc(sizeof(struct dj_receiver_dev), GFP_KERNEL); if (!djrcv_dev) { dev_err(&hdev->dev, "%s:failed allocating dj_receiver_dev\n", __func__); return -ENOMEM; } djrcv_dev->hdev = hdev; INIT_WORK(&djrcv_dev->work, delayedwork_callback); spin_lock_init(&djrcv_dev->lock); if (kfifo_alloc(&djrcv_dev->notif_fifo, DJ_MAX_NUMBER_NOTIFICATIONS * sizeof(struct dj_report), GFP_KERNEL)) { dev_err(&hdev->dev, "%s:failed allocating notif_fifo\n", __func__); kfree(djrcv_dev); return -ENOMEM; } hid_set_drvdata(hdev, djrcv_dev); retval = hid_parse(hdev); if (retval) { dev_err(&hdev->dev, "%s:parse of interface 2 failed\n", __func__); goto hid_parse_fail; } retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (retval) { dev_err(&hdev->dev, "%s:hid_hw_start returned error\n", __func__); goto hid_hw_start_fail; } retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); if (retval < 0) { dev_err(&hdev->dev, "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n", __func__, retval); goto switch_to_dj_mode_fail; } retval = hdev->ll_driver->open(hdev); if (retval < 0) { dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned " "error:%d\n", __func__, retval); goto llopen_failed; } retval = logi_dj_recv_query_paired_devices(djrcv_dev); if (retval < 0) { dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices " "error:%d\n", __func__, retval); goto logi_dj_recv_query_paired_devices_failed; } return retval; logi_dj_recv_query_paired_devices_failed: hdev->ll_driver->close(hdev); llopen_failed: switch_to_dj_mode_fail: hid_hw_stop(hdev); hid_hw_start_fail: hid_parse_fail: kfifo_free(&djrcv_dev->notif_fifo); kfree(djrcv_dev); hid_set_drvdata(hdev, NULL); return retval; }
static void logi_dj_ll_stop(struct hid_device *hid) { dbg_hid("%s\n", __func__); }
static int samsung_universal_kbd_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { if (!(HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE) || HID_UP_KEYBOARD == (usage->hid & HID_USAGE_PAGE))) return 0; dbg_hid("samsung wireless keyboard input mapping event [0x%x]\n", usage->hid & HID_USAGE); if (HID_UP_KEYBOARD == (usage->hid & HID_USAGE_PAGE)) { switch (usage->hid & HID_USAGE) { set_bit(EV_REP, hi->input->evbit); /* Only for UK keyboard */ /* key found */ case 0x32: samsung_kbd_mouse_map_key_clear(KEY_BACKSLASH); break; case 0x64: samsung_kbd_mouse_map_key_clear(KEY_102ND); break; /* Only for BR keyboard */ case 0x87: samsung_kbd_mouse_map_key_clear(KEY_RO); break; default: return 0; } } if (HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE)) { switch (usage->hid & HID_USAGE) { /* report 2 */ /* MENU */ case 0x040: samsung_kbd_mouse_map_key_clear(KEY_MENU); break; case 0x18a: samsung_kbd_mouse_map_key_clear(KEY_MAIL); break; case 0x196: samsung_kbd_mouse_map_key_clear(KEY_WWW); break; case 0x19e: samsung_kbd_mouse_map_key_clear(KEY_SCREENLOCK); break; case 0x221: samsung_kbd_mouse_map_key_clear(KEY_SEARCH); break; case 0x223: samsung_kbd_mouse_map_key_clear(KEY_HOMEPAGE); break; /* RECENTAPPS */ case 0x301: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY1); break; /* APPLICATION */ case 0x302: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY2); break; /* Voice search */ case 0x305: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY4); break; /* QPANEL on/off */ case 0x306: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY5); break; /* SIP on/off */ case 0x307: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY3); break; /* LANG */ case 0x308: samsung_kbd_mouse_map_key_clear(KEY_LANGUAGE); break; case 0x30a: samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSDOWN); break; case 0x070: samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSDOWN); break; case 0x30b: samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSUP); break; case 0x06f: samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSUP); break; /* S-Finder */ case 0x304: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY7); break; /* Screen Capture */ case 0x303: samsung_kbd_mouse_map_key_clear(KEY_SYSRQ); break; /* Multi Window */ case 0x309: samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY9); break; /* TouchPad ON for TabS2*/ case 0x310: samsung_kbd_mouse_map_key_clear(KEY_TOUCHPAD_ON); break; /* TouchPad OFF for TabS2*/ case 0x311: samsung_kbd_mouse_map_key_clear(KEY_TOUCHPAD_OFF); break; default: return 0; } } return 1; }
static int logi_dj_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct dj_receiver_dev *djrcv_dev; int retval; if (is_dj_device((struct dj_device *)hdev->driver_data)) return -ENODEV; dbg_hid("%s called for ifnum %d\n", __func__, intf->cur_altsetting->desc.bInterfaceNumber); /* Ignore interfaces 0 and 1, they will not carry any data, dont create * any hid_device for them */ if (intf->cur_altsetting->desc.bInterfaceNumber != LOGITECH_DJ_INTERFACE_NUMBER) { dbg_hid("%s: ignoring ifnum %d\n", __func__, intf->cur_altsetting->desc.bInterfaceNumber); return -ENODEV; } /* Treat interface 2 */ djrcv_dev = kzalloc(sizeof(struct dj_receiver_dev), GFP_KERNEL); if (!djrcv_dev) { dev_err(&hdev->dev, "%s:failed allocating dj_receiver_dev\n", __func__); return -ENOMEM; } djrcv_dev->hdev = hdev; INIT_WORK(&djrcv_dev->work, delayedwork_callback); spin_lock_init(&djrcv_dev->lock); if (kfifo_alloc(&djrcv_dev->notif_fifo, DJ_MAX_NUMBER_NOTIFICATIONS * sizeof(struct dj_report), GFP_KERNEL)) { dev_err(&hdev->dev, "%s:failed allocating notif_fifo\n", __func__); kfree(djrcv_dev); return -ENOMEM; } hid_set_drvdata(hdev, djrcv_dev); /* Call to usbhid to fetch the HID descriptors of interface 2 and * subsequently call to the hid/hid-core to parse the fetched * descriptors, this will in turn create the hidraw and hiddev nodes * for interface 2 of the receiver */ retval = hid_parse(hdev); if (retval) { dev_err(&hdev->dev, "%s:parse of interface 2 failed\n", __func__); goto hid_parse_fail; } /* Starts the usb device and connects to upper interfaces hiddev and * hidraw */ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (retval) { dev_err(&hdev->dev, "%s:hid_hw_start returned error\n", __func__); goto hid_hw_start_fail; } retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); if (retval < 0) { dev_err(&hdev->dev, "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n", __func__, retval); goto switch_to_dj_mode_fail; } /* This is enabling the polling urb on the IN endpoint */ retval = hdev->ll_driver->open(hdev); if (retval < 0) { dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned " "error:%d\n", __func__, retval); goto llopen_failed; } retval = logi_dj_recv_query_paired_devices(djrcv_dev); if (retval < 0) { dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices " "error:%d\n", __func__, retval); goto logi_dj_recv_query_paired_devices_failed; } return retval; logi_dj_recv_query_paired_devices_failed: hdev->ll_driver->close(hdev); llopen_failed: switch_to_dj_mode_fail: hid_hw_stop(hdev); hid_hw_start_fail: hid_parse_fail: kfifo_free(&djrcv_dev->notif_fifo); kfree(djrcv_dev); hid_set_drvdata(hdev, NULL); return retval; }
static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) { switch (item->tag) { case HID_GLOBAL_ITEM_TAG_PUSH: if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { dbg_hid("global enviroment stack overflow\n"); return -1; } memcpy(parser->global_stack + parser->global_stack_ptr++, &parser->global, sizeof(struct hid_global)); return 0; case HID_GLOBAL_ITEM_TAG_POP: if (!parser->global_stack_ptr) { dbg_hid("global enviroment stack underflow\n"); return -1; } memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr, sizeof(struct hid_global)); return 0; case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: parser->global.usage_page = item_udata(item); return 0; case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: parser->global.logical_minimum = item_sdata(item); return 0; case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: if (parser->global.logical_minimum < 0) parser->global.logical_maximum = item_sdata(item); else parser->global.logical_maximum = item_udata(item); return 0; case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: parser->global.physical_minimum = item_sdata(item); return 0; case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: if (parser->global.physical_minimum < 0) parser->global.physical_maximum = item_sdata(item); else parser->global.physical_maximum = item_udata(item); return 0; case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: parser->global.unit_exponent = item_sdata(item); return 0; case HID_GLOBAL_ITEM_TAG_UNIT: parser->global.unit = item_udata(item); return 0; case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: if ((parser->global.report_size = item_udata(item)) > 32) { dbg_hid("invalid report_size %d\n", parser->global.report_size); return -1; } return 0; case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { dbg_hid("invalid report_count %d\n", parser->global.report_count); return -1; } return 0; case HID_GLOBAL_ITEM_TAG_REPORT_ID: if ((parser->global.report_id = item_udata(item)) == 0) { dbg_hid("report_id 0 is invalid\n"); return -1; } return 0; default: dbg_hid("unknown global tag 0x%x\n", item->tag); return -1; } }