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