static int valve_sc_send_request(struct valve_sc_device *sc, u8 report_id, const u8 *params, int params_size, u8 *answer, int *answer_size) { int ret; struct hid_device *hdev = sc->hdev; u8 report[65]; if (params_size > 62) return -EINVAL; report[0] = 0; report[1] = report_id; report[2] = params_size; memcpy(&report[3], params, params_size); ret = hid_hw_raw_request(hdev, 0, report, sizeof(report), HID_FEATURE_REPORT, HID_REQ_SET_REPORT); if (ret < 0) { hid_warn(hdev, "Error sending feature: %d\n", -ret); return ret; } if (ret != sizeof (report)) { hid_warn(hdev, "Sent incomplete feature.\n"); return -EIO; } if (!answer) return 0; msleep(50); ret = hid_hw_raw_request(hdev, 0, report, sizeof(report), HID_FEATURE_REPORT, HID_REQ_GET_REPORT); if (ret < 0) { hid_warn(hdev, "Error receiving feature: %d\n", -ret); return ret; } if (ret != sizeof (report)) { hid_warn(hdev, "Received incomplete feature.\n"); return -EIO; } if (report[1] != report_id) { hid_warn(hdev, "Invalid feature id.\n"); return -EIO; } *answer_size = report[2]; memcpy(answer, &report[3], *answer_size); return 0; }
/* The first byte is expected to be a report number. * This function is to be called with the minors_lock mutex held */ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type) { unsigned int minor = iminor(file->f_path.dentry->d_inode); struct hid_device *dev; __u8 *buf; int ret = 0; if (!hidraw_table[minor]) { ret = -ENODEV; goto out; } dev = hidraw_table[minor]->hid; if (!dev->hid_output_raw_report) { ret = -ENODEV; goto out; } if (count > HID_MAX_BUFFER_SIZE) { hid_warn(dev, "pid %d passed too large report\n", task_pid_nr(current)); ret = -EINVAL; goto out; } if (count < 2) { hid_warn(dev, "pid %d passed too short report\n", task_pid_nr(current)); ret = -EINVAL; goto out; } buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); if (!buf) { ret = -ENOMEM; goto out; } if (copy_from_user(buf, buffer, count)) { ret = -EFAULT; goto out_free; } ret = dev->hid_output_raw_report(dev, buf, count, report_type); out_free: kfree(buf); out: return ret; }
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; }
static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id) { int error; dev_dbg(&hdev->dev, "ACRUX HID hardware probe...\n"); error = hid_parse(hdev); if (error) { hid_err(hdev, "parse failed\n"); return error; } error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (error) { hid_err(hdev, "hw start failed\n"); return error; } error = axff_init(hdev); if (error) { /* * Do not fail device initialization completely as device * may still be partially operable, just warn. */ hid_warn(hdev, "Failed to enable force feedback support, error: %d\n", error); } return 0; }
static ssize_t valve_sc_store_orientation(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; struct valve_sc_device *sc = dev_get_drvdata(dev); struct hid_device *hdev = to_hid_device(dev); u8 params[3]; if (strncmp(buf, "on", 2) == 0) sc->orientation = SC_SETTINGS_ORIENTATION_ACCEL | SC_SETTINGS_ORIENTATION_GYRO; else if (strncmp(buf, "off", 3) == 0) sc->orientation = 0; else return -EINVAL; if (sc->connected) { params[0] = SC_SETTINGS_ORIENTATION; params[1] = sc->orientation; params[2] = 0; ret = valve_sc_send_request(sc, SC_FEATURE_SETTINGS, params, sizeof(params), NULL, NULL); if (ret < 0) hid_warn(hdev, "Error while setting automouse: %d\n", -ret); } return count; }
static ssize_t valve_sc_store_autobuttons(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; struct valve_sc_device *sc = dev_get_drvdata(dev); struct hid_device *hdev = to_hid_device(dev); if (strncmp(buf, "on", 2) == 0) sc->autobuttons = true; else if (strncmp(buf, "off", 3) == 0) sc->autobuttons = false; else return -EINVAL; if (sc->connected) { u8 feature; if (sc->autobuttons) feature = SC_FEATURE_ENABLE_AUTO_BUTTONS; else feature = SC_FEATURE_DISABLE_AUTO_BUTTONS; ret = valve_sc_send_request(sc, feature, NULL, 0, NULL, NULL); if (ret < 0) hid_warn(hdev, "Error while setting autobuttons: %d\n", -ret); } return count; }
static ssize_t valve_sc_store_automouse(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; struct valve_sc_device *sc = dev_get_drvdata(dev); struct hid_device *hdev = to_hid_device(dev); u8 params[3]; if (strncmp(buf, "on", 2) == 0) sc->automouse = true; else if (strncmp(buf, "off", 3) == 0) sc->automouse = false; else return -EINVAL; if (sc->connected) { params[0] = SC_SETTINGS_AUTOMOUSE; if (sc->automouse) params[1] = SC_SETTINGS_AUTOMOUSE_ON; else params[1] = SC_SETTINGS_AUTOMOUSE_OFF; params[2] = 0; ret = valve_sc_send_request(sc, SC_FEATURE_SETTINGS, params, sizeof(params), NULL, NULL); if (ret < 0) hid_warn(hdev, "Error while setting automouse: %d\n", -ret); } return count; }
static int valve_sc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *raw_data, int size) { struct valve_sc_device *sc = hid_get_drvdata (hdev); struct input_dev *input = sc->input; if (sc->parse_raw_report && size == 64) { switch (raw_data[SC_OFFSET_TYPE]) { case 0x01: /* Input events */ if (raw_data[SC_OFFSET_LENGTH] != 60) hid_warn(hdev, "Wrong input event length.\n"); if (input) valve_sc_parse_input_events(sc, raw_data); break; case 0x03: /* Connection events */ if (raw_data[SC_OFFSET_LENGTH] != 1) hid_warn(hdev, "Wrong connection event length.\n"); switch (raw_data[4]) { case 0x01: /* Disconnected device */ hid_dbg(hdev, "Disconnected event\n"); if (sc->connected) { sc->connected = false; schedule_work(&sc->disconnect_work); } break; case 0x02: /* Connected device */ hid_dbg(hdev, "Connected event\n"); if (!sc->connected) { sc->connected = true; schedule_work(&sc->connect_work); } break; case 0x03: /* Paired device*/ default: break; } break; default: break; } } 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; 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); } } }
static int lenovo_probe_cptkbd(struct hid_device *hdev) { int ret; struct lenovo_drvdata_cptkbd *cptkbd_data; /* All the custom action happens on the USBMOUSE device for USB */ if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD && hdev->type != HID_TYPE_USBMOUSE) { hid_dbg(hdev, "Ignoring keyboard half of device\n"); return 0; } cptkbd_data = devm_kzalloc(&hdev->dev, sizeof(*cptkbd_data), GFP_KERNEL); if (cptkbd_data == NULL) { hid_err(hdev, "can't alloc keyboard descriptor\n"); return -ENOMEM; } hid_set_drvdata(hdev, cptkbd_data); /* * Tell the keyboard a driver understands it, and turn F7, F9, F11 into * regular keys */ ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03); if (ret) hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret); /* Switch middle button to native mode */ ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01); if (ret) hid_warn(hdev, "Failed to switch middle button: %d\n", ret); /* Set keyboard settings to known state */ cptkbd_data->middlebutton_state = 0; cptkbd_data->fn_lock = true; cptkbd_data->sensitivity = 0x05; lenovo_features_set_cptkbd(hdev); ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd); if (ret) hid_warn(hdev, "Could not create sysfs group: %d\n", ret); return 0; }
static void handler_return(struct wiimote_data *wdata, const __u8 *payload) { __u8 err = payload[3]; __u8 cmd = payload[2]; handler_keys(wdata, payload); if (err) hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err, cmd); }
/* Find a given report */ struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir) { struct list_head *feature_report_list = &hdev->report_enum[dir].report_list; struct hid_report *report = NULL; list_for_each_entry(report, feature_report_list, list) { if (report->id == id) return report; } hid_warn(hdev, "No report with id 0x%x found\n", id); return NULL; }
static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer, size_t count) { unsigned long flags; __u8 newhead; if (count > HID_MAX_BUFFER_SIZE) { hid_warn(wdata->hdev, "Sending too large output report\n"); return; } /* * Copy new request into our output queue and check whether the * queue is full. If it is full, discard this request. * If it is empty we need to start a new worker that will * send out the buffer to the hid device. * If the queue is not empty, then there must be a worker * that is currently sending out our buffer and this worker * will reschedule itself until the queue is empty. */ spin_lock_irqsave(&wdata->qlock, flags); memcpy(wdata->outq[wdata->head].data, buffer, count); wdata->outq[wdata->head].size = count; newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE; if (wdata->head == wdata->tail) { wdata->head = newhead; schedule_work(&wdata->worker); } else if (newhead != wdata->tail) { wdata->head = newhead; } else { hid_warn(wdata->hdev, "Output queue is full"); } spin_unlock_irqrestore(&wdata->qlock, flags); }
static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev) { __u8 newhead; newhead = (uhid->head + 1) % UHID_BUFSIZE; if (newhead != uhid->tail) { uhid->outq[uhid->head] = ev; uhid->head = newhead; wake_up_interruptible(&uhid->waitq); } else { hid_warn(uhid->hid, "Output queue is full\n"); kfree(ev); } }
static int uhid_hid_input(struct input_dev *input, unsigned int type, unsigned int code, int value) { struct hid_device *hid = input_get_drvdata(input); struct uhid_device *uhid = hid->driver_data; unsigned long flags; struct uhid_event *ev; struct hid_field *field; struct hid_report *report; int offset; ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) return -ENOMEM; switch (type) { case EV_LED: offset = hidinput_find_field(hid, type, code, &field); if (offset == -1) { hid_warn(input, "event field not found\n"); kfree(ev); return -1; } hid_set_field(field, offset, value); report = field->report; ev->type = UHID_OUTPUT; ev->u.output.rtype = UHID_OUTPUT_REPORT; hid_output_report(report, ev->u.output.data); ev->u.output.size = ((report->size - 1) >> 3) + 1 + (report->id > 0); break; default: ev->type = UHID_OUTPUT_EV; ev->u.output_ev.type = type; ev->u.output_ev.code = code; ev->u.output_ev.value = value; } spin_lock_irqsave(&uhid->qlock, flags); uhid_queue(uhid, ev); spin_unlock_irqrestore(&uhid->qlock, flags); return 0; }
static int tmff_init(struct hid_device *hid, const signed short *ff_bits) { struct tmff_device *tmff; struct hid_report *report; struct list_head *report_list; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; int error; int i; tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!tmff) return -ENOMEM; /* Find the report to use */ report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; list_for_each_entry(report, report_list, list) { int fieldnum; for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) { struct hid_field *field = report->field[fieldnum]; if (field->maxusage <= 0) continue; switch (field->usage[0].hid) { case THRUSTMASTER_USAGE_FF: if (field->report_count < 2) { <<<<<<< HEAD hid_warn(hid, "ignoring FF field with report_count < 2\n"); ======= dev_warn(&hid->dev, "ignoring FF field " "with report_count < 2\n"); >>>>>>> 296c66da8a02d52243f45b80521febece5ed498a continue; }
static int tmff_init(struct hid_device *hid, const signed short *ff_bits) { struct tmff_device *tmff; struct hid_report *report; struct list_head *report_list; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; int error; int i; tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!tmff) return -ENOMEM; /* Find the report to use */ report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; list_for_each_entry(report, report_list, list) { int fieldnum; for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) { struct hid_field *field = report->field[fieldnum]; if (field->maxusage <= 0) continue; switch (field->usage[0].hid) { case THRUSTMASTER_USAGE_FF: if (field->report_count < 2) { hid_warn(hid, "ignoring FF field with report_count < 2\n"); continue; } if (field->logical_maximum == field->logical_minimum) { hid_warn(hid, "ignoring FF field with logical_maximum == logical_minimum\n"); continue; } if (tmff->report && tmff->report != report) { hid_warn(hid, "ignoring FF field in other report\n"); continue; } if (tmff->ff_field && tmff->ff_field != field) { hid_warn(hid, "ignoring duplicate FF field\n"); continue; } tmff->report = report; tmff->ff_field = field; for (i = 0; ff_bits[i] >= 0; i++) set_bit(ff_bits[i], input_dev->ffbit); break; default: hid_warn(hid, "ignoring unknown output usage %08x\n", field->usage[0].hid); continue; } } }
static int valve_sc_init_device(struct valve_sc_device *sc) { int ret; struct hid_device *hdev = sc->hdev; struct input_dev *input; u8 params[6]; u8 feature; u8 serial[64]; int serial_len; char *name, *uniq; int name_sz, uniq_sz; hid_info(hdev, "Initializing device.\n"); /* Retrieve controller serial */ serial[0] = 1; ret = valve_sc_send_request(sc, SC_FEATURE_GET_SERIAL, serial, 21, serial, &serial_len); if (ret < 0 || serial_len < 1 || serial_len > 62) { hid_warn(hdev, "Error while get controller serial: %d\n", -ret); serial[1] = '\0'; } else { serial[serial_len] = '\0'; } /* Set mouse mode for right pad */ params[0] = SC_SETTINGS_AUTOMOUSE; if (sc->automouse) params[1] = SC_SETTINGS_AUTOMOUSE_ON; else params[1] = SC_SETTINGS_AUTOMOUSE_OFF; params[2] = 0; params[3] = SC_SETTINGS_ORIENTATION; params[4] = sc->orientation; params[5] = 0; ret = valve_sc_send_request(sc, SC_FEATURE_SETTINGS, params, 6, NULL, NULL); if (ret < 0) hid_warn(hdev, "Error while disabling mouse: %d\n", -ret); /* Disable buttons acting as keys */ if (sc->autobuttons) feature = SC_FEATURE_ENABLE_AUTO_BUTTONS; else feature = SC_FEATURE_DISABLE_AUTO_BUTTONS; ret = valve_sc_send_request(sc, feature, NULL, 0, NULL, NULL); if (ret < 0) hid_warn(hdev, "Error while setting auto buttons: %d\n", -ret); /* Create input device */ input = input_allocate_device(); if (!input) { hid_err(hdev, "Failed to allocate input device.\n"); return -ENOMEM; } sc->input = input; input->dev.parent = &hdev->dev; input->id.bustype = hdev->bus; input->id.vendor = hdev->vendor; input->id.product = hdev->product; input->id.version = hdev->version; name_sz = strlen(hdev->name) + 1; name = devm_kzalloc(&input->dev, name_sz, GFP_KERNEL); strncpy(name, hdev->name, name_sz); input->name = name; uniq_sz = serial_len + 1; uniq = devm_kzalloc(&input->dev, uniq_sz, GFP_KERNEL); strncpy(uniq, &serial[1], serial_len); uniq[serial_len] = '\0'; input->uniq = uniq; valve_sc_setup_input(input); ret = input_register_device(input); if (ret != 0) { hid_err(hdev, "Failed to register input device: %d.\n", -ret); input_free_device(input); sc->input = NULL; return ret; } return 0; }
/** * 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 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 valve_sc_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; struct valve_sc_device *sc; char answer[64]; int answer_len; sc = devm_kzalloc(&hdev->dev, sizeof (struct valve_sc_device), GFP_KERNEL); if (!sc) { hid_err (hdev, "cannot alloc driver data\n"); return -ENOMEM; } hid_set_drvdata(hdev, sc); sc->hdev = hdev; sc->automouse = false; sc->autobuttons = false; sc->orientation = 0; sc->center_touchpads = true; INIT_WORK(&sc->connect_work, valve_sc_connect_work); INIT_WORK(&sc->disconnect_work, valve_sc_disconnect_work); ret = hid_parse(hdev); if (ret != 0) { hid_err(hdev, "parse failed\n"); return ret; } if (hdev->rsize == RAW_REPORT_DESC_SIZE && strncmp (hdev->rdesc, raw_report_desc, RAW_REPORT_DESC_SIZE) == 0) { sc->parse_raw_report = true; ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); if (ret != 0) { hid_err(hdev, "HW start failed\n"); return ret; } ret = hid_hw_open(hdev); if (ret != 0) { hid_err(hdev, "HW open failed\n"); return ret; } switch (id->product) { case USB_DEVICE_ID_STEAM_CONTROLLER: /* Wired device is always connected */ sc->connected = true; valve_sc_init_device(sc); break; case USB_DEVICE_ID_STEAM_CONTROLLER_RECEIVER: /* Wireless will be initialized when connected */ sc->connected = false; ret = valve_sc_send_request(sc, SC_FEATURE_GET_CONNECTION_STATE, NULL, 0, answer, &answer_len); if (ret < 0) hid_warn(hdev, "Error while getting connection state: %d\n", -ret); break; } ret = sysfs_create_group(&hdev->dev.kobj, &valve_sc_attr_group); if (ret != 0) hid_warn(hdev, "Failed to create sysfs attribute group.\n"); } else { /* This is a generic mouse/keyboard interface */ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret != 0) { hid_err(hdev, "HW start failed\n"); return ret; } } return 0; }