162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * chaoskey - driver for ChaosKey device from Altus Metrum.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This device provides true random numbers using a noise source based
662306a36Sopenharmony_ci * on a reverse-biased p-n junction in avalanche breakdown. More
762306a36Sopenharmony_ci * details can be found at http://chaoskey.org
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * The driver connects to the kernel hardware RNG interface to provide
1062306a36Sopenharmony_ci * entropy for /dev/random and other kernel activities. It also offers
1162306a36Sopenharmony_ci * a separate /dev/ entry to allow for direct access to the random
1262306a36Sopenharmony_ci * bit stream.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Copyright © 2015 Keith Packard <keithp@keithp.com>
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/usb.h>
2062306a36Sopenharmony_ci#include <linux/wait.h>
2162306a36Sopenharmony_ci#include <linux/hw_random.h>
2262306a36Sopenharmony_ci#include <linux/mutex.h>
2362306a36Sopenharmony_ci#include <linux/uaccess.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic struct usb_driver chaoskey_driver;
2662306a36Sopenharmony_cistatic struct usb_class_driver chaoskey_class;
2762306a36Sopenharmony_cistatic int chaoskey_rng_read(struct hwrng *rng, void *data,
2862306a36Sopenharmony_ci			     size_t max, bool wait);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define usb_dbg(usb_if, format, arg...) \
3162306a36Sopenharmony_ci	dev_dbg(&(usb_if)->dev, format, ## arg)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define usb_err(usb_if, format, arg...) \
3462306a36Sopenharmony_ci	dev_err(&(usb_if)->dev, format, ## arg)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Version Information */
3762306a36Sopenharmony_ci#define DRIVER_AUTHOR	"Keith Packard, keithp@keithp.com"
3862306a36Sopenharmony_ci#define DRIVER_DESC	"Altus Metrum ChaosKey driver"
3962306a36Sopenharmony_ci#define DRIVER_SHORT	"chaoskey"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
4262306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
4362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define CHAOSKEY_VENDOR_ID	0x1d50	/* OpenMoko */
4662306a36Sopenharmony_ci#define CHAOSKEY_PRODUCT_ID	0x60c6	/* ChaosKey */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define ALEA_VENDOR_ID		0x12d8	/* Araneus */
4962306a36Sopenharmony_ci#define ALEA_PRODUCT_ID		0x0001	/* Alea I */
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define CHAOSKEY_BUF_LEN	64	/* max size of USB full speed packet */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define NAK_TIMEOUT (HZ)		/* normal stall/wait timeout */
5462306a36Sopenharmony_ci#define ALEA_FIRST_TIMEOUT (HZ*3)	/* first stall/wait timeout for Alea */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#ifdef CONFIG_USB_DYNAMIC_MINORS
5762306a36Sopenharmony_ci#define USB_CHAOSKEY_MINOR_BASE 0
5862306a36Sopenharmony_ci#else
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* IOWARRIOR_MINOR_BASE + 16, not official yet */
6162306a36Sopenharmony_ci#define USB_CHAOSKEY_MINOR_BASE 224
6262306a36Sopenharmony_ci#endif
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const struct usb_device_id chaoskey_table[] = {
6562306a36Sopenharmony_ci	{ USB_DEVICE(CHAOSKEY_VENDOR_ID, CHAOSKEY_PRODUCT_ID) },
6662306a36Sopenharmony_ci	{ USB_DEVICE(ALEA_VENDOR_ID, ALEA_PRODUCT_ID) },
6762306a36Sopenharmony_ci	{ },
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, chaoskey_table);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic void chaos_read_callback(struct urb *urb);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* Driver-local specific stuff */
7462306a36Sopenharmony_cistruct chaoskey {
7562306a36Sopenharmony_ci	struct usb_interface *interface;
7662306a36Sopenharmony_ci	char in_ep;
7762306a36Sopenharmony_ci	struct mutex lock;
7862306a36Sopenharmony_ci	struct mutex rng_lock;
7962306a36Sopenharmony_ci	int open;			/* open count */
8062306a36Sopenharmony_ci	bool present;			/* device not disconnected */
8162306a36Sopenharmony_ci	bool reading;			/* ongoing IO */
8262306a36Sopenharmony_ci	bool reads_started;		/* track first read for Alea */
8362306a36Sopenharmony_ci	int size;			/* size of buf */
8462306a36Sopenharmony_ci	int valid;			/* bytes of buf read */
8562306a36Sopenharmony_ci	int used;			/* bytes of buf consumed */
8662306a36Sopenharmony_ci	char *name;			/* product + serial */
8762306a36Sopenharmony_ci	struct hwrng hwrng;		/* Embedded struct for hwrng */
8862306a36Sopenharmony_ci	int hwrng_registered;		/* registered with hwrng API */
8962306a36Sopenharmony_ci	wait_queue_head_t wait_q;	/* for timeouts */
9062306a36Sopenharmony_ci	struct urb *urb;		/* for performing IO */
9162306a36Sopenharmony_ci	char *buf;
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic void chaoskey_free(struct chaoskey *dev)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	if (dev) {
9762306a36Sopenharmony_ci		usb_dbg(dev->interface, "free");
9862306a36Sopenharmony_ci		usb_free_urb(dev->urb);
9962306a36Sopenharmony_ci		kfree(dev->name);
10062306a36Sopenharmony_ci		kfree(dev->buf);
10162306a36Sopenharmony_ci		usb_put_intf(dev->interface);
10262306a36Sopenharmony_ci		kfree(dev);
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic int chaoskey_probe(struct usb_interface *interface,
10762306a36Sopenharmony_ci			  const struct usb_device_id *id)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(interface);
11062306a36Sopenharmony_ci	struct usb_host_interface *altsetting = interface->cur_altsetting;
11162306a36Sopenharmony_ci	struct usb_endpoint_descriptor *epd;
11262306a36Sopenharmony_ci	int in_ep;
11362306a36Sopenharmony_ci	struct chaoskey *dev;
11462306a36Sopenharmony_ci	int result = -ENOMEM;
11562306a36Sopenharmony_ci	int size;
11662306a36Sopenharmony_ci	int res;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	usb_dbg(interface, "probe %s-%s", udev->product, udev->serial);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* Find the first bulk IN endpoint and its packet size */
12162306a36Sopenharmony_ci	res = usb_find_bulk_in_endpoint(altsetting, &epd);
12262306a36Sopenharmony_ci	if (res) {
12362306a36Sopenharmony_ci		usb_dbg(interface, "no IN endpoint found");
12462306a36Sopenharmony_ci		return res;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	in_ep = usb_endpoint_num(epd);
12862306a36Sopenharmony_ci	size = usb_endpoint_maxp(epd);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* Validate endpoint and size */
13162306a36Sopenharmony_ci	if (size <= 0) {
13262306a36Sopenharmony_ci		usb_dbg(interface, "invalid size (%d)", size);
13362306a36Sopenharmony_ci		return -ENODEV;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (size > CHAOSKEY_BUF_LEN) {
13762306a36Sopenharmony_ci		usb_dbg(interface, "size reduced from %d to %d\n",
13862306a36Sopenharmony_ci			size, CHAOSKEY_BUF_LEN);
13962306a36Sopenharmony_ci		size = CHAOSKEY_BUF_LEN;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* Looks good, allocate and initialize */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	dev = kzalloc(sizeof(struct chaoskey), GFP_KERNEL);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (dev == NULL)
14762306a36Sopenharmony_ci		goto out;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	dev->interface = usb_get_intf(interface);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	dev->buf = kmalloc(size, GFP_KERNEL);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (dev->buf == NULL)
15462306a36Sopenharmony_ci		goto out;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	dev->urb = usb_alloc_urb(0, GFP_KERNEL);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (!dev->urb)
15962306a36Sopenharmony_ci		goto out;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	usb_fill_bulk_urb(dev->urb,
16262306a36Sopenharmony_ci		udev,
16362306a36Sopenharmony_ci		usb_rcvbulkpipe(udev, in_ep),
16462306a36Sopenharmony_ci		dev->buf,
16562306a36Sopenharmony_ci		size,
16662306a36Sopenharmony_ci		chaos_read_callback,
16762306a36Sopenharmony_ci		dev);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* Construct a name using the product and serial values. Each
17062306a36Sopenharmony_ci	 * device needs a unique name for the hwrng code
17162306a36Sopenharmony_ci	 */
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (udev->product && udev->serial) {
17462306a36Sopenharmony_ci		dev->name = kasprintf(GFP_KERNEL, "%s-%s", udev->product,
17562306a36Sopenharmony_ci				      udev->serial);
17662306a36Sopenharmony_ci		if (dev->name == NULL)
17762306a36Sopenharmony_ci			goto out;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	dev->in_ep = in_ep;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (le16_to_cpu(udev->descriptor.idVendor) != ALEA_VENDOR_ID)
18362306a36Sopenharmony_ci		dev->reads_started = true;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	dev->size = size;
18662306a36Sopenharmony_ci	dev->present = true;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	init_waitqueue_head(&dev->wait_q);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	mutex_init(&dev->lock);
19162306a36Sopenharmony_ci	mutex_init(&dev->rng_lock);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	usb_set_intfdata(interface, dev);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	result = usb_register_dev(interface, &chaoskey_class);
19662306a36Sopenharmony_ci	if (result) {
19762306a36Sopenharmony_ci		usb_err(interface, "Unable to allocate minor number.");
19862306a36Sopenharmony_ci		goto out;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	dev->hwrng.name = dev->name ? dev->name : chaoskey_driver.name;
20262306a36Sopenharmony_ci	dev->hwrng.read = chaoskey_rng_read;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	dev->hwrng_registered = (hwrng_register(&dev->hwrng) == 0);
20562306a36Sopenharmony_ci	if (!dev->hwrng_registered)
20662306a36Sopenharmony_ci		usb_err(interface, "Unable to register with hwrng");
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	usb_enable_autosuspend(udev);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	usb_dbg(interface, "chaoskey probe success, size %d", dev->size);
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ciout:
21462306a36Sopenharmony_ci	usb_set_intfdata(interface, NULL);
21562306a36Sopenharmony_ci	chaoskey_free(dev);
21662306a36Sopenharmony_ci	return result;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic void chaoskey_disconnect(struct usb_interface *interface)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	struct chaoskey	*dev;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	usb_dbg(interface, "disconnect");
22462306a36Sopenharmony_ci	dev = usb_get_intfdata(interface);
22562306a36Sopenharmony_ci	if (!dev) {
22662306a36Sopenharmony_ci		usb_dbg(interface, "disconnect failed - no dev");
22762306a36Sopenharmony_ci		return;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (dev->hwrng_registered)
23162306a36Sopenharmony_ci		hwrng_unregister(&dev->hwrng);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	usb_deregister_dev(interface, &chaoskey_class);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	usb_set_intfdata(interface, NULL);
23662306a36Sopenharmony_ci	mutex_lock(&dev->lock);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	dev->present = false;
23962306a36Sopenharmony_ci	usb_poison_urb(dev->urb);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (!dev->open) {
24262306a36Sopenharmony_ci		mutex_unlock(&dev->lock);
24362306a36Sopenharmony_ci		chaoskey_free(dev);
24462306a36Sopenharmony_ci	} else
24562306a36Sopenharmony_ci		mutex_unlock(&dev->lock);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	usb_dbg(interface, "disconnect done");
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic int chaoskey_open(struct inode *inode, struct file *file)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct chaoskey *dev;
25362306a36Sopenharmony_ci	struct usb_interface *interface;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/* get the interface from minor number and driver information */
25662306a36Sopenharmony_ci	interface = usb_find_interface(&chaoskey_driver, iminor(inode));
25762306a36Sopenharmony_ci	if (!interface)
25862306a36Sopenharmony_ci		return -ENODEV;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	usb_dbg(interface, "open");
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	dev = usb_get_intfdata(interface);
26362306a36Sopenharmony_ci	if (!dev) {
26462306a36Sopenharmony_ci		usb_dbg(interface, "open (dev)");
26562306a36Sopenharmony_ci		return -ENODEV;
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	file->private_data = dev;
26962306a36Sopenharmony_ci	mutex_lock(&dev->lock);
27062306a36Sopenharmony_ci	++dev->open;
27162306a36Sopenharmony_ci	mutex_unlock(&dev->lock);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	usb_dbg(interface, "open success");
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic int chaoskey_release(struct inode *inode, struct file *file)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct chaoskey *dev = file->private_data;
28062306a36Sopenharmony_ci	struct usb_interface *interface;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (dev == NULL)
28362306a36Sopenharmony_ci		return -ENODEV;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	interface = dev->interface;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	usb_dbg(interface, "release");
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	mutex_lock(&dev->lock);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	usb_dbg(interface, "open count at release is %d", dev->open);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (dev->open <= 0) {
29462306a36Sopenharmony_ci		usb_dbg(interface, "invalid open count (%d)", dev->open);
29562306a36Sopenharmony_ci		mutex_unlock(&dev->lock);
29662306a36Sopenharmony_ci		return -ENODEV;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	--dev->open;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (!dev->present) {
30262306a36Sopenharmony_ci		if (dev->open == 0) {
30362306a36Sopenharmony_ci			mutex_unlock(&dev->lock);
30462306a36Sopenharmony_ci			chaoskey_free(dev);
30562306a36Sopenharmony_ci		} else
30662306a36Sopenharmony_ci			mutex_unlock(&dev->lock);
30762306a36Sopenharmony_ci	} else
30862306a36Sopenharmony_ci		mutex_unlock(&dev->lock);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	usb_dbg(interface, "release success");
31162306a36Sopenharmony_ci	return 0;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void chaos_read_callback(struct urb *urb)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct chaoskey *dev = urb->context;
31762306a36Sopenharmony_ci	int status = urb->status;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	usb_dbg(dev->interface, "callback status (%d)", status);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (status == 0)
32262306a36Sopenharmony_ci		dev->valid = urb->actual_length;
32362306a36Sopenharmony_ci	else
32462306a36Sopenharmony_ci		dev->valid = 0;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	dev->used = 0;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* must be seen first before validity is announced */
32962306a36Sopenharmony_ci	smp_wmb();
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	dev->reading = false;
33262306a36Sopenharmony_ci	wake_up(&dev->wait_q);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci/* Fill the buffer. Called with dev->lock held
33662306a36Sopenharmony_ci */
33762306a36Sopenharmony_cistatic int _chaoskey_fill(struct chaoskey *dev)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	DEFINE_WAIT(wait);
34062306a36Sopenharmony_ci	int result;
34162306a36Sopenharmony_ci	bool started;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	usb_dbg(dev->interface, "fill");
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Return immediately if someone called before the buffer was
34662306a36Sopenharmony_ci	 * empty */
34762306a36Sopenharmony_ci	if (dev->valid != dev->used) {
34862306a36Sopenharmony_ci		usb_dbg(dev->interface, "not empty yet (valid %d used %d)",
34962306a36Sopenharmony_ci			dev->valid, dev->used);
35062306a36Sopenharmony_ci		return 0;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* Bail if the device has been removed */
35462306a36Sopenharmony_ci	if (!dev->present) {
35562306a36Sopenharmony_ci		usb_dbg(dev->interface, "device not present");
35662306a36Sopenharmony_ci		return -ENODEV;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/* Make sure the device is awake */
36062306a36Sopenharmony_ci	result = usb_autopm_get_interface(dev->interface);
36162306a36Sopenharmony_ci	if (result) {
36262306a36Sopenharmony_ci		usb_dbg(dev->interface, "wakeup failed (result %d)", result);
36362306a36Sopenharmony_ci		return result;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	dev->reading = true;
36762306a36Sopenharmony_ci	result = usb_submit_urb(dev->urb, GFP_KERNEL);
36862306a36Sopenharmony_ci	if (result < 0) {
36962306a36Sopenharmony_ci		result = usb_translate_errors(result);
37062306a36Sopenharmony_ci		dev->reading = false;
37162306a36Sopenharmony_ci		goto out;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* The first read on the Alea takes a little under 2 seconds.
37562306a36Sopenharmony_ci	 * Reads after the first read take only a few microseconds
37662306a36Sopenharmony_ci	 * though.  Presumably the entropy-generating circuit needs
37762306a36Sopenharmony_ci	 * time to ramp up.  So, we wait longer on the first read.
37862306a36Sopenharmony_ci	 */
37962306a36Sopenharmony_ci	started = dev->reads_started;
38062306a36Sopenharmony_ci	dev->reads_started = true;
38162306a36Sopenharmony_ci	result = wait_event_interruptible_timeout(
38262306a36Sopenharmony_ci		dev->wait_q,
38362306a36Sopenharmony_ci		!dev->reading,
38462306a36Sopenharmony_ci		(started ? NAK_TIMEOUT : ALEA_FIRST_TIMEOUT) );
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (result < 0) {
38762306a36Sopenharmony_ci		usb_kill_urb(dev->urb);
38862306a36Sopenharmony_ci		goto out;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (result == 0) {
39262306a36Sopenharmony_ci		result = -ETIMEDOUT;
39362306a36Sopenharmony_ci		usb_kill_urb(dev->urb);
39462306a36Sopenharmony_ci	} else {
39562306a36Sopenharmony_ci		result = dev->valid;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ciout:
39862306a36Sopenharmony_ci	/* Let the device go back to sleep eventually */
39962306a36Sopenharmony_ci	usb_autopm_put_interface(dev->interface);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	usb_dbg(dev->interface, "read %d bytes", dev->valid);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	return result;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic ssize_t chaoskey_read(struct file *file,
40762306a36Sopenharmony_ci			     char __user *buffer,
40862306a36Sopenharmony_ci			     size_t count,
40962306a36Sopenharmony_ci			     loff_t *ppos)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct chaoskey *dev;
41262306a36Sopenharmony_ci	ssize_t read_count = 0;
41362306a36Sopenharmony_ci	int this_time;
41462306a36Sopenharmony_ci	int result = 0;
41562306a36Sopenharmony_ci	unsigned long remain;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	dev = file->private_data;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (dev == NULL || !dev->present)
42062306a36Sopenharmony_ci		return -ENODEV;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	usb_dbg(dev->interface, "read %zu", count);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	while (count > 0) {
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		/* Grab the rng_lock briefly to ensure that the hwrng interface
42762306a36Sopenharmony_ci		 * gets priority over other user access
42862306a36Sopenharmony_ci		 */
42962306a36Sopenharmony_ci		result = mutex_lock_interruptible(&dev->rng_lock);
43062306a36Sopenharmony_ci		if (result)
43162306a36Sopenharmony_ci			goto bail;
43262306a36Sopenharmony_ci		mutex_unlock(&dev->rng_lock);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		result = mutex_lock_interruptible(&dev->lock);
43562306a36Sopenharmony_ci		if (result)
43662306a36Sopenharmony_ci			goto bail;
43762306a36Sopenharmony_ci		if (dev->valid == dev->used) {
43862306a36Sopenharmony_ci			result = _chaoskey_fill(dev);
43962306a36Sopenharmony_ci			if (result < 0) {
44062306a36Sopenharmony_ci				mutex_unlock(&dev->lock);
44162306a36Sopenharmony_ci				goto bail;
44262306a36Sopenharmony_ci			}
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		this_time = dev->valid - dev->used;
44662306a36Sopenharmony_ci		if (this_time > count)
44762306a36Sopenharmony_ci			this_time = count;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		remain = copy_to_user(buffer, dev->buf + dev->used, this_time);
45062306a36Sopenharmony_ci		if (remain) {
45162306a36Sopenharmony_ci			result = -EFAULT;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci			/* Consume the bytes that were copied so we don't leak
45462306a36Sopenharmony_ci			 * data to user space
45562306a36Sopenharmony_ci			 */
45662306a36Sopenharmony_ci			dev->used += this_time - remain;
45762306a36Sopenharmony_ci			mutex_unlock(&dev->lock);
45862306a36Sopenharmony_ci			goto bail;
45962306a36Sopenharmony_ci		}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		count -= this_time;
46262306a36Sopenharmony_ci		read_count += this_time;
46362306a36Sopenharmony_ci		buffer += this_time;
46462306a36Sopenharmony_ci		dev->used += this_time;
46562306a36Sopenharmony_ci		mutex_unlock(&dev->lock);
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_cibail:
46862306a36Sopenharmony_ci	if (read_count) {
46962306a36Sopenharmony_ci		usb_dbg(dev->interface, "read %zu bytes", read_count);
47062306a36Sopenharmony_ci		return read_count;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci	usb_dbg(dev->interface, "empty read, result %d", result);
47362306a36Sopenharmony_ci	if (result == -ETIMEDOUT)
47462306a36Sopenharmony_ci		result = -EAGAIN;
47562306a36Sopenharmony_ci	return result;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int chaoskey_rng_read(struct hwrng *rng, void *data,
47962306a36Sopenharmony_ci			     size_t max, bool wait)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	struct chaoskey *dev = container_of(rng, struct chaoskey, hwrng);
48262306a36Sopenharmony_ci	int this_time;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	usb_dbg(dev->interface, "rng_read max %zu wait %d", max, wait);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (!dev->present) {
48762306a36Sopenharmony_ci		usb_dbg(dev->interface, "device not present");
48862306a36Sopenharmony_ci		return 0;
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* Hold the rng_lock until we acquire the device lock so that
49262306a36Sopenharmony_ci	 * this operation gets priority over other user access to the
49362306a36Sopenharmony_ci	 * device
49462306a36Sopenharmony_ci	 */
49562306a36Sopenharmony_ci	mutex_lock(&dev->rng_lock);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	mutex_lock(&dev->lock);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	mutex_unlock(&dev->rng_lock);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* Try to fill the buffer if empty. It doesn't actually matter
50262306a36Sopenharmony_ci	 * if _chaoskey_fill works; we'll just return zero bytes as
50362306a36Sopenharmony_ci	 * the buffer will still be empty
50462306a36Sopenharmony_ci	 */
50562306a36Sopenharmony_ci	if (dev->valid == dev->used)
50662306a36Sopenharmony_ci		(void) _chaoskey_fill(dev);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	this_time = dev->valid - dev->used;
50962306a36Sopenharmony_ci	if (this_time > max)
51062306a36Sopenharmony_ci		this_time = max;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	memcpy(data, dev->buf + dev->used, this_time);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	dev->used += this_time;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	mutex_unlock(&dev->lock);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	usb_dbg(dev->interface, "rng_read this_time %d\n", this_time);
51962306a36Sopenharmony_ci	return this_time;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci#ifdef CONFIG_PM
52362306a36Sopenharmony_cistatic int chaoskey_suspend(struct usb_interface *interface,
52462306a36Sopenharmony_ci			    pm_message_t message)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	usb_dbg(interface, "suspend");
52762306a36Sopenharmony_ci	return 0;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic int chaoskey_resume(struct usb_interface *interface)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	struct chaoskey *dev;
53362306a36Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(interface);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	usb_dbg(interface, "resume");
53662306a36Sopenharmony_ci	dev = usb_get_intfdata(interface);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/*
53962306a36Sopenharmony_ci	 * We may have lost power.
54062306a36Sopenharmony_ci	 * In that case the device that needs a long time
54162306a36Sopenharmony_ci	 * for the first requests needs an extended timeout
54262306a36Sopenharmony_ci	 * again
54362306a36Sopenharmony_ci	 */
54462306a36Sopenharmony_ci	if (le16_to_cpu(udev->descriptor.idVendor) == ALEA_VENDOR_ID)
54562306a36Sopenharmony_ci		dev->reads_started = false;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	return 0;
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci#else
55062306a36Sopenharmony_ci#define chaoskey_suspend NULL
55162306a36Sopenharmony_ci#define chaoskey_resume NULL
55262306a36Sopenharmony_ci#endif
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/* file operation pointers */
55562306a36Sopenharmony_cistatic const struct file_operations chaoskey_fops = {
55662306a36Sopenharmony_ci	.owner = THIS_MODULE,
55762306a36Sopenharmony_ci	.read = chaoskey_read,
55862306a36Sopenharmony_ci	.open = chaoskey_open,
55962306a36Sopenharmony_ci	.release = chaoskey_release,
56062306a36Sopenharmony_ci	.llseek = default_llseek,
56162306a36Sopenharmony_ci};
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci/* class driver information */
56462306a36Sopenharmony_cistatic struct usb_class_driver chaoskey_class = {
56562306a36Sopenharmony_ci	.name = "chaoskey%d",
56662306a36Sopenharmony_ci	.fops = &chaoskey_fops,
56762306a36Sopenharmony_ci	.minor_base = USB_CHAOSKEY_MINOR_BASE,
56862306a36Sopenharmony_ci};
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci/* usb specific object needed to register this driver with the usb subsystem */
57162306a36Sopenharmony_cistatic struct usb_driver chaoskey_driver = {
57262306a36Sopenharmony_ci	.name = DRIVER_SHORT,
57362306a36Sopenharmony_ci	.probe = chaoskey_probe,
57462306a36Sopenharmony_ci	.disconnect = chaoskey_disconnect,
57562306a36Sopenharmony_ci	.suspend = chaoskey_suspend,
57662306a36Sopenharmony_ci	.resume = chaoskey_resume,
57762306a36Sopenharmony_ci	.reset_resume = chaoskey_resume,
57862306a36Sopenharmony_ci	.id_table = chaoskey_table,
57962306a36Sopenharmony_ci	.supports_autosuspend = 1,
58062306a36Sopenharmony_ci};
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cimodule_usb_driver(chaoskey_driver);
58362306a36Sopenharmony_ci
584