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;
}
Exemple #2
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;
}
Exemple #3
0
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);
		}
	}
}
Exemple #10
0
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;
}
Exemple #11
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);
}
Exemple #12
0
/* 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;
}
Exemple #13
0
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);
}
Exemple #14
0
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;
				}
Exemple #17
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) {
					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;
}
Exemple #19
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;
}
Exemple #20
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;
}