cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

onetouch.c (7802B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Support for the Maxtor OneTouch USB hard drive's button
      4 *
      5 * Current development and maintenance by:
      6 *	Copyright (c) 2005 Nick Sillik <n.sillik@temple.edu>
      7 *
      8 * Initial work by:
      9 *	Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se>
     10 *
     11 * Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann)
     12 *
     13 */
     14#include <linux/kernel.h>
     15#include <linux/input.h>
     16#include <linux/slab.h>
     17#include <linux/module.h>
     18#include <linux/usb/input.h>
     19#include "usb.h"
     20#include "debug.h"
     21#include "scsiglue.h"
     22
     23#define DRV_NAME "ums-onetouch"
     24
     25MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver");
     26MODULE_AUTHOR("Nick Sillik <n.sillik@temple.edu>");
     27MODULE_LICENSE("GPL");
     28MODULE_IMPORT_NS(USB_STORAGE);
     29
     30#define ONETOUCH_PKT_LEN        0x02
     31#define ONETOUCH_BUTTON         KEY_PROG1
     32
     33static int onetouch_connect_input(struct us_data *ss);
     34static void onetouch_release_input(void *onetouch_);
     35
     36struct usb_onetouch {
     37	char name[128];
     38	char phys[64];
     39	struct input_dev *dev;	/* input device interface */
     40	struct usb_device *udev;	/* usb device */
     41
     42	struct urb *irq;	/* urb for interrupt in report */
     43	unsigned char *data;	/* input data */
     44	dma_addr_t data_dma;
     45	unsigned int is_open:1;
     46};
     47
     48
     49/*
     50 * The table of devices
     51 */
     52#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
     53		    vendorName, productName, useProtocol, useTransport, \
     54		    initFunction, flags) \
     55{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
     56  .driver_info = (flags) }
     57
     58static struct usb_device_id onetouch_usb_ids[] = {
     59#	include "unusual_onetouch.h"
     60	{ }		/* Terminating entry */
     61};
     62MODULE_DEVICE_TABLE(usb, onetouch_usb_ids);
     63
     64#undef UNUSUAL_DEV
     65
     66/*
     67 * The flags table
     68 */
     69#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
     70		    vendor_name, product_name, use_protocol, use_transport, \
     71		    init_function, Flags) \
     72{ \
     73	.vendorName = vendor_name,	\
     74	.productName = product_name,	\
     75	.useProtocol = use_protocol,	\
     76	.useTransport = use_transport,	\
     77	.initFunction = init_function,	\
     78}
     79
     80static struct us_unusual_dev onetouch_unusual_dev_list[] = {
     81#	include "unusual_onetouch.h"
     82	{ }		/* Terminating entry */
     83};
     84
     85#undef UNUSUAL_DEV
     86
     87
     88static void usb_onetouch_irq(struct urb *urb)
     89{
     90	struct usb_onetouch *onetouch = urb->context;
     91	signed char *data = onetouch->data;
     92	struct input_dev *dev = onetouch->dev;
     93	int status = urb->status;
     94	int retval;
     95
     96	switch (status) {
     97	case 0:			/* success */
     98		break;
     99	case -ECONNRESET:	/* unlink */
    100	case -ENOENT:
    101	case -ESHUTDOWN:
    102		return;
    103	/* -EPIPE:  should clear the halt */
    104	default:		/* error */
    105		goto resubmit;
    106	}
    107
    108	input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02);
    109	input_sync(dev);
    110
    111resubmit:
    112	retval = usb_submit_urb (urb, GFP_ATOMIC);
    113	if (retval)
    114		dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, "
    115			"retval %d\n", onetouch->udev->bus->bus_name,
    116			onetouch->udev->devpath, retval);
    117}
    118
    119static int usb_onetouch_open(struct input_dev *dev)
    120{
    121	struct usb_onetouch *onetouch = input_get_drvdata(dev);
    122
    123	onetouch->is_open = 1;
    124	onetouch->irq->dev = onetouch->udev;
    125	if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
    126		dev_err(&dev->dev, "usb_submit_urb failed\n");
    127		return -EIO;
    128	}
    129
    130	return 0;
    131}
    132
    133static void usb_onetouch_close(struct input_dev *dev)
    134{
    135	struct usb_onetouch *onetouch = input_get_drvdata(dev);
    136
    137	usb_kill_urb(onetouch->irq);
    138	onetouch->is_open = 0;
    139}
    140
    141#ifdef CONFIG_PM
    142static void usb_onetouch_pm_hook(struct us_data *us, int action)
    143{
    144	struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra;
    145
    146	if (onetouch->is_open) {
    147		switch (action) {
    148		case US_SUSPEND:
    149			usb_kill_urb(onetouch->irq);
    150			break;
    151		case US_RESUME:
    152			if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0)
    153				dev_err(&onetouch->irq->dev->dev,
    154					"usb_submit_urb failed\n");
    155			break;
    156		default:
    157			break;
    158		}
    159	}
    160}
    161#endif /* CONFIG_PM */
    162
    163static int onetouch_connect_input(struct us_data *ss)
    164{
    165	struct usb_device *udev = ss->pusb_dev;
    166	struct usb_host_interface *interface;
    167	struct usb_endpoint_descriptor *endpoint;
    168	struct usb_onetouch *onetouch;
    169	struct input_dev *input_dev;
    170	int pipe, maxp;
    171	int error = -ENOMEM;
    172
    173	interface = ss->pusb_intf->cur_altsetting;
    174
    175	if (interface->desc.bNumEndpoints != 3)
    176		return -ENODEV;
    177
    178	endpoint = &interface->endpoint[2].desc;
    179	if (!usb_endpoint_is_int_in(endpoint))
    180		return -ENODEV;
    181
    182	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
    183	maxp = usb_maxpacket(udev, pipe);
    184	maxp = min(maxp, ONETOUCH_PKT_LEN);
    185
    186	onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL);
    187	input_dev = input_allocate_device();
    188	if (!onetouch || !input_dev)
    189		goto fail1;
    190
    191	onetouch->data = usb_alloc_coherent(udev, ONETOUCH_PKT_LEN,
    192					    GFP_KERNEL, &onetouch->data_dma);
    193	if (!onetouch->data)
    194		goto fail1;
    195
    196	onetouch->irq = usb_alloc_urb(0, GFP_KERNEL);
    197	if (!onetouch->irq)
    198		goto fail2;
    199
    200	onetouch->udev = udev;
    201	onetouch->dev = input_dev;
    202
    203	if (udev->manufacturer)
    204		strlcpy(onetouch->name, udev->manufacturer,
    205			sizeof(onetouch->name));
    206	if (udev->product) {
    207		if (udev->manufacturer)
    208			strlcat(onetouch->name, " ", sizeof(onetouch->name));
    209		strlcat(onetouch->name, udev->product, sizeof(onetouch->name));
    210	}
    211
    212	if (!strlen(onetouch->name))
    213		snprintf(onetouch->name, sizeof(onetouch->name),
    214			 "Maxtor Onetouch %04x:%04x",
    215			 le16_to_cpu(udev->descriptor.idVendor),
    216			 le16_to_cpu(udev->descriptor.idProduct));
    217
    218	usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys));
    219	strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys));
    220
    221	input_dev->name = onetouch->name;
    222	input_dev->phys = onetouch->phys;
    223	usb_to_input_id(udev, &input_dev->id);
    224	input_dev->dev.parent = &udev->dev;
    225
    226	set_bit(EV_KEY, input_dev->evbit);
    227	set_bit(ONETOUCH_BUTTON, input_dev->keybit);
    228	clear_bit(0, input_dev->keybit);
    229
    230	input_set_drvdata(input_dev, onetouch);
    231
    232	input_dev->open = usb_onetouch_open;
    233	input_dev->close = usb_onetouch_close;
    234
    235	usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp,
    236			 usb_onetouch_irq, onetouch, endpoint->bInterval);
    237	onetouch->irq->transfer_dma = onetouch->data_dma;
    238	onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    239
    240	ss->extra_destructor = onetouch_release_input;
    241	ss->extra = onetouch;
    242#ifdef CONFIG_PM
    243	ss->suspend_resume_hook = usb_onetouch_pm_hook;
    244#endif
    245
    246	error = input_register_device(onetouch->dev);
    247	if (error)
    248		goto fail3;
    249
    250	return 0;
    251
    252 fail3:	usb_free_urb(onetouch->irq);
    253 fail2:	usb_free_coherent(udev, ONETOUCH_PKT_LEN,
    254			  onetouch->data, onetouch->data_dma);
    255 fail1:	kfree(onetouch);
    256	input_free_device(input_dev);
    257	return error;
    258}
    259
    260static void onetouch_release_input(void *onetouch_)
    261{
    262	struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
    263
    264	if (onetouch) {
    265		usb_kill_urb(onetouch->irq);
    266		input_unregister_device(onetouch->dev);
    267		usb_free_urb(onetouch->irq);
    268		usb_free_coherent(onetouch->udev, ONETOUCH_PKT_LEN,
    269				  onetouch->data, onetouch->data_dma);
    270	}
    271}
    272
    273static struct scsi_host_template onetouch_host_template;
    274
    275static int onetouch_probe(struct usb_interface *intf,
    276			 const struct usb_device_id *id)
    277{
    278	struct us_data *us;
    279	int result;
    280
    281	result = usb_stor_probe1(&us, intf, id,
    282			(id - onetouch_usb_ids) + onetouch_unusual_dev_list,
    283			&onetouch_host_template);
    284	if (result)
    285		return result;
    286
    287	/* Use default transport and protocol */
    288
    289	result = usb_stor_probe2(us);
    290	return result;
    291}
    292
    293static struct usb_driver onetouch_driver = {
    294	.name =		DRV_NAME,
    295	.probe =	onetouch_probe,
    296	.disconnect =	usb_stor_disconnect,
    297	.suspend =	usb_stor_suspend,
    298	.resume =	usb_stor_resume,
    299	.reset_resume =	usb_stor_reset_resume,
    300	.pre_reset =	usb_stor_pre_reset,
    301	.post_reset =	usb_stor_post_reset,
    302	.id_table =	onetouch_usb_ids,
    303	.soft_unbind =	1,
    304	.no_dynamic_id = 1,
    305};
    306
    307module_usb_stor_driver(onetouch_driver, onetouch_host_template, DRV_NAME);