static int tpkbd_probe_tp(struct hid_device *hdev) { struct device *dev = &hdev->dev; struct tpkbd_data_pointer *data_pointer; size_t name_sz = strlen(dev_name(dev)) + 16; char *name_mute, *name_micmute; int i; /* Validate required reports. */ for (i = 0; i < 4; i++) { if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1)) return -ENODEV; } if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2)) return -ENODEV; if (sysfs_create_group(&hdev->dev.kobj, &tpkbd_attr_group_pointer)) { hid_warn(hdev, "Could not create sysfs group\n"); } data_pointer = devm_kzalloc(&hdev->dev, sizeof(struct tpkbd_data_pointer), GFP_KERNEL); if (data_pointer == NULL) { hid_err(hdev, "Could not allocate memory for driver data\n"); return -ENOMEM; } // set same default values as windows driver data_pointer->sensitivity = 0xa0; data_pointer->press_speed = 0x38; name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); if (name_mute == NULL || name_micmute == NULL) { hid_err(hdev, "Could not allocate memory for led data\n"); return -ENOMEM; } snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev)); snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev)); hid_set_drvdata(hdev, data_pointer); data_pointer->led_mute.name = name_mute; data_pointer->led_mute.brightness_get = tpkbd_led_brightness_get; data_pointer->led_mute.brightness_set = tpkbd_led_brightness_set; data_pointer->led_mute.dev = dev; led_classdev_register(dev, &data_pointer->led_mute); data_pointer->led_micmute.name = name_micmute; data_pointer->led_micmute.brightness_get = tpkbd_led_brightness_get; data_pointer->led_micmute.brightness_set = tpkbd_led_brightness_set; data_pointer->led_micmute.dev = dev; led_classdev_register(dev, &data_pointer->led_micmute); tpkbd_features_set(hdev); return 0; }
int lg2ff_init(struct hid_device *hid) { struct lg2ff_device *lg2ff; struct hid_report *report; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *dev = hidinput->input; int error; /* Check that the report looks ok */ report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7); if (!report) return -ENODEV; lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); if (!lg2ff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, lg2ff, play_effect); if (error) { kfree(lg2ff); return error; } lg2ff->report = report; report->field[0]->value[0] = 0xf3; report->field[0]->value[1] = 0x00; report->field[0]->value[2] = 0x00; report->field[0]->value[3] = 0x00; report->field[0]->value[4] = 0x00; report->field[0]->value[5] = 0x00; report->field[0]->value[6] = 0x00; hid_hw_request(hid, report, HID_REQ_SET_REPORT); hid_info(hid, "Force feedback for Logitech variant 2 rumble devices by Anssi Hannula <*****@*****.**>\n"); return 0; }
static int zpff_init(struct hid_device *hid) { struct zpff_device *zpff; struct hid_report *report; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *dev = hidinput->input; int i, error; for (i = 0; i < 4; i++) { report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1); if (!report) return -ENODEV; } zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); if (!zpff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, zpff, zpff_play); if (error) { kfree(zpff); return error; } zpff->report = report; zpff->report->field[0]->value[0] = 0x00; zpff->report->field[1]->value[0] = 0x02; zpff->report->field[2]->value[0] = 0x00; zpff->report->field[3]->value[0] = 0x00; usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); dev_info(&hid->dev, "force feedback for Zeroplus based devices by " "Anssi Hannula <*****@*****.**>\n"); 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); /* 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; } if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, REPORT_ID_DJ_SHORT, 0, DJREPORT_SHORT_LENGTH - 1)) { retval = -ENODEV; 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; } /* Allow incoming packets to arrive: */ hid_device_io_start(hdev); 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 lenovo_probe_tpkbd(struct hid_device *hdev) { struct device *dev = &hdev->dev; struct lenovo_drvdata_tpkbd *data_pointer; size_t name_sz = strlen(dev_name(dev)) + 16; char *name_mute, *name_micmute; int i; int ret; /* * Only register extra settings against subdevice where input_mapping * set drvdata to 1, i.e. the trackpoint. */ if (!hid_get_drvdata(hdev)) return 0; hid_set_drvdata(hdev, NULL); /* Validate required reports. */ for (i = 0; i < 4; i++) { if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1)) return -ENODEV; } if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2)) return -ENODEV; ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tpkbd); if (ret) hid_warn(hdev, "Could not create sysfs group: %d\n", ret); data_pointer = devm_kzalloc(&hdev->dev, sizeof(struct lenovo_drvdata_tpkbd), GFP_KERNEL); if (data_pointer == NULL) { hid_err(hdev, "Could not allocate memory for driver data\n"); return -ENOMEM; } // set same default values as windows driver data_pointer->sensitivity = 0xa0; data_pointer->press_speed = 0x38; name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); if (name_mute == NULL || name_micmute == NULL) { hid_err(hdev, "Could not allocate memory for led data\n"); return -ENOMEM; } snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev)); snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev)); hid_set_drvdata(hdev, data_pointer); data_pointer->led_mute.name = name_mute; data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd; data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd; data_pointer->led_mute.dev = dev; led_classdev_register(dev, &data_pointer->led_mute); data_pointer->led_micmute.name = name_micmute; data_pointer->led_micmute.brightness_get = lenovo_led_brightness_get_tpkbd; data_pointer->led_micmute.brightness_set = lenovo_led_brightness_set_tpkbd; data_pointer->led_micmute.dev = dev; led_classdev_register(dev, &data_pointer->led_micmute); lenovo_features_set_tpkbd(hdev); return 0; }
static int buzz_init(struct hid_device *hdev) { struct sony_sc *drv_data; struct buzz_extra *buzz; int n, ret = 0; struct led_classdev *led; size_t name_sz; char *name; drv_data = hid_get_drvdata(hdev); BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER)); /* Validate expected report characteristics. */ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7)) return -ENODEV; buzz = kzalloc(sizeof(*buzz), GFP_KERNEL); if (!buzz) { hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); return -ENOMEM; } drv_data->extra = buzz; /* Clear LEDs as we have no way of reading their initial state. This is * only relevant if the driver is loaded after somebody actively set the * LEDs to on */ buzz_set_leds(hdev, 0x00); name_sz = strlen(dev_name(&hdev->dev)) + strlen("::buzz#") + 1; for (n = 0; n < 4; n++) { led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL); if (!led) { hid_err(hdev, "Couldn't allocate memory for LED %d\n", n); goto error_leds; } name = (void *)(&led[1]); snprintf(name, name_sz, "%s::buzz%d", dev_name(&hdev->dev), n + 1); led->name = name; led->brightness = 0; led->max_brightness = 1; led->brightness_get = buzz_led_get_brightness; led->brightness_set = buzz_led_set_brightness; if (led_classdev_register(&hdev->dev, led)) { hid_err(hdev, "Failed to register LED %d\n", n); kfree(led); goto error_leds; } buzz->leds[n] = led; } return ret; error_leds: for (n = 0; n < 4; n++) { led = buzz->leds[n]; buzz->leds[n] = NULL; if (!led) continue; led_classdev_unregister(led); kfree(led); } kfree(drv_data->extra); drv_data->extra = NULL; return ret; }