xref: /openbmc/linux/drivers/hid/hid-u2fzero.c (revision 83478938)
142337b9dSAndrej Shadura // SPDX-License-Identifier: GPL-2.0
242337b9dSAndrej Shadura /*
342337b9dSAndrej Shadura  * U2F Zero LED and RNG driver
442337b9dSAndrej Shadura  *
542337b9dSAndrej Shadura  * Copyright 2018 Andrej Shadura <andrew@shadura.me>
642337b9dSAndrej Shadura  * Loosely based on drivers/hid/hid-led.c
742337b9dSAndrej Shadura  *              and drivers/usb/misc/chaoskey.c
842337b9dSAndrej Shadura  *
942337b9dSAndrej Shadura  * This program is free software; you can redistribute it and/or
1042337b9dSAndrej Shadura  * modify it under the terms of the GNU General Public License as
1142337b9dSAndrej Shadura  * published by the Free Software Foundation, version 2.
1242337b9dSAndrej Shadura  */
1342337b9dSAndrej Shadura 
1442337b9dSAndrej Shadura #include <linux/hid.h>
1542337b9dSAndrej Shadura #include <linux/hidraw.h>
1642337b9dSAndrej Shadura #include <linux/hw_random.h>
1742337b9dSAndrej Shadura #include <linux/leds.h>
1842337b9dSAndrej Shadura #include <linux/module.h>
1942337b9dSAndrej Shadura #include <linux/mutex.h>
2042337b9dSAndrej Shadura #include <linux/usb.h>
2142337b9dSAndrej Shadura 
2242337b9dSAndrej Shadura #include "usbhid/usbhid.h"
2342337b9dSAndrej Shadura #include "hid-ids.h"
2442337b9dSAndrej Shadura 
2542337b9dSAndrej Shadura #define DRIVER_SHORT		"u2fzero"
2642337b9dSAndrej Shadura 
2742337b9dSAndrej Shadura #define HID_REPORT_SIZE		64
2842337b9dSAndrej Shadura 
296748031aSAndrej Shadura enum hw_revision {
306748031aSAndrej Shadura 	HW_U2FZERO,
316748031aSAndrej Shadura 	HW_NITROKEY_U2F,
326748031aSAndrej Shadura };
336748031aSAndrej Shadura 
346748031aSAndrej Shadura struct hw_revision_config {
356748031aSAndrej Shadura 	u8 rng_cmd;
366748031aSAndrej Shadura 	u8 wink_cmd;
376748031aSAndrej Shadura 	const char *name;
386748031aSAndrej Shadura };
396748031aSAndrej Shadura 
406748031aSAndrej Shadura static const struct hw_revision_config hw_configs[] = {
416748031aSAndrej Shadura 	[HW_U2FZERO] = {
426748031aSAndrej Shadura 		.rng_cmd  = 0x21,
436748031aSAndrej Shadura 		.wink_cmd = 0x24,
446748031aSAndrej Shadura 		.name = "U2F Zero",
456748031aSAndrej Shadura 	},
466748031aSAndrej Shadura 	[HW_NITROKEY_U2F] = {
476748031aSAndrej Shadura 		.rng_cmd  = 0xc0,
486748031aSAndrej Shadura 		.wink_cmd = 0xc2,
496748031aSAndrej Shadura 		.name = "NitroKey U2F",
506748031aSAndrej Shadura 	},
516748031aSAndrej Shadura };
526748031aSAndrej Shadura 
5342337b9dSAndrej Shadura /* We only use broadcast (CID-less) messages */
5442337b9dSAndrej Shadura #define CID_BROADCAST		0xffffffff
5542337b9dSAndrej Shadura 
5642337b9dSAndrej Shadura struct u2f_hid_msg {
5742337b9dSAndrej Shadura 	u32 cid;
5842337b9dSAndrej Shadura 	union {
5942337b9dSAndrej Shadura 		struct {
6042337b9dSAndrej Shadura 			u8 cmd;
6142337b9dSAndrej Shadura 			u8 bcnth;
6242337b9dSAndrej Shadura 			u8 bcntl;
6342337b9dSAndrej Shadura 			u8 data[HID_REPORT_SIZE - 7];
6442337b9dSAndrej Shadura 		} init;
6542337b9dSAndrej Shadura 		struct {
6642337b9dSAndrej Shadura 			u8 seq;
6742337b9dSAndrej Shadura 			u8 data[HID_REPORT_SIZE - 5];
6842337b9dSAndrej Shadura 		} cont;
6942337b9dSAndrej Shadura 	};
7042337b9dSAndrej Shadura } __packed;
7142337b9dSAndrej Shadura 
7242337b9dSAndrej Shadura struct u2f_hid_report {
7342337b9dSAndrej Shadura 	u8 report_type;
7442337b9dSAndrej Shadura 	struct u2f_hid_msg msg;
7542337b9dSAndrej Shadura } __packed;
7642337b9dSAndrej Shadura 
7742337b9dSAndrej Shadura #define U2F_HID_MSG_LEN(f)	(size_t)(((f).init.bcnth << 8) + (f).init.bcntl)
7842337b9dSAndrej Shadura 
7942337b9dSAndrej Shadura struct u2fzero_device {
8042337b9dSAndrej Shadura 	struct hid_device	*hdev;
8142337b9dSAndrej Shadura 	struct urb		*urb;	    /* URB for the RNG data */
8242337b9dSAndrej Shadura 	struct led_classdev	ldev;	    /* Embedded struct for led */
8342337b9dSAndrej Shadura 	struct hwrng		hwrng;	    /* Embedded struct for hwrng */
8442337b9dSAndrej Shadura 	char			*led_name;
8542337b9dSAndrej Shadura 	char			*rng_name;
8642337b9dSAndrej Shadura 	u8			*buf_out;
8742337b9dSAndrej Shadura 	u8			*buf_in;
8842337b9dSAndrej Shadura 	struct mutex		lock;
8942337b9dSAndrej Shadura 	bool			present;
906748031aSAndrej Shadura 	kernel_ulong_t		hw_revision;
9142337b9dSAndrej Shadura };
9242337b9dSAndrej Shadura 
u2fzero_send(struct u2fzero_device * dev,struct u2f_hid_report * req)9342337b9dSAndrej Shadura static int u2fzero_send(struct u2fzero_device *dev, struct u2f_hid_report *req)
9442337b9dSAndrej Shadura {
9542337b9dSAndrej Shadura 	int ret;
9642337b9dSAndrej Shadura 
9742337b9dSAndrej Shadura 	mutex_lock(&dev->lock);
9842337b9dSAndrej Shadura 
9942337b9dSAndrej Shadura 	memcpy(dev->buf_out, req, sizeof(struct u2f_hid_report));
10042337b9dSAndrej Shadura 
10142337b9dSAndrej Shadura 	ret = hid_hw_output_report(dev->hdev, dev->buf_out,
10242337b9dSAndrej Shadura 				   sizeof(struct u2f_hid_msg));
10342337b9dSAndrej Shadura 
10442337b9dSAndrej Shadura 	mutex_unlock(&dev->lock);
10542337b9dSAndrej Shadura 
10642337b9dSAndrej Shadura 	if (ret < 0)
10742337b9dSAndrej Shadura 		return ret;
10842337b9dSAndrej Shadura 
10942337b9dSAndrej Shadura 	return ret == sizeof(struct u2f_hid_msg) ? 0 : -EMSGSIZE;
11042337b9dSAndrej Shadura }
11142337b9dSAndrej Shadura 
11242337b9dSAndrej Shadura struct u2fzero_transfer_context {
11342337b9dSAndrej Shadura 	struct completion done;
11442337b9dSAndrej Shadura 	int status;
11542337b9dSAndrej Shadura };
11642337b9dSAndrej Shadura 
u2fzero_read_callback(struct urb * urb)11742337b9dSAndrej Shadura static void u2fzero_read_callback(struct urb *urb)
11842337b9dSAndrej Shadura {
11942337b9dSAndrej Shadura 	struct u2fzero_transfer_context *ctx = urb->context;
12042337b9dSAndrej Shadura 
12142337b9dSAndrej Shadura 	ctx->status = urb->status;
12242337b9dSAndrej Shadura 	complete(&ctx->done);
12342337b9dSAndrej Shadura }
12442337b9dSAndrej Shadura 
u2fzero_recv(struct u2fzero_device * dev,struct u2f_hid_report * req,struct u2f_hid_msg * resp)12542337b9dSAndrej Shadura static int u2fzero_recv(struct u2fzero_device *dev,
12642337b9dSAndrej Shadura 			struct u2f_hid_report *req,
12742337b9dSAndrej Shadura 			struct u2f_hid_msg *resp)
12842337b9dSAndrej Shadura {
12942337b9dSAndrej Shadura 	int ret;
13042337b9dSAndrej Shadura 	struct hid_device *hdev = dev->hdev;
13142337b9dSAndrej Shadura 	struct u2fzero_transfer_context ctx;
13242337b9dSAndrej Shadura 
13342337b9dSAndrej Shadura 	mutex_lock(&dev->lock);
13442337b9dSAndrej Shadura 
13542337b9dSAndrej Shadura 	memcpy(dev->buf_out, req, sizeof(struct u2f_hid_report));
13642337b9dSAndrej Shadura 
13742337b9dSAndrej Shadura 	dev->urb->context = &ctx;
13842337b9dSAndrej Shadura 	init_completion(&ctx.done);
13942337b9dSAndrej Shadura 
14042337b9dSAndrej Shadura 	ret = usb_submit_urb(dev->urb, GFP_NOIO);
14142337b9dSAndrej Shadura 	if (unlikely(ret)) {
14242337b9dSAndrej Shadura 		hid_err(hdev, "usb_submit_urb failed: %d", ret);
14342337b9dSAndrej Shadura 		goto err;
14442337b9dSAndrej Shadura 	}
14542337b9dSAndrej Shadura 
14642337b9dSAndrej Shadura 	ret = hid_hw_output_report(dev->hdev, dev->buf_out,
14742337b9dSAndrej Shadura 				   sizeof(struct u2f_hid_msg));
14842337b9dSAndrej Shadura 
14942337b9dSAndrej Shadura 	if (ret < 0) {
15042337b9dSAndrej Shadura 		hid_err(hdev, "hid_hw_output_report failed: %d", ret);
15142337b9dSAndrej Shadura 		goto err;
15242337b9dSAndrej Shadura 	}
15342337b9dSAndrej Shadura 
15442337b9dSAndrej Shadura 	ret = (wait_for_completion_timeout(
15542337b9dSAndrej Shadura 		&ctx.done, msecs_to_jiffies(USB_CTRL_SET_TIMEOUT)));
15643775e62SAndrej Shadura 	if (ret == 0) {
15742337b9dSAndrej Shadura 		usb_kill_urb(dev->urb);
15842337b9dSAndrej Shadura 		hid_err(hdev, "urb submission timed out");
15942337b9dSAndrej Shadura 	} else {
16042337b9dSAndrej Shadura 		ret = dev->urb->actual_length;
16142337b9dSAndrej Shadura 		memcpy(resp, dev->buf_in, ret);
16242337b9dSAndrej Shadura 	}
16342337b9dSAndrej Shadura 
16442337b9dSAndrej Shadura err:
16542337b9dSAndrej Shadura 	mutex_unlock(&dev->lock);
16642337b9dSAndrej Shadura 
16742337b9dSAndrej Shadura 	return ret;
16842337b9dSAndrej Shadura }
16942337b9dSAndrej Shadura 
u2fzero_blink(struct led_classdev * ldev)17042337b9dSAndrej Shadura static int u2fzero_blink(struct led_classdev *ldev)
17142337b9dSAndrej Shadura {
17242337b9dSAndrej Shadura 	struct u2fzero_device *dev = container_of(ldev,
17342337b9dSAndrej Shadura 		struct u2fzero_device, ldev);
17442337b9dSAndrej Shadura 	struct u2f_hid_report req = {
17542337b9dSAndrej Shadura 		.report_type = 0,
17642337b9dSAndrej Shadura 		.msg.cid = CID_BROADCAST,
17742337b9dSAndrej Shadura 		.msg.init = {
1786748031aSAndrej Shadura 			.cmd = hw_configs[dev->hw_revision].wink_cmd,
17942337b9dSAndrej Shadura 			.bcnth = 0,
18042337b9dSAndrej Shadura 			.bcntl = 0,
18142337b9dSAndrej Shadura 			.data  = {0},
18242337b9dSAndrej Shadura 		}
18342337b9dSAndrej Shadura 	};
18442337b9dSAndrej Shadura 	return u2fzero_send(dev, &req);
18542337b9dSAndrej Shadura }
18642337b9dSAndrej Shadura 
u2fzero_brightness_set(struct led_classdev * ldev,enum led_brightness brightness)18742337b9dSAndrej Shadura static int u2fzero_brightness_set(struct led_classdev *ldev,
18842337b9dSAndrej Shadura 				  enum led_brightness brightness)
18942337b9dSAndrej Shadura {
19042337b9dSAndrej Shadura 	ldev->brightness = LED_OFF;
19142337b9dSAndrej Shadura 	if (brightness)
19242337b9dSAndrej Shadura 		return u2fzero_blink(ldev);
19342337b9dSAndrej Shadura 	else
19442337b9dSAndrej Shadura 		return 0;
19542337b9dSAndrej Shadura }
19642337b9dSAndrej Shadura 
u2fzero_rng_read(struct hwrng * rng,void * data,size_t max,bool wait)19742337b9dSAndrej Shadura static int u2fzero_rng_read(struct hwrng *rng, void *data,
19842337b9dSAndrej Shadura 			    size_t max, bool wait)
19942337b9dSAndrej Shadura {
20042337b9dSAndrej Shadura 	struct u2fzero_device *dev = container_of(rng,
20142337b9dSAndrej Shadura 		struct u2fzero_device, hwrng);
20242337b9dSAndrej Shadura 	struct u2f_hid_report req = {
20342337b9dSAndrej Shadura 		.report_type = 0,
20442337b9dSAndrej Shadura 		.msg.cid = CID_BROADCAST,
20542337b9dSAndrej Shadura 		.msg.init = {
2066748031aSAndrej Shadura 			.cmd = hw_configs[dev->hw_revision].rng_cmd,
20742337b9dSAndrej Shadura 			.bcnth = 0,
20842337b9dSAndrej Shadura 			.bcntl = 0,
20942337b9dSAndrej Shadura 			.data  = {0},
21042337b9dSAndrej Shadura 		}
21142337b9dSAndrej Shadura 	};
21242337b9dSAndrej Shadura 	struct u2f_hid_msg resp;
21342337b9dSAndrej Shadura 	int ret;
21442337b9dSAndrej Shadura 	size_t actual_length;
215b7abf78bSAndrej Shadura 	/* valid packets must have a correct header */
216b7abf78bSAndrej Shadura 	int min_length = offsetof(struct u2f_hid_msg, init.data);
21742337b9dSAndrej Shadura 
21842337b9dSAndrej Shadura 	if (!dev->present) {
21942337b9dSAndrej Shadura 		hid_dbg(dev->hdev, "device not present");
22042337b9dSAndrej Shadura 		return 0;
22142337b9dSAndrej Shadura 	}
22242337b9dSAndrej Shadura 
22342337b9dSAndrej Shadura 	ret = u2fzero_recv(dev, &req, &resp);
22422d65765SAndrej Shadura 
22522d65765SAndrej Shadura 	/* ignore errors or packets without data */
226b7abf78bSAndrej Shadura 	if (ret < min_length)
22742337b9dSAndrej Shadura 		return 0;
22842337b9dSAndrej Shadura 
22942337b9dSAndrej Shadura 	/* only take the minimum amount of data it is safe to take */
230b7abf78bSAndrej Shadura 	actual_length = min3((size_t)ret - min_length,
231b7abf78bSAndrej Shadura 		U2F_HID_MSG_LEN(resp), max);
23242337b9dSAndrej Shadura 
23342337b9dSAndrej Shadura 	memcpy(data, resp.init.data, actual_length);
23442337b9dSAndrej Shadura 
23542337b9dSAndrej Shadura 	return actual_length;
23642337b9dSAndrej Shadura }
23742337b9dSAndrej Shadura 
u2fzero_init_led(struct u2fzero_device * dev,unsigned int minor)23842337b9dSAndrej Shadura static int u2fzero_init_led(struct u2fzero_device *dev,
23942337b9dSAndrej Shadura 			    unsigned int minor)
24042337b9dSAndrej Shadura {
24142337b9dSAndrej Shadura 	dev->led_name = devm_kasprintf(&dev->hdev->dev, GFP_KERNEL,
24242337b9dSAndrej Shadura 		"%s%u", DRIVER_SHORT, minor);
24342337b9dSAndrej Shadura 	if (dev->led_name == NULL)
24442337b9dSAndrej Shadura 		return -ENOMEM;
24542337b9dSAndrej Shadura 
24642337b9dSAndrej Shadura 	dev->ldev.name = dev->led_name;
24742337b9dSAndrej Shadura 	dev->ldev.max_brightness = LED_ON;
24842337b9dSAndrej Shadura 	dev->ldev.flags = LED_HW_PLUGGABLE;
24942337b9dSAndrej Shadura 	dev->ldev.brightness_set_blocking = u2fzero_brightness_set;
25042337b9dSAndrej Shadura 
25142337b9dSAndrej Shadura 	return devm_led_classdev_register(&dev->hdev->dev, &dev->ldev);
25242337b9dSAndrej Shadura }
25342337b9dSAndrej Shadura 
u2fzero_init_hwrng(struct u2fzero_device * dev,unsigned int minor)25442337b9dSAndrej Shadura static int u2fzero_init_hwrng(struct u2fzero_device *dev,
25542337b9dSAndrej Shadura 			      unsigned int minor)
25642337b9dSAndrej Shadura {
25742337b9dSAndrej Shadura 	dev->rng_name = devm_kasprintf(&dev->hdev->dev, GFP_KERNEL,
25842337b9dSAndrej Shadura 		"%s-rng%u", DRIVER_SHORT, minor);
25942337b9dSAndrej Shadura 	if (dev->rng_name == NULL)
26042337b9dSAndrej Shadura 		return -ENOMEM;
26142337b9dSAndrej Shadura 
26242337b9dSAndrej Shadura 	dev->hwrng.name = dev->rng_name;
26342337b9dSAndrej Shadura 	dev->hwrng.read = u2fzero_rng_read;
26442337b9dSAndrej Shadura 
26542337b9dSAndrej Shadura 	return devm_hwrng_register(&dev->hdev->dev, &dev->hwrng);
26642337b9dSAndrej Shadura }
26742337b9dSAndrej Shadura 
u2fzero_fill_in_urb(struct u2fzero_device * dev)26842337b9dSAndrej Shadura static int u2fzero_fill_in_urb(struct u2fzero_device *dev)
26942337b9dSAndrej Shadura {
27042337b9dSAndrej Shadura 	struct hid_device *hdev = dev->hdev;
27142337b9dSAndrej Shadura 	struct usb_device *udev;
27242337b9dSAndrej Shadura 	struct usbhid_device *usbhid = hdev->driver_data;
27342337b9dSAndrej Shadura 	unsigned int pipe_in;
27442337b9dSAndrej Shadura 	struct usb_host_endpoint *ep;
27542337b9dSAndrej Shadura 
27642337b9dSAndrej Shadura 	if (dev->hdev->bus != BUS_USB)
27742337b9dSAndrej Shadura 		return -EINVAL;
27842337b9dSAndrej Shadura 
27942337b9dSAndrej Shadura 	udev = hid_to_usb_dev(hdev);
28042337b9dSAndrej Shadura 
28142337b9dSAndrej Shadura 	if (!usbhid->urbout || !usbhid->urbin)
28242337b9dSAndrej Shadura 		return -ENODEV;
28342337b9dSAndrej Shadura 
28442337b9dSAndrej Shadura 	ep = usb_pipe_endpoint(udev, usbhid->urbin->pipe);
28542337b9dSAndrej Shadura 	if (!ep)
28642337b9dSAndrej Shadura 		return -ENODEV;
28742337b9dSAndrej Shadura 
28842337b9dSAndrej Shadura 	dev->urb = usb_alloc_urb(0, GFP_KERNEL);
28942337b9dSAndrej Shadura 	if (!dev->urb)
29042337b9dSAndrej Shadura 		return -ENOMEM;
29142337b9dSAndrej Shadura 
29242337b9dSAndrej Shadura 	pipe_in = (usbhid->urbin->pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
29342337b9dSAndrej Shadura 
29442337b9dSAndrej Shadura 	usb_fill_int_urb(dev->urb,
29542337b9dSAndrej Shadura 		udev,
29642337b9dSAndrej Shadura 		pipe_in,
29742337b9dSAndrej Shadura 		dev->buf_in,
29842337b9dSAndrej Shadura 		HID_REPORT_SIZE,
29942337b9dSAndrej Shadura 		u2fzero_read_callback,
30042337b9dSAndrej Shadura 		NULL,
30142337b9dSAndrej Shadura 		ep->desc.bInterval);
30242337b9dSAndrej Shadura 
30342337b9dSAndrej Shadura 	return 0;
30442337b9dSAndrej Shadura }
30542337b9dSAndrej Shadura 
u2fzero_probe(struct hid_device * hdev,const struct hid_device_id * id)30642337b9dSAndrej Shadura static int u2fzero_probe(struct hid_device *hdev,
30742337b9dSAndrej Shadura 			 const struct hid_device_id *id)
30842337b9dSAndrej Shadura {
30942337b9dSAndrej Shadura 	struct u2fzero_device *dev;
31042337b9dSAndrej Shadura 	unsigned int minor;
31142337b9dSAndrej Shadura 	int ret;
31242337b9dSAndrej Shadura 
313*f83baa0cSGreg Kroah-Hartman 	if (!hid_is_usb(hdev))
31459579a8dSJiri Kosina 		return -EINVAL;
31559579a8dSJiri Kosina 
31642337b9dSAndrej Shadura 	dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
31742337b9dSAndrej Shadura 	if (dev == NULL)
31842337b9dSAndrej Shadura 		return -ENOMEM;
31942337b9dSAndrej Shadura 
3206748031aSAndrej Shadura 	dev->hw_revision = id->driver_data;
3216748031aSAndrej Shadura 
32242337b9dSAndrej Shadura 	dev->buf_out = devm_kmalloc(&hdev->dev,
32342337b9dSAndrej Shadura 		sizeof(struct u2f_hid_report), GFP_KERNEL);
32442337b9dSAndrej Shadura 	if (dev->buf_out == NULL)
32542337b9dSAndrej Shadura 		return -ENOMEM;
32642337b9dSAndrej Shadura 
32742337b9dSAndrej Shadura 	dev->buf_in = devm_kmalloc(&hdev->dev,
32842337b9dSAndrej Shadura 		sizeof(struct u2f_hid_msg), GFP_KERNEL);
32942337b9dSAndrej Shadura 	if (dev->buf_in == NULL)
33042337b9dSAndrej Shadura 		return -ENOMEM;
33142337b9dSAndrej Shadura 
33242337b9dSAndrej Shadura 	ret = hid_parse(hdev);
33342337b9dSAndrej Shadura 	if (ret)
33442337b9dSAndrej Shadura 		return ret;
33542337b9dSAndrej Shadura 
33642337b9dSAndrej Shadura 	dev->hdev = hdev;
33742337b9dSAndrej Shadura 	hid_set_drvdata(hdev, dev);
33842337b9dSAndrej Shadura 	mutex_init(&dev->lock);
33942337b9dSAndrej Shadura 
34042337b9dSAndrej Shadura 	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
34142337b9dSAndrej Shadura 	if (ret)
34242337b9dSAndrej Shadura 		return ret;
34342337b9dSAndrej Shadura 
34442337b9dSAndrej Shadura 	u2fzero_fill_in_urb(dev);
34542337b9dSAndrej Shadura 
34642337b9dSAndrej Shadura 	dev->present = true;
34742337b9dSAndrej Shadura 
34842337b9dSAndrej Shadura 	minor = ((struct hidraw *) hdev->hidraw)->minor;
34942337b9dSAndrej Shadura 
35042337b9dSAndrej Shadura 	ret = u2fzero_init_led(dev, minor);
35142337b9dSAndrej Shadura 	if (ret) {
35242337b9dSAndrej Shadura 		hid_hw_stop(hdev);
35342337b9dSAndrej Shadura 		return ret;
35442337b9dSAndrej Shadura 	}
35542337b9dSAndrej Shadura 
3566748031aSAndrej Shadura 	hid_info(hdev, "%s LED initialised\n", hw_configs[dev->hw_revision].name);
35742337b9dSAndrej Shadura 
35842337b9dSAndrej Shadura 	ret = u2fzero_init_hwrng(dev, minor);
35942337b9dSAndrej Shadura 	if (ret) {
36042337b9dSAndrej Shadura 		hid_hw_stop(hdev);
36142337b9dSAndrej Shadura 		return ret;
36242337b9dSAndrej Shadura 	}
36342337b9dSAndrej Shadura 
3646748031aSAndrej Shadura 	hid_info(hdev, "%s RNG initialised\n", hw_configs[dev->hw_revision].name);
36542337b9dSAndrej Shadura 
36642337b9dSAndrej Shadura 	return 0;
36742337b9dSAndrej Shadura }
36842337b9dSAndrej Shadura 
u2fzero_remove(struct hid_device * hdev)36942337b9dSAndrej Shadura static void u2fzero_remove(struct hid_device *hdev)
37042337b9dSAndrej Shadura {
37142337b9dSAndrej Shadura 	struct u2fzero_device *dev = hid_get_drvdata(hdev);
37242337b9dSAndrej Shadura 
37342337b9dSAndrej Shadura 	mutex_lock(&dev->lock);
37442337b9dSAndrej Shadura 	dev->present = false;
37542337b9dSAndrej Shadura 	mutex_unlock(&dev->lock);
37642337b9dSAndrej Shadura 
37742337b9dSAndrej Shadura 	hid_hw_stop(hdev);
37842337b9dSAndrej Shadura 	usb_poison_urb(dev->urb);
37942337b9dSAndrej Shadura 	usb_free_urb(dev->urb);
38042337b9dSAndrej Shadura }
38142337b9dSAndrej Shadura 
38242337b9dSAndrej Shadura static const struct hid_device_id u2fzero_table[] = {
38342337b9dSAndrej Shadura 	{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL,
3846748031aSAndrej Shadura 	  USB_DEVICE_ID_U2F_ZERO),
3856748031aSAndrej Shadura 	  .driver_data = HW_U2FZERO },
3866748031aSAndrej Shadura 	{ HID_USB_DEVICE(USB_VENDOR_ID_CLAY_LOGIC,
3876748031aSAndrej Shadura 	  USB_DEVICE_ID_NITROKEY_U2F),
3886748031aSAndrej Shadura 	  .driver_data = HW_NITROKEY_U2F },
38942337b9dSAndrej Shadura 	{ }
39042337b9dSAndrej Shadura };
39142337b9dSAndrej Shadura MODULE_DEVICE_TABLE(hid, u2fzero_table);
39242337b9dSAndrej Shadura 
39342337b9dSAndrej Shadura static struct hid_driver u2fzero_driver = {
39442337b9dSAndrej Shadura 	.name = "hid-" DRIVER_SHORT,
39542337b9dSAndrej Shadura 	.probe = u2fzero_probe,
39642337b9dSAndrej Shadura 	.remove = u2fzero_remove,
39742337b9dSAndrej Shadura 	.id_table = u2fzero_table,
39842337b9dSAndrej Shadura };
39942337b9dSAndrej Shadura 
40042337b9dSAndrej Shadura module_hid_driver(u2fzero_driver);
40142337b9dSAndrej Shadura 
40242337b9dSAndrej Shadura MODULE_LICENSE("GPL");
40342337b9dSAndrej Shadura MODULE_AUTHOR("Andrej Shadura <andrew@shadura.me>");
40442337b9dSAndrej Shadura MODULE_DESCRIPTION("U2F Zero LED and RNG driver");
405