xref: /openbmc/linux/drivers/usb/class/usbtmc.c (revision 94d25e91)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
2aa37c246SLee Jones /*
3af901ca1SAndré Goddard Rosa  * drivers/usb/class/usbtmc.c - USB Test & Measurement class driver
45b775f67SGreg Kroah-Hartman  *
55b775f67SGreg Kroah-Hartman  * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
65b775f67SGreg Kroah-Hartman  * Copyright (C) 2008 Novell, Inc.
75b775f67SGreg Kroah-Hartman  * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
8658f24f4SGuido Kiener  * Copyright (C) 2018 IVI Foundation, Inc.
95b775f67SGreg Kroah-Hartman  */
105b775f67SGreg Kroah-Hartman 
11f4d844cbSAndy Shevchenko #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12f4d844cbSAndy Shevchenko 
135b775f67SGreg Kroah-Hartman #include <linux/module.h>
14857cc4dfSIlpo Järvinen #include <linux/kernel.h>
155b775f67SGreg Kroah-Hartman #include <linux/fs.h>
165b775f67SGreg Kroah-Hartman #include <linux/uaccess.h>
175b775f67SGreg Kroah-Hartman #include <linux/kref.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
19eb6b92ecSDave Penkler #include <linux/poll.h>
205b775f67SGreg Kroah-Hartman #include <linux/mutex.h>
215b775f67SGreg Kroah-Hartman #include <linux/usb.h>
2260207c8eSGuido Kiener #include <linux/compat.h>
235b775f67SGreg Kroah-Hartman #include <linux/usb/tmc.h>
245b775f67SGreg Kroah-Hartman 
25e013477bSGuido Kiener /* Increment API VERSION when changing tmc.h with new flags or ioctls
26e013477bSGuido Kiener  * or when changing a significant behavior of the driver.
27e013477bSGuido Kiener  */
28614b388cSDave Penkler #define USBTMC_API_VERSION (3)
295b775f67SGreg Kroah-Hartman 
308402db5dSAlexandre Peixoto Ferreira #define USBTMC_HEADER_SIZE	12
315b775f67SGreg Kroah-Hartman #define USBTMC_MINOR_BASE	176
325b775f67SGreg Kroah-Hartman 
33048c6d88SGuido Kiener /* Minimum USB timeout (in milliseconds) */
34048c6d88SGuido Kiener #define USBTMC_MIN_TIMEOUT	100
355b775f67SGreg Kroah-Hartman /* Default USB timeout (in milliseconds) */
3635f76e89SGergely Imreh #define USBTMC_TIMEOUT		5000
375b775f67SGreg Kroah-Hartman 
384ddc645fSGuido Kiener /* Max number of urbs used in write transfers */
394ddc645fSGuido Kiener #define MAX_URBS_IN_FLIGHT	16
40658f24f4SGuido Kiener /* I/O buffer size used in generic read/write functions */
41658f24f4SGuido Kiener #define USBTMC_BUFSIZE		(4096)
42658f24f4SGuido Kiener 
435b775f67SGreg Kroah-Hartman /*
445b775f67SGreg Kroah-Hartman  * Maximum number of read cycles to empty bulk in endpoint during CLEAR and
455b775f67SGreg Kroah-Hartman  * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short
465b775f67SGreg Kroah-Hartman  * packet is never read.
475b775f67SGreg Kroah-Hartman  */
485b775f67SGreg Kroah-Hartman #define USBTMC_MAX_READS_TO_CLEAR_BULK_IN	100
495b775f67SGreg Kroah-Hartman 
506ef4852bSNémeth Márton static const struct usb_device_id usbtmc_devices[] = {
515b775f67SGreg Kroah-Hartman 	{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), },
52228dd05dSGreg Kroah-Hartman 	{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), },
535b775f67SGreg Kroah-Hartman 	{ 0, } /* terminating entry */
545b775f67SGreg Kroah-Hartman };
555413aa46SGreg Kroah-Hartman MODULE_DEVICE_TABLE(usb, usbtmc_devices);
565b775f67SGreg Kroah-Hartman 
575b775f67SGreg Kroah-Hartman /*
585b775f67SGreg Kroah-Hartman  * This structure is the capabilities for the device
59d0a38365SGergely Imreh  * See section 4.2.1.8 of the USBTMC specification,
60d0a38365SGergely Imreh  * and section 4.2.2 of the USBTMC usb488 subclass
61d0a38365SGergely Imreh  * specification for details.
625b775f67SGreg Kroah-Hartman  */
635b775f67SGreg Kroah-Hartman struct usbtmc_dev_capabilities {
645b775f67SGreg Kroah-Hartman 	__u8 interface_capabilities;
655b775f67SGreg Kroah-Hartman 	__u8 device_capabilities;
665b775f67SGreg Kroah-Hartman 	__u8 usb488_interface_capabilities;
675b775f67SGreg Kroah-Hartman 	__u8 usb488_device_capabilities;
685b775f67SGreg Kroah-Hartman };
695b775f67SGreg Kroah-Hartman 
705b775f67SGreg Kroah-Hartman /* This structure holds private data for each USBTMC device. One copy is
715b775f67SGreg Kroah-Hartman  * allocated for each USBTMC device in the driver's probe function.
725b775f67SGreg Kroah-Hartman  */
735b775f67SGreg Kroah-Hartman struct usbtmc_device_data {
745b775f67SGreg Kroah-Hartman 	const struct usb_device_id *id;
755b775f67SGreg Kroah-Hartman 	struct usb_device *usb_dev;
765b775f67SGreg Kroah-Hartman 	struct usb_interface *intf;
774f3c8d6eSGuido Kiener 	struct list_head file_list;
785b775f67SGreg Kroah-Hartman 
795b775f67SGreg Kroah-Hartman 	unsigned int bulk_in;
805b775f67SGreg Kroah-Hartman 	unsigned int bulk_out;
815b775f67SGreg Kroah-Hartman 
825b775f67SGreg Kroah-Hartman 	u8 bTag;
835b775f67SGreg Kroah-Hartman 	u8 bTag_last_write;	/* needed for abort */
845b775f67SGreg Kroah-Hartman 	u8 bTag_last_read;	/* needed for abort */
855b775f67SGreg Kroah-Hartman 
86bb99794aSGuido Kiener 	/* packet size of IN bulk */
87bb99794aSGuido Kiener 	u16            wMaxPacketSize;
88bb99794aSGuido Kiener 
89dbf3e7f6SDave Penkler 	/* data for interrupt in endpoint handling */
90dbf3e7f6SDave Penkler 	u8             bNotify1;
91dbf3e7f6SDave Penkler 	u8             bNotify2;
92dbf3e7f6SDave Penkler 	u16            ifnum;
93dbf3e7f6SDave Penkler 	u8             iin_bTag;
94dbf3e7f6SDave Penkler 	u8            *iin_buffer;
95dbf3e7f6SDave Penkler 	atomic_t       iin_data_valid;
96dbf3e7f6SDave Penkler 	unsigned int   iin_ep;
97dbf3e7f6SDave Penkler 	int            iin_ep_present;
98dbf3e7f6SDave Penkler 	int            iin_interval;
99dbf3e7f6SDave Penkler 	struct urb    *iin_urb;
100dbf3e7f6SDave Penkler 	u16            iin_wMaxPacketSize;
101dbf3e7f6SDave Penkler 
10229779d89SDave Penkler 	/* coalesced usb488_caps from usbtmc_dev_capabilities */
10329779d89SDave Penkler 	__u8 usb488_caps;
10429779d89SDave Penkler 
10586286883SOliver Neukum 	bool zombie; /* fd of disconnected device */
10686286883SOliver Neukum 
1075b775f67SGreg Kroah-Hartman 	struct usbtmc_dev_capabilities	capabilities;
1085b775f67SGreg Kroah-Hartman 	struct kref kref;
1095b775f67SGreg Kroah-Hartman 	struct mutex io_mutex;	/* only one i/o function running at a time */
110dbf3e7f6SDave Penkler 	wait_queue_head_t waitq;
11182ed3381SDave Penkler 	struct fasync_struct *fasync;
1124f3c8d6eSGuido Kiener 	spinlock_t dev_lock; /* lock for file_list */
1135b775f67SGreg Kroah-Hartman };
1145b775f67SGreg Kroah-Hartman #define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
1155b775f67SGreg Kroah-Hartman 
1164f3c8d6eSGuido Kiener /*
1174f3c8d6eSGuido Kiener  * This structure holds private data for each USBTMC file handle.
1184f3c8d6eSGuido Kiener  */
1194f3c8d6eSGuido Kiener struct usbtmc_file_data {
1204f3c8d6eSGuido Kiener 	struct usbtmc_device_data *data;
1214f3c8d6eSGuido Kiener 	struct list_head file_elem;
1224f3c8d6eSGuido Kiener 
123048c6d88SGuido Kiener 	u32            timeout;
1244f3c8d6eSGuido Kiener 	u8             srq_byte;
1254f3c8d6eSGuido Kiener 	atomic_t       srq_asserted;
126739240a9SGuido Kiener 	atomic_t       closing;
1278409e96fSGuido Kiener 	u8             bmTransferAttributes; /* member of DEV_DEP_MSG_IN */
1284ddc645fSGuido Kiener 
129fbd83971SGuido Kiener 	u8             eom_val;
13012dcaeb7SGuido Kiener 	u8             term_char;
13112dcaeb7SGuido Kiener 	bool           term_char_enabled;
132ec34d08eSGuido Kiener 	bool           auto_abort;
1334ddc645fSGuido Kiener 
1344ddc645fSGuido Kiener 	spinlock_t     err_lock; /* lock for errors */
1354ddc645fSGuido Kiener 
1364ddc645fSGuido Kiener 	struct usb_anchor submitted;
1374ddc645fSGuido Kiener 
1384ddc645fSGuido Kiener 	/* data for generic_write */
1394ddc645fSGuido Kiener 	struct semaphore limit_write_sem;
1404ddc645fSGuido Kiener 	u32 out_transfer_size;
1414ddc645fSGuido Kiener 	int out_status;
142bb99794aSGuido Kiener 
143bb99794aSGuido Kiener 	/* data for generic_read */
144bb99794aSGuido Kiener 	u32 in_transfer_size;
145bb99794aSGuido Kiener 	int in_status;
146bb99794aSGuido Kiener 	int in_urbs_used;
147bb99794aSGuido Kiener 	struct usb_anchor in_anchor;
148bb99794aSGuido Kiener 	wait_queue_head_t wait_bulk_in;
1494f3c8d6eSGuido Kiener };
1504f3c8d6eSGuido Kiener 
1515b775f67SGreg Kroah-Hartman /* Forward declarations */
1525b775f67SGreg Kroah-Hartman static struct usb_driver usbtmc_driver;
1534ddc645fSGuido Kiener static void usbtmc_draw_down(struct usbtmc_file_data *file_data);
1545b775f67SGreg Kroah-Hartman 
usbtmc_delete(struct kref * kref)1555b775f67SGreg Kroah-Hartman static void usbtmc_delete(struct kref *kref)
1565b775f67SGreg Kroah-Hartman {
1575b775f67SGreg Kroah-Hartman 	struct usbtmc_device_data *data = to_usbtmc_data(kref);
1585b775f67SGreg Kroah-Hartman 
1595b775f67SGreg Kroah-Hartman 	usb_put_dev(data->usb_dev);
160ab21b63eSGreg Kroah-Hartman 	kfree(data);
1615b775f67SGreg Kroah-Hartman }
1625b775f67SGreg Kroah-Hartman 
usbtmc_open(struct inode * inode,struct file * filp)1635b775f67SGreg Kroah-Hartman static int usbtmc_open(struct inode *inode, struct file *filp)
1645b775f67SGreg Kroah-Hartman {
1655b775f67SGreg Kroah-Hartman 	struct usb_interface *intf;
1665b775f67SGreg Kroah-Hartman 	struct usbtmc_device_data *data;
1674f3c8d6eSGuido Kiener 	struct usbtmc_file_data *file_data;
1685b775f67SGreg Kroah-Hartman 
1695b775f67SGreg Kroah-Hartman 	intf = usb_find_interface(&usbtmc_driver, iminor(inode));
1705b775f67SGreg Kroah-Hartman 	if (!intf) {
171f4d844cbSAndy Shevchenko 		pr_err("can not find device for minor %d", iminor(inode));
172f4d844cbSAndy Shevchenko 		return -ENODEV;
1735b775f67SGreg Kroah-Hartman 	}
1745b775f67SGreg Kroah-Hartman 
1754f3c8d6eSGuido Kiener 	file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
1764f3c8d6eSGuido Kiener 	if (!file_data)
1774f3c8d6eSGuido Kiener 		return -ENOMEM;
1784f3c8d6eSGuido Kiener 
1794ddc645fSGuido Kiener 	spin_lock_init(&file_data->err_lock);
1804ddc645fSGuido Kiener 	sema_init(&file_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
1814ddc645fSGuido Kiener 	init_usb_anchor(&file_data->submitted);
182bb99794aSGuido Kiener 	init_usb_anchor(&file_data->in_anchor);
183bb99794aSGuido Kiener 	init_waitqueue_head(&file_data->wait_bulk_in);
1844ddc645fSGuido Kiener 
1855b775f67SGreg Kroah-Hartman 	data = usb_get_intfdata(intf);
18688aecde4SDave Penkler 	/* Protect reference to data from file structure until release */
1875b775f67SGreg Kroah-Hartman 	kref_get(&data->kref);
1885b775f67SGreg Kroah-Hartman 
1894f3c8d6eSGuido Kiener 	mutex_lock(&data->io_mutex);
1904f3c8d6eSGuido Kiener 	file_data->data = data;
1915b775f67SGreg Kroah-Hartman 
192739240a9SGuido Kiener 	atomic_set(&file_data->closing, 0);
193739240a9SGuido Kiener 
194048c6d88SGuido Kiener 	file_data->timeout = USBTMC_TIMEOUT;
195b32abf8fSGuido Kiener 	file_data->term_char = '\n';
196b32abf8fSGuido Kiener 	file_data->term_char_enabled = 0;
197b32abf8fSGuido Kiener 	file_data->auto_abort = 0;
198fbd83971SGuido Kiener 	file_data->eom_val = 1;
199048c6d88SGuido Kiener 
2004f3c8d6eSGuido Kiener 	INIT_LIST_HEAD(&file_data->file_elem);
2014f3c8d6eSGuido Kiener 	spin_lock_irq(&data->dev_lock);
2024f3c8d6eSGuido Kiener 	list_add_tail(&file_data->file_elem, &data->file_list);
2034f3c8d6eSGuido Kiener 	spin_unlock_irq(&data->dev_lock);
2044f3c8d6eSGuido Kiener 	mutex_unlock(&data->io_mutex);
2054f3c8d6eSGuido Kiener 
2064f3c8d6eSGuido Kiener 	/* Store pointer in file structure's private data field */
2074f3c8d6eSGuido Kiener 	filp->private_data = file_data;
2084f3c8d6eSGuido Kiener 
2094f3c8d6eSGuido Kiener 	return 0;
2105b775f67SGreg Kroah-Hartman }
2115b775f67SGreg Kroah-Hartman 
2124ddc645fSGuido Kiener /*
2134ddc645fSGuido Kiener  * usbtmc_flush - called before file handle is closed
2144ddc645fSGuido Kiener  */
usbtmc_flush(struct file * file,fl_owner_t id)2154ddc645fSGuido Kiener static int usbtmc_flush(struct file *file, fl_owner_t id)
2164ddc645fSGuido Kiener {
2174ddc645fSGuido Kiener 	struct usbtmc_file_data *file_data;
2184ddc645fSGuido Kiener 	struct usbtmc_device_data *data;
2194ddc645fSGuido Kiener 
2204ddc645fSGuido Kiener 	file_data = file->private_data;
2214ddc645fSGuido Kiener 	if (file_data == NULL)
2224ddc645fSGuido Kiener 		return -ENODEV;
2234ddc645fSGuido Kiener 
224739240a9SGuido Kiener 	atomic_set(&file_data->closing, 1);
2254ddc645fSGuido Kiener 	data = file_data->data;
2264ddc645fSGuido Kiener 
2274ddc645fSGuido Kiener 	/* wait for io to stop */
2284ddc645fSGuido Kiener 	mutex_lock(&data->io_mutex);
2294ddc645fSGuido Kiener 
2304ddc645fSGuido Kiener 	usbtmc_draw_down(file_data);
2314ddc645fSGuido Kiener 
2324ddc645fSGuido Kiener 	spin_lock_irq(&file_data->err_lock);
233bb99794aSGuido Kiener 	file_data->in_status = 0;
234bb99794aSGuido Kiener 	file_data->in_transfer_size = 0;
235bb99794aSGuido Kiener 	file_data->in_urbs_used = 0;
2364ddc645fSGuido Kiener 	file_data->out_status = 0;
2374ddc645fSGuido Kiener 	file_data->out_transfer_size = 0;
2384ddc645fSGuido Kiener 	spin_unlock_irq(&file_data->err_lock);
2394ddc645fSGuido Kiener 
2404ddc645fSGuido Kiener 	wake_up_interruptible_all(&data->waitq);
2414ddc645fSGuido Kiener 	mutex_unlock(&data->io_mutex);
2424ddc645fSGuido Kiener 
2434ddc645fSGuido Kiener 	return 0;
2444ddc645fSGuido Kiener }
2454ddc645fSGuido Kiener 
usbtmc_release(struct inode * inode,struct file * file)2465b775f67SGreg Kroah-Hartman static int usbtmc_release(struct inode *inode, struct file *file)
2475b775f67SGreg Kroah-Hartman {
2484f3c8d6eSGuido Kiener 	struct usbtmc_file_data *file_data = file->private_data;
2495b775f67SGreg Kroah-Hartman 
2504f3c8d6eSGuido Kiener 	/* prevent IO _AND_ usbtmc_interrupt */
2514f3c8d6eSGuido Kiener 	mutex_lock(&file_data->data->io_mutex);
2524f3c8d6eSGuido Kiener 	spin_lock_irq(&file_data->data->dev_lock);
2534f3c8d6eSGuido Kiener 
2544f3c8d6eSGuido Kiener 	list_del(&file_data->file_elem);
2554f3c8d6eSGuido Kiener 
2564f3c8d6eSGuido Kiener 	spin_unlock_irq(&file_data->data->dev_lock);
2574f3c8d6eSGuido Kiener 	mutex_unlock(&file_data->data->io_mutex);
2584f3c8d6eSGuido Kiener 
2594f3c8d6eSGuido Kiener 	kref_put(&file_data->data->kref, usbtmc_delete);
2604f3c8d6eSGuido Kiener 	file_data->data = NULL;
2614f3c8d6eSGuido Kiener 	kfree(file_data);
2625b775f67SGreg Kroah-Hartman 	return 0;
2635b775f67SGreg Kroah-Hartman }
2645b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data * data,u8 tag)265cbe743f1SGuido Kiener static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data,
266cbe743f1SGuido Kiener 					  u8 tag)
2675b775f67SGreg Kroah-Hartman {
268b361a6e3SChris Malley 	u8 *buffer;
2695b775f67SGreg Kroah-Hartman 	struct device *dev;
2705b775f67SGreg Kroah-Hartman 	int rv;
2715b775f67SGreg Kroah-Hartman 	int n;
2725b775f67SGreg Kroah-Hartman 	int actual;
2735b775f67SGreg Kroah-Hartman 
2745b775f67SGreg Kroah-Hartman 	dev = &data->intf->dev;
275cbe743f1SGuido Kiener 	buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
2765b775f67SGreg Kroah-Hartman 	if (!buffer)
2775b775f67SGreg Kroah-Hartman 		return -ENOMEM;
2785b775f67SGreg Kroah-Hartman 
2795b775f67SGreg Kroah-Hartman 	rv = usb_control_msg(data->usb_dev,
2805b775f67SGreg Kroah-Hartman 			     usb_rcvctrlpipe(data->usb_dev, 0),
2815b775f67SGreg Kroah-Hartman 			     USBTMC_REQUEST_INITIATE_ABORT_BULK_IN,
2825b775f67SGreg Kroah-Hartman 			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
283cbe743f1SGuido Kiener 			     tag, data->bulk_in,
284cbe743f1SGuido Kiener 			     buffer, 2, USB_CTRL_GET_TIMEOUT);
2855b775f67SGreg Kroah-Hartman 
2865b775f67SGreg Kroah-Hartman 	if (rv < 0) {
2875b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_control_msg returned %d\n", rv);
2885b775f67SGreg Kroah-Hartman 		goto exit;
2895b775f67SGreg Kroah-Hartman 	}
2905b775f67SGreg Kroah-Hartman 
291cbe743f1SGuido Kiener 	dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n",
292cbe743f1SGuido Kiener 		buffer[0], buffer[1]);
2935b775f67SGreg Kroah-Hartman 
2945b775f67SGreg Kroah-Hartman 	if (buffer[0] == USBTMC_STATUS_FAILED) {
295cbe743f1SGuido Kiener 		/* No transfer in progress and the Bulk-OUT FIFO is empty. */
2965b775f67SGreg Kroah-Hartman 		rv = 0;
2975b775f67SGreg Kroah-Hartman 		goto exit;
2985b775f67SGreg Kroah-Hartman 	}
2995b775f67SGreg Kroah-Hartman 
300cbe743f1SGuido Kiener 	if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) {
301cbe743f1SGuido Kiener 		/* The device returns this status if either:
302cbe743f1SGuido Kiener 		 * - There is a transfer in progress, but the specified bTag
303cbe743f1SGuido Kiener 		 *   does not match.
304cbe743f1SGuido Kiener 		 * - There is no transfer in progress, but the Bulk-OUT FIFO
305cbe743f1SGuido Kiener 		 *   is not empty.
306cbe743f1SGuido Kiener 		 */
307cbe743f1SGuido Kiener 		rv = -ENOMSG;
308cbe743f1SGuido Kiener 		goto exit;
309cbe743f1SGuido Kiener 	}
310cbe743f1SGuido Kiener 
3115b775f67SGreg Kroah-Hartman 	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
3125b775f67SGreg Kroah-Hartman 		dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
3135b775f67SGreg Kroah-Hartman 			buffer[0]);
3145b775f67SGreg Kroah-Hartman 		rv = -EPERM;
3155b775f67SGreg Kroah-Hartman 		goto exit;
3165b775f67SGreg Kroah-Hartman 	}
3175b775f67SGreg Kroah-Hartman 
3185b775f67SGreg Kroah-Hartman 	n = 0;
3195b775f67SGreg Kroah-Hartman 
320cbe743f1SGuido Kiener usbtmc_abort_bulk_in_status:
3215b775f67SGreg Kroah-Hartman 	dev_dbg(dev, "Reading from bulk in EP\n");
3225b775f67SGreg Kroah-Hartman 
323cbe743f1SGuido Kiener 	/* Data must be present. So use low timeout 300 ms */
3242e32188aSGuido Kiener 	actual = 0;
3255b775f67SGreg Kroah-Hartman 	rv = usb_bulk_msg(data->usb_dev,
3265b775f67SGreg Kroah-Hartman 			  usb_rcvbulkpipe(data->usb_dev,
3275b775f67SGreg Kroah-Hartman 					  data->bulk_in),
328cbe743f1SGuido Kiener 			  buffer, USBTMC_BUFSIZE,
329cbe743f1SGuido Kiener 			  &actual, 300);
330cbe743f1SGuido Kiener 
331cbe743f1SGuido Kiener 	print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1,
332cbe743f1SGuido Kiener 			     buffer, actual, true);
3335b775f67SGreg Kroah-Hartman 
3345b775f67SGreg Kroah-Hartman 	n++;
3355b775f67SGreg Kroah-Hartman 
3365b775f67SGreg Kroah-Hartman 	if (rv < 0) {
3375b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_bulk_msg returned %d\n", rv);
338cbe743f1SGuido Kiener 		if (rv != -ETIMEDOUT)
3395b775f67SGreg Kroah-Hartman 			goto exit;
3405b775f67SGreg Kroah-Hartman 	}
3415b775f67SGreg Kroah-Hartman 
342cbe743f1SGuido Kiener 	if (actual == USBTMC_BUFSIZE)
343cbe743f1SGuido Kiener 		goto usbtmc_abort_bulk_in_status;
344cbe743f1SGuido Kiener 
345cbe743f1SGuido Kiener 	if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) {
3465b775f67SGreg Kroah-Hartman 		dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
3475b775f67SGreg Kroah-Hartman 			USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
3485b775f67SGreg Kroah-Hartman 		rv = -EPERM;
3495b775f67SGreg Kroah-Hartman 		goto exit;
3505b775f67SGreg Kroah-Hartman 	}
3515b775f67SGreg Kroah-Hartman 
3525b775f67SGreg Kroah-Hartman 	rv = usb_control_msg(data->usb_dev,
3535b775f67SGreg Kroah-Hartman 			     usb_rcvctrlpipe(data->usb_dev, 0),
3545b775f67SGreg Kroah-Hartman 			     USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS,
3555b775f67SGreg Kroah-Hartman 			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
3565b775f67SGreg Kroah-Hartman 			     0, data->bulk_in, buffer, 0x08,
357cbe743f1SGuido Kiener 			     USB_CTRL_GET_TIMEOUT);
3585b775f67SGreg Kroah-Hartman 
3595b775f67SGreg Kroah-Hartman 	if (rv < 0) {
3605b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_control_msg returned %d\n", rv);
3615b775f67SGreg Kroah-Hartman 		goto exit;
3625b775f67SGreg Kroah-Hartman 	}
3635b775f67SGreg Kroah-Hartman 
364cbe743f1SGuido Kiener 	dev_dbg(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]);
3655b775f67SGreg Kroah-Hartman 
3665b775f67SGreg Kroah-Hartman 	if (buffer[0] == USBTMC_STATUS_SUCCESS) {
3675b775f67SGreg Kroah-Hartman 		rv = 0;
3685b775f67SGreg Kroah-Hartman 		goto exit;
3695b775f67SGreg Kroah-Hartman 	}
3705b775f67SGreg Kroah-Hartman 
3715b775f67SGreg Kroah-Hartman 	if (buffer[0] != USBTMC_STATUS_PENDING) {
372cbe743f1SGuido Kiener 		dev_err(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]);
3735b775f67SGreg Kroah-Hartman 		rv = -EPERM;
3745b775f67SGreg Kroah-Hartman 		goto exit;
3755b775f67SGreg Kroah-Hartman 	}
3765b775f67SGreg Kroah-Hartman 
377cbe743f1SGuido Kiener 	if ((buffer[1] & 1) > 0) {
378cbe743f1SGuido Kiener 		/* The device has 1 or more queued packets the Host can read */
3795b775f67SGreg Kroah-Hartman 		goto usbtmc_abort_bulk_in_status;
380cbe743f1SGuido Kiener 	}
3815b775f67SGreg Kroah-Hartman 
382cbe743f1SGuido Kiener 	/* The Host must send CHECK_ABORT_BULK_IN_STATUS at a later time. */
383cbe743f1SGuido Kiener 	rv = -EAGAIN;
3845b775f67SGreg Kroah-Hartman exit:
3855b775f67SGreg Kroah-Hartman 	kfree(buffer);
3865b775f67SGreg Kroah-Hartman 	return rv;
387cbe743f1SGuido Kiener }
3885b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data * data)389cbe743f1SGuido Kiener static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
390cbe743f1SGuido Kiener {
391cbe743f1SGuido Kiener 	return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read);
3925b775f67SGreg Kroah-Hartman }
3935b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data * data,u8 tag)3940e59088eSGuido Kiener static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data,
3950e59088eSGuido Kiener 					   u8 tag)
3965b775f67SGreg Kroah-Hartman {
3975b775f67SGreg Kroah-Hartman 	struct device *dev;
3985b775f67SGreg Kroah-Hartman 	u8 *buffer;
3995b775f67SGreg Kroah-Hartman 	int rv;
4005b775f67SGreg Kroah-Hartman 	int n;
4015b775f67SGreg Kroah-Hartman 
4025b775f67SGreg Kroah-Hartman 	dev = &data->intf->dev;
4035b775f67SGreg Kroah-Hartman 
4045b775f67SGreg Kroah-Hartman 	buffer = kmalloc(8, GFP_KERNEL);
4055b775f67SGreg Kroah-Hartman 	if (!buffer)
4065b775f67SGreg Kroah-Hartman 		return -ENOMEM;
4075b775f67SGreg Kroah-Hartman 
4085b775f67SGreg Kroah-Hartman 	rv = usb_control_msg(data->usb_dev,
4095b775f67SGreg Kroah-Hartman 			     usb_rcvctrlpipe(data->usb_dev, 0),
4105b775f67SGreg Kroah-Hartman 			     USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT,
4115b775f67SGreg Kroah-Hartman 			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
4120e59088eSGuido Kiener 			     tag, data->bulk_out,
4130e59088eSGuido Kiener 			     buffer, 2, USB_CTRL_GET_TIMEOUT);
4145b775f67SGreg Kroah-Hartman 
4155b775f67SGreg Kroah-Hartman 	if (rv < 0) {
4165b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_control_msg returned %d\n", rv);
4175b775f67SGreg Kroah-Hartman 		goto exit;
4185b775f67SGreg Kroah-Hartman 	}
4195b775f67SGreg Kroah-Hartman 
4205b775f67SGreg Kroah-Hartman 	dev_dbg(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", buffer[0]);
4215b775f67SGreg Kroah-Hartman 
4225b775f67SGreg Kroah-Hartman 	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
4235b775f67SGreg Kroah-Hartman 		dev_err(dev, "INITIATE_ABORT_BULK_OUT returned %x\n",
4245b775f67SGreg Kroah-Hartman 			buffer[0]);
4255b775f67SGreg Kroah-Hartman 		rv = -EPERM;
4265b775f67SGreg Kroah-Hartman 		goto exit;
4275b775f67SGreg Kroah-Hartman 	}
4285b775f67SGreg Kroah-Hartman 
4295b775f67SGreg Kroah-Hartman 	n = 0;
4305b775f67SGreg Kroah-Hartman 
4315b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_check_status:
4320e59088eSGuido Kiener 	/* do not stress device with subsequent requests */
4330e59088eSGuido Kiener 	msleep(50);
4345b775f67SGreg Kroah-Hartman 	rv = usb_control_msg(data->usb_dev,
4355b775f67SGreg Kroah-Hartman 			     usb_rcvctrlpipe(data->usb_dev, 0),
4365b775f67SGreg Kroah-Hartman 			     USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS,
4375b775f67SGreg Kroah-Hartman 			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
4385b775f67SGreg Kroah-Hartman 			     0, data->bulk_out, buffer, 0x08,
4390e59088eSGuido Kiener 			     USB_CTRL_GET_TIMEOUT);
4405b775f67SGreg Kroah-Hartman 	n++;
4415b775f67SGreg Kroah-Hartman 	if (rv < 0) {
4425b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_control_msg returned %d\n", rv);
4435b775f67SGreg Kroah-Hartman 		goto exit;
4445b775f67SGreg Kroah-Hartman 	}
4455b775f67SGreg Kroah-Hartman 
4465b775f67SGreg Kroah-Hartman 	dev_dbg(dev, "CHECK_ABORT_BULK_OUT returned %x\n", buffer[0]);
4475b775f67SGreg Kroah-Hartman 
4485b775f67SGreg Kroah-Hartman 	if (buffer[0] == USBTMC_STATUS_SUCCESS)
4495b775f67SGreg Kroah-Hartman 		goto usbtmc_abort_bulk_out_clear_halt;
4505b775f67SGreg Kroah-Hartman 
4515b775f67SGreg Kroah-Hartman 	if ((buffer[0] == USBTMC_STATUS_PENDING) &&
4525b775f67SGreg Kroah-Hartman 	    (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN))
4535b775f67SGreg Kroah-Hartman 		goto usbtmc_abort_bulk_out_check_status;
4545b775f67SGreg Kroah-Hartman 
4555b775f67SGreg Kroah-Hartman 	rv = -EPERM;
4565b775f67SGreg Kroah-Hartman 	goto exit;
4575b775f67SGreg Kroah-Hartman 
4585b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_clear_halt:
4593342ecdaSSarah Sharp 	rv = usb_clear_halt(data->usb_dev,
4603342ecdaSSarah Sharp 			    usb_sndbulkpipe(data->usb_dev, data->bulk_out));
4615b775f67SGreg Kroah-Hartman 
4625b775f67SGreg Kroah-Hartman 	if (rv < 0) {
4635b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_control_msg returned %d\n", rv);
4645b775f67SGreg Kroah-Hartman 		goto exit;
4655b775f67SGreg Kroah-Hartman 	}
4665b775f67SGreg Kroah-Hartman 	rv = 0;
4675b775f67SGreg Kroah-Hartman 
4685b775f67SGreg Kroah-Hartman exit:
4695b775f67SGreg Kroah-Hartman 	kfree(buffer);
4705b775f67SGreg Kroah-Hartman 	return rv;
4715b775f67SGreg Kroah-Hartman }
4725b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data * data)4730e59088eSGuido Kiener static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
4740e59088eSGuido Kiener {
4750e59088eSGuido Kiener 	return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write);
4760e59088eSGuido Kiener }
4770e59088eSGuido Kiener 
usbtmc_get_stb(struct usbtmc_file_data * file_data,__u8 * stb)4783c1037e2SDave Penkler static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb)
479dbf3e7f6SDave Penkler {
4804f3c8d6eSGuido Kiener 	struct usbtmc_device_data *data = file_data->data;
481dbf3e7f6SDave Penkler 	struct device *dev = &data->intf->dev;
482dbf3e7f6SDave Penkler 	u8 *buffer;
483dbf3e7f6SDave Penkler 	u8 tag;
484dbf3e7f6SDave Penkler 	int rv;
485dbf3e7f6SDave Penkler 
486dbf3e7f6SDave Penkler 	dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
487dbf3e7f6SDave Penkler 		data->iin_ep_present);
488dbf3e7f6SDave Penkler 
489dbf3e7f6SDave Penkler 	buffer = kmalloc(8, GFP_KERNEL);
490dbf3e7f6SDave Penkler 	if (!buffer)
491dbf3e7f6SDave Penkler 		return -ENOMEM;
492dbf3e7f6SDave Penkler 
493dbf3e7f6SDave Penkler 	atomic_set(&data->iin_data_valid, 0);
494dbf3e7f6SDave Penkler 
495dbf3e7f6SDave Penkler 	rv = usb_control_msg(data->usb_dev,
496dbf3e7f6SDave Penkler 			usb_rcvctrlpipe(data->usb_dev, 0),
497dbf3e7f6SDave Penkler 			USBTMC488_REQUEST_READ_STATUS_BYTE,
498dbf3e7f6SDave Penkler 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
499dbf3e7f6SDave Penkler 			data->iin_bTag,
500dbf3e7f6SDave Penkler 			data->ifnum,
50163c97bbaSGuido Kiener 			buffer, 0x03, USB_CTRL_GET_TIMEOUT);
502dbf3e7f6SDave Penkler 	if (rv < 0) {
503dbf3e7f6SDave Penkler 		dev_err(dev, "stb usb_control_msg returned %d\n", rv);
504dbf3e7f6SDave Penkler 		goto exit;
505dbf3e7f6SDave Penkler 	}
506dbf3e7f6SDave Penkler 
507dbf3e7f6SDave Penkler 	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
508dbf3e7f6SDave Penkler 		dev_err(dev, "control status returned %x\n", buffer[0]);
509dbf3e7f6SDave Penkler 		rv = -EIO;
510dbf3e7f6SDave Penkler 		goto exit;
511dbf3e7f6SDave Penkler 	}
512dbf3e7f6SDave Penkler 
513dbf3e7f6SDave Penkler 	if (data->iin_ep_present) {
514dbf3e7f6SDave Penkler 		rv = wait_event_interruptible_timeout(
515dbf3e7f6SDave Penkler 			data->waitq,
516dbf3e7f6SDave Penkler 			atomic_read(&data->iin_data_valid) != 0,
517048c6d88SGuido Kiener 			file_data->timeout);
518dbf3e7f6SDave Penkler 		if (rv < 0) {
519dbf3e7f6SDave Penkler 			dev_dbg(dev, "wait interrupted %d\n", rv);
520dbf3e7f6SDave Penkler 			goto exit;
521dbf3e7f6SDave Penkler 		}
522dbf3e7f6SDave Penkler 
523dbf3e7f6SDave Penkler 		if (rv == 0) {
524dbf3e7f6SDave Penkler 			dev_dbg(dev, "wait timed out\n");
52519e6c57eSGuido Kiener 			rv = -ETIMEDOUT;
526dbf3e7f6SDave Penkler 			goto exit;
527dbf3e7f6SDave Penkler 		}
528dbf3e7f6SDave Penkler 
529dbf3e7f6SDave Penkler 		tag = data->bNotify1 & 0x7f;
530dbf3e7f6SDave Penkler 		if (tag != data->iin_bTag) {
531dbf3e7f6SDave Penkler 			dev_err(dev, "expected bTag %x got %x\n",
532dbf3e7f6SDave Penkler 				data->iin_bTag, tag);
533dbf3e7f6SDave Penkler 		}
534dbf3e7f6SDave Penkler 
5353c1037e2SDave Penkler 		*stb = data->bNotify2;
536dbf3e7f6SDave Penkler 	} else {
5373c1037e2SDave Penkler 		*stb = buffer[2];
538dbf3e7f6SDave Penkler 	}
539dbf3e7f6SDave Penkler 
5403c1037e2SDave Penkler 	dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)*stb, rv);
541dbf3e7f6SDave Penkler 
542dbf3e7f6SDave Penkler  exit:
543dbf3e7f6SDave Penkler 	/* bump interrupt bTag */
544dbf3e7f6SDave Penkler 	data->iin_bTag += 1;
545dbf3e7f6SDave Penkler 	if (data->iin_bTag > 127)
546dbf3e7f6SDave Penkler 		/* 1 is for SRQ see USBTMC-USB488 subclass spec section 4.3.1 */
547dbf3e7f6SDave Penkler 		data->iin_bTag = 2;
548dbf3e7f6SDave Penkler 
549dbf3e7f6SDave Penkler 	kfree(buffer);
550dbf3e7f6SDave Penkler 	return rv;
551dbf3e7f6SDave Penkler }
552dbf3e7f6SDave Penkler 
usbtmc488_ioctl_read_stb(struct usbtmc_file_data * file_data,void __user * arg)5533c1037e2SDave Penkler static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
5543c1037e2SDave Penkler 				void __user *arg)
5553c1037e2SDave Penkler {
5563c1037e2SDave Penkler 	int srq_asserted = 0;
5573c1037e2SDave Penkler 	__u8 stb;
5583c1037e2SDave Penkler 	int rv;
5593c1037e2SDave Penkler 
5603c1037e2SDave Penkler 	rv = usbtmc_get_stb(file_data, &stb);
5613c1037e2SDave Penkler 
5623c1037e2SDave Penkler 	if (rv > 0) {
5633c1037e2SDave Penkler 		srq_asserted = atomic_xchg(&file_data->srq_asserted,
5643c1037e2SDave Penkler 					srq_asserted);
5653c1037e2SDave Penkler 		if (srq_asserted)
5663c1037e2SDave Penkler 			stb |= 0x40; /* Set RQS bit */
5673c1037e2SDave Penkler 
5683c1037e2SDave Penkler 		rv = put_user(stb, (__u8 __user *)arg);
5693c1037e2SDave Penkler 	}
5703c1037e2SDave Penkler 	return rv;
5713c1037e2SDave Penkler 
5723c1037e2SDave Penkler }
5733c1037e2SDave Penkler 
usbtmc_ioctl_get_srq_stb(struct usbtmc_file_data * file_data,void __user * arg)574d1d9defdSDave Penkler static int usbtmc_ioctl_get_srq_stb(struct usbtmc_file_data *file_data,
575d1d9defdSDave Penkler 				void __user *arg)
576d1d9defdSDave Penkler {
577d1d9defdSDave Penkler 	struct usbtmc_device_data *data = file_data->data;
578d1d9defdSDave Penkler 	struct device *dev = &data->intf->dev;
579d1d9defdSDave Penkler 	int srq_asserted = 0;
580d1d9defdSDave Penkler 	__u8 stb = 0;
581d1d9defdSDave Penkler 	int rv;
582d1d9defdSDave Penkler 
583d1d9defdSDave Penkler 	spin_lock_irq(&data->dev_lock);
584d1d9defdSDave Penkler 	srq_asserted  = atomic_xchg(&file_data->srq_asserted, srq_asserted);
585d1d9defdSDave Penkler 
586d1d9defdSDave Penkler 	if (srq_asserted) {
587d1d9defdSDave Penkler 		stb = file_data->srq_byte;
588d1d9defdSDave Penkler 		spin_unlock_irq(&data->dev_lock);
589d1d9defdSDave Penkler 		rv = put_user(stb, (__u8 __user *)arg);
590d1d9defdSDave Penkler 	} else {
591d1d9defdSDave Penkler 		spin_unlock_irq(&data->dev_lock);
592d1d9defdSDave Penkler 		rv = -ENOMSG;
593d1d9defdSDave Penkler 	}
594d1d9defdSDave Penkler 
595d1d9defdSDave Penkler 	dev_dbg(dev, "stb:0x%02x with srq received %d\n", (unsigned int)stb, rv);
596d1d9defdSDave Penkler 
597d1d9defdSDave Penkler 	return rv;
598d1d9defdSDave Penkler }
599d1d9defdSDave Penkler 
usbtmc488_ioctl_wait_srq(struct usbtmc_file_data * file_data,__u32 __user * arg)600739240a9SGuido Kiener static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data,
601739240a9SGuido Kiener 				    __u32 __user *arg)
602739240a9SGuido Kiener {
603739240a9SGuido Kiener 	struct usbtmc_device_data *data = file_data->data;
604739240a9SGuido Kiener 	struct device *dev = &data->intf->dev;
605739240a9SGuido Kiener 	int rv;
606739240a9SGuido Kiener 	u32 timeout;
607739240a9SGuido Kiener 	unsigned long expire;
608739240a9SGuido Kiener 
609739240a9SGuido Kiener 	if (!data->iin_ep_present) {
610739240a9SGuido Kiener 		dev_dbg(dev, "no interrupt endpoint present\n");
611739240a9SGuido Kiener 		return -EFAULT;
612739240a9SGuido Kiener 	}
613739240a9SGuido Kiener 
614739240a9SGuido Kiener 	if (get_user(timeout, arg))
615739240a9SGuido Kiener 		return -EFAULT;
616739240a9SGuido Kiener 
617739240a9SGuido Kiener 	expire = msecs_to_jiffies(timeout);
618739240a9SGuido Kiener 
619739240a9SGuido Kiener 	mutex_unlock(&data->io_mutex);
620739240a9SGuido Kiener 
621739240a9SGuido Kiener 	rv = wait_event_interruptible_timeout(
622739240a9SGuido Kiener 			data->waitq,
623739240a9SGuido Kiener 			atomic_read(&file_data->srq_asserted) != 0 ||
624739240a9SGuido Kiener 			atomic_read(&file_data->closing),
625739240a9SGuido Kiener 			expire);
626739240a9SGuido Kiener 
627739240a9SGuido Kiener 	mutex_lock(&data->io_mutex);
628739240a9SGuido Kiener 
629739240a9SGuido Kiener 	/* Note! disconnect or close could be called in the meantime */
630739240a9SGuido Kiener 	if (atomic_read(&file_data->closing) || data->zombie)
631739240a9SGuido Kiener 		rv = -ENODEV;
632739240a9SGuido Kiener 
633739240a9SGuido Kiener 	if (rv < 0) {
634739240a9SGuido Kiener 		/* dev can be invalid now! */
635739240a9SGuido Kiener 		pr_debug("%s - wait interrupted %d\n", __func__, rv);
636739240a9SGuido Kiener 		return rv;
637739240a9SGuido Kiener 	}
638739240a9SGuido Kiener 
639739240a9SGuido Kiener 	if (rv == 0) {
640739240a9SGuido Kiener 		dev_dbg(dev, "%s - wait timed out\n", __func__);
641739240a9SGuido Kiener 		return -ETIMEDOUT;
642739240a9SGuido Kiener 	}
643739240a9SGuido Kiener 
644739240a9SGuido Kiener 	dev_dbg(dev, "%s - srq asserted\n", __func__);
645739240a9SGuido Kiener 	return 0;
646739240a9SGuido Kiener }
647739240a9SGuido Kiener 
usbtmc488_ioctl_simple(struct usbtmc_device_data * data,void __user * arg,unsigned int cmd)648379d3d33SDave Penkler static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
649379d3d33SDave Penkler 				void __user *arg, unsigned int cmd)
650379d3d33SDave Penkler {
651379d3d33SDave Penkler 	struct device *dev = &data->intf->dev;
652379d3d33SDave Penkler 	__u8 val;
653379d3d33SDave Penkler 	u8 *buffer;
654379d3d33SDave Penkler 	u16 wValue;
655379d3d33SDave Penkler 	int rv;
656379d3d33SDave Penkler 
657379d3d33SDave Penkler 	if (!(data->usb488_caps & USBTMC488_CAPABILITY_SIMPLE))
658379d3d33SDave Penkler 		return -EINVAL;
659379d3d33SDave Penkler 
660379d3d33SDave Penkler 	buffer = kmalloc(8, GFP_KERNEL);
661379d3d33SDave Penkler 	if (!buffer)
662379d3d33SDave Penkler 		return -ENOMEM;
663379d3d33SDave Penkler 
664379d3d33SDave Penkler 	if (cmd == USBTMC488_REQUEST_REN_CONTROL) {
665379d3d33SDave Penkler 		rv = copy_from_user(&val, arg, sizeof(val));
666379d3d33SDave Penkler 		if (rv) {
667379d3d33SDave Penkler 			rv = -EFAULT;
668379d3d33SDave Penkler 			goto exit;
669379d3d33SDave Penkler 		}
670379d3d33SDave Penkler 		wValue = val ? 1 : 0;
671379d3d33SDave Penkler 	} else {
672379d3d33SDave Penkler 		wValue = 0;
673379d3d33SDave Penkler 	}
674379d3d33SDave Penkler 
675379d3d33SDave Penkler 	rv = usb_control_msg(data->usb_dev,
676379d3d33SDave Penkler 			usb_rcvctrlpipe(data->usb_dev, 0),
677379d3d33SDave Penkler 			cmd,
678379d3d33SDave Penkler 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
679379d3d33SDave Penkler 			wValue,
680379d3d33SDave Penkler 			data->ifnum,
68163c97bbaSGuido Kiener 			buffer, 0x01, USB_CTRL_GET_TIMEOUT);
682379d3d33SDave Penkler 	if (rv < 0) {
683379d3d33SDave Penkler 		dev_err(dev, "simple usb_control_msg failed %d\n", rv);
684379d3d33SDave Penkler 		goto exit;
685379d3d33SDave Penkler 	} else if (rv != 1) {
686379d3d33SDave Penkler 		dev_warn(dev, "simple usb_control_msg returned %d\n", rv);
687379d3d33SDave Penkler 		rv = -EIO;
688379d3d33SDave Penkler 		goto exit;
689379d3d33SDave Penkler 	}
690379d3d33SDave Penkler 
691379d3d33SDave Penkler 	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
692379d3d33SDave Penkler 		dev_err(dev, "simple control status returned %x\n", buffer[0]);
693379d3d33SDave Penkler 		rv = -EIO;
694379d3d33SDave Penkler 		goto exit;
695379d3d33SDave Penkler 	}
696379d3d33SDave Penkler 	rv = 0;
697379d3d33SDave Penkler 
698379d3d33SDave Penkler  exit:
699379d3d33SDave Penkler 	kfree(buffer);
700379d3d33SDave Penkler 	return rv;
701379d3d33SDave Penkler }
702379d3d33SDave Penkler 
70388d9b2b3SAlexandre Peixoto Ferreira /*
704fe78a7c6SGuido Kiener  * Sends a TRIGGER Bulk-OUT command message
705fe78a7c6SGuido Kiener  * See the USBTMC-USB488 specification, Table 2.
706fe78a7c6SGuido Kiener  *
707fe78a7c6SGuido Kiener  * Also updates bTag_last_write.
708fe78a7c6SGuido Kiener  */
usbtmc488_ioctl_trigger(struct usbtmc_file_data * file_data)709fe78a7c6SGuido Kiener static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data)
710fe78a7c6SGuido Kiener {
711fe78a7c6SGuido Kiener 	struct usbtmc_device_data *data = file_data->data;
712fe78a7c6SGuido Kiener 	int retval;
713fe78a7c6SGuido Kiener 	u8 *buffer;
714fe78a7c6SGuido Kiener 	int actual;
715fe78a7c6SGuido Kiener 
716fe78a7c6SGuido Kiener 	buffer = kzalloc(USBTMC_HEADER_SIZE, GFP_KERNEL);
717fe78a7c6SGuido Kiener 	if (!buffer)
718fe78a7c6SGuido Kiener 		return -ENOMEM;
719fe78a7c6SGuido Kiener 
720fe78a7c6SGuido Kiener 	buffer[0] = 128;
721fe78a7c6SGuido Kiener 	buffer[1] = data->bTag;
722fe78a7c6SGuido Kiener 	buffer[2] = ~data->bTag;
723fe78a7c6SGuido Kiener 
724fe78a7c6SGuido Kiener 	retval = usb_bulk_msg(data->usb_dev,
725fe78a7c6SGuido Kiener 			      usb_sndbulkpipe(data->usb_dev,
726fe78a7c6SGuido Kiener 					      data->bulk_out),
727fe78a7c6SGuido Kiener 			      buffer, USBTMC_HEADER_SIZE,
728fe78a7c6SGuido Kiener 			      &actual, file_data->timeout);
729fe78a7c6SGuido Kiener 
730fe78a7c6SGuido Kiener 	/* Store bTag (in case we need to abort) */
731fe78a7c6SGuido Kiener 	data->bTag_last_write = data->bTag;
732fe78a7c6SGuido Kiener 
733fe78a7c6SGuido Kiener 	/* Increment bTag -- and increment again if zero */
734fe78a7c6SGuido Kiener 	data->bTag++;
735fe78a7c6SGuido Kiener 	if (!data->bTag)
736fe78a7c6SGuido Kiener 		data->bTag++;
737fe78a7c6SGuido Kiener 
738fe78a7c6SGuido Kiener 	kfree(buffer);
739fe78a7c6SGuido Kiener 	if (retval < 0) {
740fe78a7c6SGuido Kiener 		dev_err(&data->intf->dev, "%s returned %d\n",
741fe78a7c6SGuido Kiener 			__func__, retval);
742fe78a7c6SGuido Kiener 		return retval;
743fe78a7c6SGuido Kiener 	}
744fe78a7c6SGuido Kiener 
745fe78a7c6SGuido Kiener 	return 0;
746fe78a7c6SGuido Kiener }
747fe78a7c6SGuido Kiener 
usbtmc_create_urb(void)7484ddc645fSGuido Kiener static struct urb *usbtmc_create_urb(void)
7494ddc645fSGuido Kiener {
7504ddc645fSGuido Kiener 	const size_t bufsize = USBTMC_BUFSIZE;
7514ddc645fSGuido Kiener 	u8 *dmabuf = NULL;
7524ddc645fSGuido Kiener 	struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
7534ddc645fSGuido Kiener 
7544ddc645fSGuido Kiener 	if (!urb)
7554ddc645fSGuido Kiener 		return NULL;
7564ddc645fSGuido Kiener 
7574ddc645fSGuido Kiener 	dmabuf = kmalloc(bufsize, GFP_KERNEL);
7584ddc645fSGuido Kiener 	if (!dmabuf) {
7594ddc645fSGuido Kiener 		usb_free_urb(urb);
7604ddc645fSGuido Kiener 		return NULL;
7614ddc645fSGuido Kiener 	}
7624ddc645fSGuido Kiener 
7634ddc645fSGuido Kiener 	urb->transfer_buffer = dmabuf;
7644ddc645fSGuido Kiener 	urb->transfer_buffer_length = bufsize;
7654ddc645fSGuido Kiener 	urb->transfer_flags |= URB_FREE_BUFFER;
7664ddc645fSGuido Kiener 	return urb;
7674ddc645fSGuido Kiener }
7684ddc645fSGuido Kiener 
usbtmc_read_bulk_cb(struct urb * urb)769bb99794aSGuido Kiener static void usbtmc_read_bulk_cb(struct urb *urb)
770bb99794aSGuido Kiener {
771bb99794aSGuido Kiener 	struct usbtmc_file_data *file_data = urb->context;
772bb99794aSGuido Kiener 	int status = urb->status;
773bb99794aSGuido Kiener 	unsigned long flags;
774bb99794aSGuido Kiener 
775bb99794aSGuido Kiener 	/* sync/async unlink faults aren't errors */
776bb99794aSGuido Kiener 	if (status) {
777bb99794aSGuido Kiener 		if (!(/* status == -ENOENT || */
778bb99794aSGuido Kiener 			status == -ECONNRESET ||
779bb99794aSGuido Kiener 			status == -EREMOTEIO || /* Short packet */
780bb99794aSGuido Kiener 			status == -ESHUTDOWN))
781bb99794aSGuido Kiener 			dev_err(&file_data->data->intf->dev,
782bb99794aSGuido Kiener 			"%s - nonzero read bulk status received: %d\n",
783bb99794aSGuido Kiener 			__func__, status);
784bb99794aSGuido Kiener 
785bb99794aSGuido Kiener 		spin_lock_irqsave(&file_data->err_lock, flags);
786bb99794aSGuido Kiener 		if (!file_data->in_status)
787bb99794aSGuido Kiener 			file_data->in_status = status;
788bb99794aSGuido Kiener 		spin_unlock_irqrestore(&file_data->err_lock, flags);
789bb99794aSGuido Kiener 	}
790bb99794aSGuido Kiener 
791bb99794aSGuido Kiener 	spin_lock_irqsave(&file_data->err_lock, flags);
792bb99794aSGuido Kiener 	file_data->in_transfer_size += urb->actual_length;
793bb99794aSGuido Kiener 	dev_dbg(&file_data->data->intf->dev,
794bb99794aSGuido Kiener 		"%s - total size: %u current: %d status: %d\n",
795bb99794aSGuido Kiener 		__func__, file_data->in_transfer_size,
796bb99794aSGuido Kiener 		urb->actual_length, status);
797bb99794aSGuido Kiener 	spin_unlock_irqrestore(&file_data->err_lock, flags);
798bb99794aSGuido Kiener 	usb_anchor_urb(urb, &file_data->in_anchor);
799bb99794aSGuido Kiener 
800bb99794aSGuido Kiener 	wake_up_interruptible(&file_data->wait_bulk_in);
801bb99794aSGuido Kiener 	wake_up_interruptible(&file_data->data->waitq);
802bb99794aSGuido Kiener }
803bb99794aSGuido Kiener 
usbtmc_do_transfer(struct usbtmc_file_data * file_data)804bb99794aSGuido Kiener static inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data)
805bb99794aSGuido Kiener {
806bb99794aSGuido Kiener 	bool data_or_error;
807bb99794aSGuido Kiener 
808bb99794aSGuido Kiener 	spin_lock_irq(&file_data->err_lock);
809bb99794aSGuido Kiener 	data_or_error = !usb_anchor_empty(&file_data->in_anchor)
810bb99794aSGuido Kiener 			|| file_data->in_status;
811bb99794aSGuido Kiener 	spin_unlock_irq(&file_data->err_lock);
812bb99794aSGuido Kiener 	dev_dbg(&file_data->data->intf->dev, "%s: returns %d\n", __func__,
813bb99794aSGuido Kiener 		data_or_error);
814bb99794aSGuido Kiener 	return data_or_error;
815bb99794aSGuido Kiener }
816bb99794aSGuido Kiener 
usbtmc_generic_read(struct usbtmc_file_data * file_data,void __user * user_buffer,u32 transfer_size,u32 * transferred,u32 flags)817bb99794aSGuido Kiener static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data,
818bb99794aSGuido Kiener 				   void __user *user_buffer,
819bb99794aSGuido Kiener 				   u32 transfer_size,
820bb99794aSGuido Kiener 				   u32 *transferred,
821bb99794aSGuido Kiener 				   u32 flags)
822bb99794aSGuido Kiener {
823bb99794aSGuido Kiener 	struct usbtmc_device_data *data = file_data->data;
824bb99794aSGuido Kiener 	struct device *dev = &data->intf->dev;
825bb99794aSGuido Kiener 	u32 done = 0;
826bb99794aSGuido Kiener 	u32 remaining;
827bb99794aSGuido Kiener 	const u32 bufsize = USBTMC_BUFSIZE;
828bb99794aSGuido Kiener 	int retval = 0;
829bb99794aSGuido Kiener 	u32 max_transfer_size;
830bb99794aSGuido Kiener 	unsigned long expire;
831bb99794aSGuido Kiener 	int bufcount = 1;
832bb99794aSGuido Kiener 	int again = 0;
833bb99794aSGuido Kiener 
834bb99794aSGuido Kiener 	/* mutex already locked */
835bb99794aSGuido Kiener 
836bb99794aSGuido Kiener 	*transferred = done;
837bb99794aSGuido Kiener 
838bb99794aSGuido Kiener 	max_transfer_size = transfer_size;
839bb99794aSGuido Kiener 
840bb99794aSGuido Kiener 	if (flags & USBTMC_FLAG_IGNORE_TRAILER) {
841bb99794aSGuido Kiener 		/* The device may send extra alignment bytes (up to
842bb99794aSGuido Kiener 		 * wMaxPacketSize – 1) to avoid sending a zero-length
843bb99794aSGuido Kiener 		 * packet
844bb99794aSGuido Kiener 		 */
845bb99794aSGuido Kiener 		remaining = transfer_size;
846bb99794aSGuido Kiener 		if ((max_transfer_size % data->wMaxPacketSize) == 0)
847bb99794aSGuido Kiener 			max_transfer_size += (data->wMaxPacketSize - 1);
848bb99794aSGuido Kiener 	} else {
849bb99794aSGuido Kiener 		/* round down to bufsize to avoid truncated data left */
850bb99794aSGuido Kiener 		if (max_transfer_size > bufsize) {
851bb99794aSGuido Kiener 			max_transfer_size =
852bb99794aSGuido Kiener 				roundup(max_transfer_size + 1 - bufsize,
853bb99794aSGuido Kiener 					bufsize);
854bb99794aSGuido Kiener 		}
855bb99794aSGuido Kiener 		remaining = max_transfer_size;
856bb99794aSGuido Kiener 	}
857bb99794aSGuido Kiener 
858bb99794aSGuido Kiener 	spin_lock_irq(&file_data->err_lock);
859bb99794aSGuido Kiener 
860bb99794aSGuido Kiener 	if (file_data->in_status) {
861bb99794aSGuido Kiener 		/* return the very first error */
862bb99794aSGuido Kiener 		retval = file_data->in_status;
863bb99794aSGuido Kiener 		spin_unlock_irq(&file_data->err_lock);
864bb99794aSGuido Kiener 		goto error;
865bb99794aSGuido Kiener 	}
866bb99794aSGuido Kiener 
867bb99794aSGuido Kiener 	if (flags & USBTMC_FLAG_ASYNC) {
868bb99794aSGuido Kiener 		if (usb_anchor_empty(&file_data->in_anchor))
869bb99794aSGuido Kiener 			again = 1;
870bb99794aSGuido Kiener 
871bb99794aSGuido Kiener 		if (file_data->in_urbs_used == 0) {
872bb99794aSGuido Kiener 			file_data->in_transfer_size = 0;
873bb99794aSGuido Kiener 			file_data->in_status = 0;
874bb99794aSGuido Kiener 		}
875bb99794aSGuido Kiener 	} else {
876bb99794aSGuido Kiener 		file_data->in_transfer_size = 0;
877bb99794aSGuido Kiener 		file_data->in_status = 0;
878bb99794aSGuido Kiener 	}
879bb99794aSGuido Kiener 
880bb99794aSGuido Kiener 	if (max_transfer_size == 0) {
881bb99794aSGuido Kiener 		bufcount = 0;
882bb99794aSGuido Kiener 	} else {
883bb99794aSGuido Kiener 		bufcount = roundup(max_transfer_size, bufsize) / bufsize;
884bb99794aSGuido Kiener 		if (bufcount > file_data->in_urbs_used)
885bb99794aSGuido Kiener 			bufcount -= file_data->in_urbs_used;
886bb99794aSGuido Kiener 		else
887bb99794aSGuido Kiener 			bufcount = 0;
888bb99794aSGuido Kiener 
889bb99794aSGuido Kiener 		if (bufcount + file_data->in_urbs_used > MAX_URBS_IN_FLIGHT) {
890bb99794aSGuido Kiener 			bufcount = MAX_URBS_IN_FLIGHT -
891bb99794aSGuido Kiener 					file_data->in_urbs_used;
892bb99794aSGuido Kiener 		}
893bb99794aSGuido Kiener 	}
894bb99794aSGuido Kiener 	spin_unlock_irq(&file_data->err_lock);
895bb99794aSGuido Kiener 
896bb99794aSGuido Kiener 	dev_dbg(dev, "%s: requested=%u flags=0x%X size=%u bufs=%d used=%d\n",
897bb99794aSGuido Kiener 		__func__, transfer_size, flags,
898bb99794aSGuido Kiener 		max_transfer_size, bufcount, file_data->in_urbs_used);
899bb99794aSGuido Kiener 
900bb99794aSGuido Kiener 	while (bufcount > 0) {
901bb99794aSGuido Kiener 		u8 *dmabuf = NULL;
902bb99794aSGuido Kiener 		struct urb *urb = usbtmc_create_urb();
903bb99794aSGuido Kiener 
904bb99794aSGuido Kiener 		if (!urb) {
905bb99794aSGuido Kiener 			retval = -ENOMEM;
906bb99794aSGuido Kiener 			goto error;
907bb99794aSGuido Kiener 		}
908bb99794aSGuido Kiener 
909bb99794aSGuido Kiener 		dmabuf = urb->transfer_buffer;
910bb99794aSGuido Kiener 
911bb99794aSGuido Kiener 		usb_fill_bulk_urb(urb, data->usb_dev,
912bb99794aSGuido Kiener 			usb_rcvbulkpipe(data->usb_dev, data->bulk_in),
913bb99794aSGuido Kiener 			dmabuf, bufsize,
914bb99794aSGuido Kiener 			usbtmc_read_bulk_cb, file_data);
915bb99794aSGuido Kiener 
916bb99794aSGuido Kiener 		usb_anchor_urb(urb, &file_data->submitted);
917bb99794aSGuido Kiener 		retval = usb_submit_urb(urb, GFP_KERNEL);
918bb99794aSGuido Kiener 		/* urb is anchored. We can release our reference. */
919bb99794aSGuido Kiener 		usb_free_urb(urb);
920bb99794aSGuido Kiener 		if (unlikely(retval)) {
921bb99794aSGuido Kiener 			usb_unanchor_urb(urb);
922bb99794aSGuido Kiener 			goto error;
923bb99794aSGuido Kiener 		}
924bb99794aSGuido Kiener 		file_data->in_urbs_used++;
925bb99794aSGuido Kiener 		bufcount--;
926bb99794aSGuido Kiener 	}
927bb99794aSGuido Kiener 
928bb99794aSGuido Kiener 	if (again) {
929bb99794aSGuido Kiener 		dev_dbg(dev, "%s: ret=again\n", __func__);
930bb99794aSGuido Kiener 		return -EAGAIN;
931bb99794aSGuido Kiener 	}
932bb99794aSGuido Kiener 
933bb99794aSGuido Kiener 	if (user_buffer == NULL)
934bb99794aSGuido Kiener 		return -EINVAL;
935bb99794aSGuido Kiener 
936bb99794aSGuido Kiener 	expire = msecs_to_jiffies(file_data->timeout);
937bb99794aSGuido Kiener 
938bb99794aSGuido Kiener 	while (max_transfer_size > 0) {
939bb99794aSGuido Kiener 		u32 this_part;
940bb99794aSGuido Kiener 		struct urb *urb = NULL;
941bb99794aSGuido Kiener 
942bb99794aSGuido Kiener 		if (!(flags & USBTMC_FLAG_ASYNC)) {
943bb99794aSGuido Kiener 			dev_dbg(dev, "%s: before wait time %lu\n",
944bb99794aSGuido Kiener 				__func__, expire);
945bb99794aSGuido Kiener 			retval = wait_event_interruptible_timeout(
946bb99794aSGuido Kiener 				file_data->wait_bulk_in,
947bb99794aSGuido Kiener 				usbtmc_do_transfer(file_data),
948bb99794aSGuido Kiener 				expire);
949bb99794aSGuido Kiener 
950bb99794aSGuido Kiener 			dev_dbg(dev, "%s: wait returned %d\n",
951bb99794aSGuido Kiener 				__func__, retval);
952bb99794aSGuido Kiener 
953bb99794aSGuido Kiener 			if (retval <= 0) {
954bb99794aSGuido Kiener 				if (retval == 0)
955bb99794aSGuido Kiener 					retval = -ETIMEDOUT;
956bb99794aSGuido Kiener 				goto error;
957bb99794aSGuido Kiener 			}
958bb99794aSGuido Kiener 		}
959bb99794aSGuido Kiener 
960bb99794aSGuido Kiener 		urb = usb_get_from_anchor(&file_data->in_anchor);
961bb99794aSGuido Kiener 		if (!urb) {
962bb99794aSGuido Kiener 			if (!(flags & USBTMC_FLAG_ASYNC)) {
963bb99794aSGuido Kiener 				/* synchronous case: must not happen */
964bb99794aSGuido Kiener 				retval = -EFAULT;
965bb99794aSGuido Kiener 				goto error;
966bb99794aSGuido Kiener 			}
967bb99794aSGuido Kiener 
968bb99794aSGuido Kiener 			/* asynchronous case: ready, do not block or wait */
969bb99794aSGuido Kiener 			*transferred = done;
970bb99794aSGuido Kiener 			dev_dbg(dev, "%s: (async) done=%u ret=0\n",
971bb99794aSGuido Kiener 				__func__, done);
972bb99794aSGuido Kiener 			return 0;
973bb99794aSGuido Kiener 		}
974bb99794aSGuido Kiener 
975bb99794aSGuido Kiener 		file_data->in_urbs_used--;
976bb99794aSGuido Kiener 
977bb99794aSGuido Kiener 		if (max_transfer_size > urb->actual_length)
978bb99794aSGuido Kiener 			max_transfer_size -= urb->actual_length;
979bb99794aSGuido Kiener 		else
980bb99794aSGuido Kiener 			max_transfer_size = 0;
981bb99794aSGuido Kiener 
982bb99794aSGuido Kiener 		if (remaining > urb->actual_length)
983bb99794aSGuido Kiener 			this_part = urb->actual_length;
984bb99794aSGuido Kiener 		else
985bb99794aSGuido Kiener 			this_part = remaining;
986bb99794aSGuido Kiener 
987bb99794aSGuido Kiener 		print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1,
988bb99794aSGuido Kiener 			urb->transfer_buffer, urb->actual_length, true);
989bb99794aSGuido Kiener 
990bb99794aSGuido Kiener 		if (copy_to_user(user_buffer + done,
991bb99794aSGuido Kiener 				 urb->transfer_buffer, this_part)) {
992bb99794aSGuido Kiener 			usb_free_urb(urb);
993bb99794aSGuido Kiener 			retval = -EFAULT;
994bb99794aSGuido Kiener 			goto error;
995bb99794aSGuido Kiener 		}
996bb99794aSGuido Kiener 
997bb99794aSGuido Kiener 		remaining -= this_part;
998bb99794aSGuido Kiener 		done += this_part;
999bb99794aSGuido Kiener 
1000bb99794aSGuido Kiener 		spin_lock_irq(&file_data->err_lock);
1001bb99794aSGuido Kiener 		if (urb->status) {
1002bb99794aSGuido Kiener 			/* return the very first error */
1003bb99794aSGuido Kiener 			retval = file_data->in_status;
1004bb99794aSGuido Kiener 			spin_unlock_irq(&file_data->err_lock);
1005bb99794aSGuido Kiener 			usb_free_urb(urb);
1006bb99794aSGuido Kiener 			goto error;
1007bb99794aSGuido Kiener 		}
1008bb99794aSGuido Kiener 		spin_unlock_irq(&file_data->err_lock);
1009bb99794aSGuido Kiener 
1010bb99794aSGuido Kiener 		if (urb->actual_length < bufsize) {
1011bb99794aSGuido Kiener 			/* short packet or ZLP received => ready */
1012bb99794aSGuido Kiener 			usb_free_urb(urb);
1013bb99794aSGuido Kiener 			retval = 1;
1014bb99794aSGuido Kiener 			break;
1015bb99794aSGuido Kiener 		}
1016bb99794aSGuido Kiener 
1017bb99794aSGuido Kiener 		if (!(flags & USBTMC_FLAG_ASYNC) &&
1018bb99794aSGuido Kiener 		    max_transfer_size > (bufsize * file_data->in_urbs_used)) {
1019bb99794aSGuido Kiener 			/* resubmit, since other buffers still not enough */
1020bb99794aSGuido Kiener 			usb_anchor_urb(urb, &file_data->submitted);
1021bb99794aSGuido Kiener 			retval = usb_submit_urb(urb, GFP_KERNEL);
1022bb99794aSGuido Kiener 			if (unlikely(retval)) {
1023bb99794aSGuido Kiener 				usb_unanchor_urb(urb);
1024bb99794aSGuido Kiener 				usb_free_urb(urb);
1025bb99794aSGuido Kiener 				goto error;
1026bb99794aSGuido Kiener 			}
1027bb99794aSGuido Kiener 			file_data->in_urbs_used++;
1028bb99794aSGuido Kiener 		}
1029bb99794aSGuido Kiener 		usb_free_urb(urb);
1030bb99794aSGuido Kiener 		retval = 0;
1031bb99794aSGuido Kiener 	}
1032bb99794aSGuido Kiener 
1033bb99794aSGuido Kiener error:
1034bb99794aSGuido Kiener 	*transferred = done;
1035bb99794aSGuido Kiener 
1036bb99794aSGuido Kiener 	dev_dbg(dev, "%s: before kill\n", __func__);
1037bb99794aSGuido Kiener 	/* Attention: killing urbs can take long time (2 ms) */
1038bb99794aSGuido Kiener 	usb_kill_anchored_urbs(&file_data->submitted);
1039bb99794aSGuido Kiener 	dev_dbg(dev, "%s: after kill\n", __func__);
1040bb99794aSGuido Kiener 	usb_scuttle_anchored_urbs(&file_data->in_anchor);
1041bb99794aSGuido Kiener 	file_data->in_urbs_used = 0;
1042bb99794aSGuido Kiener 	file_data->in_status = 0; /* no spinlock needed here */
1043bb99794aSGuido Kiener 	dev_dbg(dev, "%s: done=%u ret=%d\n", __func__, done, retval);
1044bb99794aSGuido Kiener 
1045bb99794aSGuido Kiener 	return retval;
1046bb99794aSGuido Kiener }
1047bb99794aSGuido Kiener 
usbtmc_ioctl_generic_read(struct usbtmc_file_data * file_data,void __user * arg)1048bb99794aSGuido Kiener static ssize_t usbtmc_ioctl_generic_read(struct usbtmc_file_data *file_data,
1049bb99794aSGuido Kiener 					 void __user *arg)
1050bb99794aSGuido Kiener {
1051bb99794aSGuido Kiener 	struct usbtmc_message msg;
1052bb99794aSGuido Kiener 	ssize_t retval = 0;
1053bb99794aSGuido Kiener 
1054bb99794aSGuido Kiener 	/* mutex already locked */
1055bb99794aSGuido Kiener 
1056bb99794aSGuido Kiener 	if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message)))
1057bb99794aSGuido Kiener 		return -EFAULT;
1058bb99794aSGuido Kiener 
1059bb99794aSGuido Kiener 	retval = usbtmc_generic_read(file_data, msg.message,
1060bb99794aSGuido Kiener 				     msg.transfer_size, &msg.transferred,
1061bb99794aSGuido Kiener 				     msg.flags);
1062bb99794aSGuido Kiener 
1063bb99794aSGuido Kiener 	if (put_user(msg.transferred,
1064bb99794aSGuido Kiener 		     &((struct usbtmc_message __user *)arg)->transferred))
1065bb99794aSGuido Kiener 		return -EFAULT;
1066bb99794aSGuido Kiener 
1067bb99794aSGuido Kiener 	return retval;
1068bb99794aSGuido Kiener }
1069bb99794aSGuido Kiener 
usbtmc_write_bulk_cb(struct urb * urb)10704ddc645fSGuido Kiener static void usbtmc_write_bulk_cb(struct urb *urb)
10714ddc645fSGuido Kiener {
10724ddc645fSGuido Kiener 	struct usbtmc_file_data *file_data = urb->context;
10734ddc645fSGuido Kiener 	int wakeup = 0;
10744ddc645fSGuido Kiener 	unsigned long flags;
10754ddc645fSGuido Kiener 
10764ddc645fSGuido Kiener 	spin_lock_irqsave(&file_data->err_lock, flags);
10774ddc645fSGuido Kiener 	file_data->out_transfer_size += urb->actual_length;
10784ddc645fSGuido Kiener 
10794ddc645fSGuido Kiener 	/* sync/async unlink faults aren't errors */
10804ddc645fSGuido Kiener 	if (urb->status) {
10814ddc645fSGuido Kiener 		if (!(urb->status == -ENOENT ||
10824ddc645fSGuido Kiener 			urb->status == -ECONNRESET ||
10834ddc645fSGuido Kiener 			urb->status == -ESHUTDOWN))
10844ddc645fSGuido Kiener 			dev_err(&file_data->data->intf->dev,
10854ddc645fSGuido Kiener 				"%s - nonzero write bulk status received: %d\n",
10864ddc645fSGuido Kiener 				__func__, urb->status);
10874ddc645fSGuido Kiener 
10884ddc645fSGuido Kiener 		if (!file_data->out_status) {
10894ddc645fSGuido Kiener 			file_data->out_status = urb->status;
10904ddc645fSGuido Kiener 			wakeup = 1;
10914ddc645fSGuido Kiener 		}
10924ddc645fSGuido Kiener 	}
10934ddc645fSGuido Kiener 	spin_unlock_irqrestore(&file_data->err_lock, flags);
10944ddc645fSGuido Kiener 
10954ddc645fSGuido Kiener 	dev_dbg(&file_data->data->intf->dev,
10964ddc645fSGuido Kiener 		"%s - write bulk total size: %u\n",
10974ddc645fSGuido Kiener 		__func__, file_data->out_transfer_size);
10984ddc645fSGuido Kiener 
10994ddc645fSGuido Kiener 	up(&file_data->limit_write_sem);
11004ddc645fSGuido Kiener 	if (usb_anchor_empty(&file_data->submitted) || wakeup)
11014ddc645fSGuido Kiener 		wake_up_interruptible(&file_data->data->waitq);
11024ddc645fSGuido Kiener }
11034ddc645fSGuido Kiener 
usbtmc_generic_write(struct usbtmc_file_data * file_data,const void __user * user_buffer,u32 transfer_size,u32 * transferred,u32 flags)11044ddc645fSGuido Kiener static ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data,
11054ddc645fSGuido Kiener 				    const void __user *user_buffer,
11064ddc645fSGuido Kiener 				    u32 transfer_size,
11074ddc645fSGuido Kiener 				    u32 *transferred,
11084ddc645fSGuido Kiener 				    u32 flags)
11094ddc645fSGuido Kiener {
11104ddc645fSGuido Kiener 	struct usbtmc_device_data *data = file_data->data;
11114ddc645fSGuido Kiener 	struct device *dev;
11124ddc645fSGuido Kiener 	u32 done = 0;
11134ddc645fSGuido Kiener 	u32 remaining;
11144ddc645fSGuido Kiener 	unsigned long expire;
11154ddc645fSGuido Kiener 	const u32 bufsize = USBTMC_BUFSIZE;
11164ddc645fSGuido Kiener 	struct urb *urb = NULL;
11174ddc645fSGuido Kiener 	int retval = 0;
11184ddc645fSGuido Kiener 	u32 timeout;
11194ddc645fSGuido Kiener 
11204ddc645fSGuido Kiener 	*transferred = 0;
11214ddc645fSGuido Kiener 
11224ddc645fSGuido Kiener 	/* Get pointer to private data structure */
11234ddc645fSGuido Kiener 	dev = &data->intf->dev;
11244ddc645fSGuido Kiener 
11254ddc645fSGuido Kiener 	dev_dbg(dev, "%s: size=%u flags=0x%X sema=%u\n",
11264ddc645fSGuido Kiener 		__func__, transfer_size, flags,
11274ddc645fSGuido Kiener 		file_data->limit_write_sem.count);
11284ddc645fSGuido Kiener 
11294ddc645fSGuido Kiener 	if (flags & USBTMC_FLAG_APPEND) {
11304ddc645fSGuido Kiener 		spin_lock_irq(&file_data->err_lock);
11314ddc645fSGuido Kiener 		retval = file_data->out_status;
11324ddc645fSGuido Kiener 		spin_unlock_irq(&file_data->err_lock);
11334ddc645fSGuido Kiener 		if (retval < 0)
11344ddc645fSGuido Kiener 			return retval;
11354ddc645fSGuido Kiener 	} else {
11364ddc645fSGuido Kiener 		spin_lock_irq(&file_data->err_lock);
11374ddc645fSGuido Kiener 		file_data->out_transfer_size = 0;
11384ddc645fSGuido Kiener 		file_data->out_status = 0;
11394ddc645fSGuido Kiener 		spin_unlock_irq(&file_data->err_lock);
11404ddc645fSGuido Kiener 	}
11414ddc645fSGuido Kiener 
11424ddc645fSGuido Kiener 	remaining = transfer_size;
11434ddc645fSGuido Kiener 	if (remaining > INT_MAX)
11444ddc645fSGuido Kiener 		remaining = INT_MAX;
11454ddc645fSGuido Kiener 
11464ddc645fSGuido Kiener 	timeout = file_data->timeout;
11474ddc645fSGuido Kiener 	expire = msecs_to_jiffies(timeout);
11484ddc645fSGuido Kiener 
11494ddc645fSGuido Kiener 	while (remaining > 0) {
11504ddc645fSGuido Kiener 		u32 this_part, aligned;
11514ddc645fSGuido Kiener 		u8 *buffer = NULL;
11524ddc645fSGuido Kiener 
11534ddc645fSGuido Kiener 		if (flags & USBTMC_FLAG_ASYNC) {
11544ddc645fSGuido Kiener 			if (down_trylock(&file_data->limit_write_sem)) {
11554ddc645fSGuido Kiener 				retval = (done)?(0):(-EAGAIN);
11564ddc645fSGuido Kiener 				goto exit;
11574ddc645fSGuido Kiener 			}
11584ddc645fSGuido Kiener 		} else {
11594ddc645fSGuido Kiener 			retval = down_timeout(&file_data->limit_write_sem,
11604ddc645fSGuido Kiener 					      expire);
11614ddc645fSGuido Kiener 			if (retval < 0) {
11624ddc645fSGuido Kiener 				retval = -ETIMEDOUT;
11634ddc645fSGuido Kiener 				goto error;
11644ddc645fSGuido Kiener 			}
11654ddc645fSGuido Kiener 		}
11664ddc645fSGuido Kiener 
11674ddc645fSGuido Kiener 		spin_lock_irq(&file_data->err_lock);
11684ddc645fSGuido Kiener 		retval = file_data->out_status;
11694ddc645fSGuido Kiener 		spin_unlock_irq(&file_data->err_lock);
11704ddc645fSGuido Kiener 		if (retval < 0) {
11714ddc645fSGuido Kiener 			up(&file_data->limit_write_sem);
11724ddc645fSGuido Kiener 			goto error;
11734ddc645fSGuido Kiener 		}
11744ddc645fSGuido Kiener 
11754ddc645fSGuido Kiener 		/* prepare next urb to send */
11764ddc645fSGuido Kiener 		urb = usbtmc_create_urb();
11774ddc645fSGuido Kiener 		if (!urb) {
11784ddc645fSGuido Kiener 			retval = -ENOMEM;
11794ddc645fSGuido Kiener 			up(&file_data->limit_write_sem);
11804ddc645fSGuido Kiener 			goto error;
11814ddc645fSGuido Kiener 		}
11824ddc645fSGuido Kiener 		buffer = urb->transfer_buffer;
11834ddc645fSGuido Kiener 
11844ddc645fSGuido Kiener 		if (remaining > bufsize)
11854ddc645fSGuido Kiener 			this_part = bufsize;
11864ddc645fSGuido Kiener 		else
11874ddc645fSGuido Kiener 			this_part = remaining;
11884ddc645fSGuido Kiener 
11894ddc645fSGuido Kiener 		if (copy_from_user(buffer, user_buffer + done, this_part)) {
11904ddc645fSGuido Kiener 			retval = -EFAULT;
11914ddc645fSGuido Kiener 			up(&file_data->limit_write_sem);
11924ddc645fSGuido Kiener 			goto error;
11934ddc645fSGuido Kiener 		}
11944ddc645fSGuido Kiener 
11954ddc645fSGuido Kiener 		print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
11964ddc645fSGuido Kiener 			16, 1, buffer, this_part, true);
11974ddc645fSGuido Kiener 
11984ddc645fSGuido Kiener 		/* fill bulk with 32 bit alignment to meet USBTMC specification
11994ddc645fSGuido Kiener 		 * (size + 3 & ~3) rounds up and simplifies user code
12004ddc645fSGuido Kiener 		 */
12014ddc645fSGuido Kiener 		aligned = (this_part + 3) & ~3;
12024ddc645fSGuido Kiener 		dev_dbg(dev, "write(size:%u align:%u done:%u)\n",
12034ddc645fSGuido Kiener 			(unsigned int)this_part,
12044ddc645fSGuido Kiener 			(unsigned int)aligned,
12054ddc645fSGuido Kiener 			(unsigned int)done);
12064ddc645fSGuido Kiener 
12074ddc645fSGuido Kiener 		usb_fill_bulk_urb(urb, data->usb_dev,
12084ddc645fSGuido Kiener 			usb_sndbulkpipe(data->usb_dev, data->bulk_out),
12094ddc645fSGuido Kiener 			urb->transfer_buffer, aligned,
12104ddc645fSGuido Kiener 			usbtmc_write_bulk_cb, file_data);
12114ddc645fSGuido Kiener 
12124ddc645fSGuido Kiener 		usb_anchor_urb(urb, &file_data->submitted);
12134ddc645fSGuido Kiener 		retval = usb_submit_urb(urb, GFP_KERNEL);
12144ddc645fSGuido Kiener 		if (unlikely(retval)) {
12154ddc645fSGuido Kiener 			usb_unanchor_urb(urb);
12164ddc645fSGuido Kiener 			up(&file_data->limit_write_sem);
12174ddc645fSGuido Kiener 			goto error;
12184ddc645fSGuido Kiener 		}
12194ddc645fSGuido Kiener 
12204ddc645fSGuido Kiener 		usb_free_urb(urb);
12214ddc645fSGuido Kiener 		urb = NULL; /* urb will be finally released by usb driver */
12224ddc645fSGuido Kiener 
12234ddc645fSGuido Kiener 		remaining -= this_part;
12244ddc645fSGuido Kiener 		done += this_part;
12254ddc645fSGuido Kiener 	}
12264ddc645fSGuido Kiener 
12274ddc645fSGuido Kiener 	/* All urbs are on the fly */
12284ddc645fSGuido Kiener 	if (!(flags & USBTMC_FLAG_ASYNC)) {
12294ddc645fSGuido Kiener 		if (!usb_wait_anchor_empty_timeout(&file_data->submitted,
12304ddc645fSGuido Kiener 						   timeout)) {
12314ddc645fSGuido Kiener 			retval = -ETIMEDOUT;
12324ddc645fSGuido Kiener 			goto error;
12334ddc645fSGuido Kiener 		}
12344ddc645fSGuido Kiener 	}
12354ddc645fSGuido Kiener 
12364ddc645fSGuido Kiener 	retval = 0;
12374ddc645fSGuido Kiener 	goto exit;
12384ddc645fSGuido Kiener 
12394ddc645fSGuido Kiener error:
12404ddc645fSGuido Kiener 	usb_kill_anchored_urbs(&file_data->submitted);
12414ddc645fSGuido Kiener exit:
12424ddc645fSGuido Kiener 	usb_free_urb(urb);
12434ddc645fSGuido Kiener 
12444ddc645fSGuido Kiener 	spin_lock_irq(&file_data->err_lock);
12454ddc645fSGuido Kiener 	if (!(flags & USBTMC_FLAG_ASYNC))
12464ddc645fSGuido Kiener 		done = file_data->out_transfer_size;
12474ddc645fSGuido Kiener 	if (!retval && file_data->out_status)
12484ddc645fSGuido Kiener 		retval = file_data->out_status;
12494ddc645fSGuido Kiener 	spin_unlock_irq(&file_data->err_lock);
12504ddc645fSGuido Kiener 
12514ddc645fSGuido Kiener 	*transferred = done;
12524ddc645fSGuido Kiener 
12534ddc645fSGuido Kiener 	dev_dbg(dev, "%s: done=%u, retval=%d, urbstat=%d\n",
12544ddc645fSGuido Kiener 		__func__, done, retval, file_data->out_status);
12554ddc645fSGuido Kiener 
12564ddc645fSGuido Kiener 	return retval;
12574ddc645fSGuido Kiener }
12584ddc645fSGuido Kiener 
usbtmc_ioctl_generic_write(struct usbtmc_file_data * file_data,void __user * arg)12594ddc645fSGuido Kiener static ssize_t usbtmc_ioctl_generic_write(struct usbtmc_file_data *file_data,
12604ddc645fSGuido Kiener 					  void __user *arg)
12614ddc645fSGuido Kiener {
12624ddc645fSGuido Kiener 	struct usbtmc_message msg;
12634ddc645fSGuido Kiener 	ssize_t retval = 0;
12644ddc645fSGuido Kiener 
12654ddc645fSGuido Kiener 	/* mutex already locked */
12664ddc645fSGuido Kiener 
12674ddc645fSGuido Kiener 	if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message)))
12684ddc645fSGuido Kiener 		return -EFAULT;
12694ddc645fSGuido Kiener 
12704ddc645fSGuido Kiener 	retval = usbtmc_generic_write(file_data, msg.message,
12714ddc645fSGuido Kiener 				      msg.transfer_size, &msg.transferred,
12724ddc645fSGuido Kiener 				      msg.flags);
12734ddc645fSGuido Kiener 
12744ddc645fSGuido Kiener 	if (put_user(msg.transferred,
12754ddc645fSGuido Kiener 		     &((struct usbtmc_message __user *)arg)->transferred))
12764ddc645fSGuido Kiener 		return -EFAULT;
12774ddc645fSGuido Kiener 
12784ddc645fSGuido Kiener 	return retval;
12794ddc645fSGuido Kiener }
12804ddc645fSGuido Kiener 
1281fe78a7c6SGuido Kiener /*
1282b1498451SGuido Kiener  * Get the generic write result
1283b1498451SGuido Kiener  */
usbtmc_ioctl_write_result(struct usbtmc_file_data * file_data,void __user * arg)1284b1498451SGuido Kiener static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data,
1285b1498451SGuido Kiener 				void __user *arg)
1286b1498451SGuido Kiener {
1287b1498451SGuido Kiener 	u32 transferred;
1288b1498451SGuido Kiener 	int retval;
1289b1498451SGuido Kiener 
1290b1498451SGuido Kiener 	spin_lock_irq(&file_data->err_lock);
1291b1498451SGuido Kiener 	transferred = file_data->out_transfer_size;
1292b1498451SGuido Kiener 	retval = file_data->out_status;
1293b1498451SGuido Kiener 	spin_unlock_irq(&file_data->err_lock);
1294b1498451SGuido Kiener 
1295b1498451SGuido Kiener 	if (put_user(transferred, (__u32 __user *)arg))
1296b1498451SGuido Kiener 		return -EFAULT;
1297b1498451SGuido Kiener 
1298b1498451SGuido Kiener 	return retval;
1299b1498451SGuido Kiener }
1300b1498451SGuido Kiener 
1301b1498451SGuido Kiener /*
130288aecde4SDave Penkler  * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
130388d9b2b3SAlexandre Peixoto Ferreira  * @transfer_size: number of bytes to request from the device.
130488d9b2b3SAlexandre Peixoto Ferreira  *
130588d9b2b3SAlexandre Peixoto Ferreira  * See the USBTMC specification, Table 4.
130688d9b2b3SAlexandre Peixoto Ferreira  *
130788d9b2b3SAlexandre Peixoto Ferreira  * Also updates bTag_last_write.
130888d9b2b3SAlexandre Peixoto Ferreira  */
send_request_dev_dep_msg_in(struct usbtmc_file_data * file_data,u32 transfer_size)1309048c6d88SGuido Kiener static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
1310d7604ff0SGuido Kiener 				       u32 transfer_size)
131188d9b2b3SAlexandre Peixoto Ferreira {
1312048c6d88SGuido Kiener 	struct usbtmc_device_data *data = file_data->data;
131388d9b2b3SAlexandre Peixoto Ferreira 	int retval;
1314d846b765SOliver Neukum 	u8 *buffer;
131588d9b2b3SAlexandre Peixoto Ferreira 	int actual;
131688d9b2b3SAlexandre Peixoto Ferreira 
1317d846b765SOliver Neukum 	buffer = kmalloc(USBTMC_HEADER_SIZE, GFP_KERNEL);
1318d846b765SOliver Neukum 	if (!buffer)
1319d846b765SOliver Neukum 		return -ENOMEM;
132088d9b2b3SAlexandre Peixoto Ferreira 	/* Setup IO buffer for REQUEST_DEV_DEP_MSG_IN message
132188d9b2b3SAlexandre Peixoto Ferreira 	 * Refer to class specs for details
132288d9b2b3SAlexandre Peixoto Ferreira 	 */
132388d9b2b3SAlexandre Peixoto Ferreira 	buffer[0] = 2;
132488d9b2b3SAlexandre Peixoto Ferreira 	buffer[1] = data->bTag;
1325bbf4976eSAndy Shevchenko 	buffer[2] = ~data->bTag;
132688d9b2b3SAlexandre Peixoto Ferreira 	buffer[3] = 0; /* Reserved */
1327bbf4976eSAndy Shevchenko 	buffer[4] = transfer_size >> 0;
1328bbf4976eSAndy Shevchenko 	buffer[5] = transfer_size >> 8;
1329bbf4976eSAndy Shevchenko 	buffer[6] = transfer_size >> 16;
1330bbf4976eSAndy Shevchenko 	buffer[7] = transfer_size >> 24;
133112dcaeb7SGuido Kiener 	buffer[8] = file_data->term_char_enabled * 2;
133288d9b2b3SAlexandre Peixoto Ferreira 	/* Use term character? */
133312dcaeb7SGuido Kiener 	buffer[9] = file_data->term_char;
133488d9b2b3SAlexandre Peixoto Ferreira 	buffer[10] = 0; /* Reserved */
133588d9b2b3SAlexandre Peixoto Ferreira 	buffer[11] = 0; /* Reserved */
133688d9b2b3SAlexandre Peixoto Ferreira 
133788d9b2b3SAlexandre Peixoto Ferreira 	/* Send bulk URB */
133888d9b2b3SAlexandre Peixoto Ferreira 	retval = usb_bulk_msg(data->usb_dev,
133988d9b2b3SAlexandre Peixoto Ferreira 			      usb_sndbulkpipe(data->usb_dev,
134088d9b2b3SAlexandre Peixoto Ferreira 					      data->bulk_out),
1341048c6d88SGuido Kiener 			      buffer, USBTMC_HEADER_SIZE,
1342048c6d88SGuido Kiener 			      &actual, file_data->timeout);
134388d9b2b3SAlexandre Peixoto Ferreira 
134488d9b2b3SAlexandre Peixoto Ferreira 	/* Store bTag (in case we need to abort) */
134588d9b2b3SAlexandre Peixoto Ferreira 	data->bTag_last_write = data->bTag;
134688d9b2b3SAlexandre Peixoto Ferreira 
134788d9b2b3SAlexandre Peixoto Ferreira 	/* Increment bTag -- and increment again if zero */
134888d9b2b3SAlexandre Peixoto Ferreira 	data->bTag++;
134988d9b2b3SAlexandre Peixoto Ferreira 	if (!data->bTag)
1350bbf4976eSAndy Shevchenko 		data->bTag++;
135188d9b2b3SAlexandre Peixoto Ferreira 
1352d846b765SOliver Neukum 	kfree(buffer);
1353d7604ff0SGuido Kiener 	if (retval < 0)
1354d7604ff0SGuido Kiener 		dev_err(&data->intf->dev, "%s returned %d\n",
1355d7604ff0SGuido Kiener 			__func__, retval);
135688d9b2b3SAlexandre Peixoto Ferreira 
1357d7604ff0SGuido Kiener 	return retval;
135888d9b2b3SAlexandre Peixoto Ferreira }
135988d9b2b3SAlexandre Peixoto Ferreira 
usbtmc_read(struct file * filp,char __user * buf,size_t count,loff_t * f_pos)13605b775f67SGreg Kroah-Hartman static ssize_t usbtmc_read(struct file *filp, char __user *buf,
13615b775f67SGreg Kroah-Hartman 			   size_t count, loff_t *f_pos)
13625b775f67SGreg Kroah-Hartman {
13634f3c8d6eSGuido Kiener 	struct usbtmc_file_data *file_data;
13645b775f67SGreg Kroah-Hartman 	struct usbtmc_device_data *data;
13655b775f67SGreg Kroah-Hartman 	struct device *dev;
1366d7604ff0SGuido Kiener 	const u32 bufsize = USBTMC_BUFSIZE;
1367665d7662SGuus Sliepen 	u32 n_characters;
13685b775f67SGreg Kroah-Hartman 	u8 *buffer;
13695b775f67SGreg Kroah-Hartman 	int actual;
1370d7604ff0SGuido Kiener 	u32 done = 0;
1371d7604ff0SGuido Kiener 	u32 remaining;
13725b775f67SGreg Kroah-Hartman 	int retval;
13735b775f67SGreg Kroah-Hartman 
13745b775f67SGreg Kroah-Hartman 	/* Get pointer to private data structure */
13754f3c8d6eSGuido Kiener 	file_data = filp->private_data;
13764f3c8d6eSGuido Kiener 	data = file_data->data;
13775b775f67SGreg Kroah-Hartman 	dev = &data->intf->dev;
13785b775f67SGreg Kroah-Hartman 
1379d7604ff0SGuido Kiener 	buffer = kmalloc(bufsize, GFP_KERNEL);
13805b775f67SGreg Kroah-Hartman 	if (!buffer)
13815b775f67SGreg Kroah-Hartman 		return -ENOMEM;
13825b775f67SGreg Kroah-Hartman 
13835b775f67SGreg Kroah-Hartman 	mutex_lock(&data->io_mutex);
138486286883SOliver Neukum 	if (data->zombie) {
138586286883SOliver Neukum 		retval = -ENODEV;
138686286883SOliver Neukum 		goto exit;
138786286883SOliver Neukum 	}
13885b775f67SGreg Kroah-Hartman 
1389d7604ff0SGuido Kiener 	if (count > INT_MAX)
1390d7604ff0SGuido Kiener 		count = INT_MAX;
1391d7604ff0SGuido Kiener 
1392d7604ff0SGuido Kiener 	dev_dbg(dev, "%s(count:%zu)\n", __func__, count);
1393d2ddce37SAlexandre Peixoto Ferreira 
1394048c6d88SGuido Kiener 	retval = send_request_dev_dep_msg_in(file_data, count);
1395d2ddce37SAlexandre Peixoto Ferreira 
1396d2ddce37SAlexandre Peixoto Ferreira 	if (retval < 0) {
1397ec34d08eSGuido Kiener 		if (file_data->auto_abort)
1398d2ddce37SAlexandre Peixoto Ferreira 			usbtmc_ioctl_abort_bulk_out(data);
1399d2ddce37SAlexandre Peixoto Ferreira 		goto exit;
1400d2ddce37SAlexandre Peixoto Ferreira 	}
1401d2ddce37SAlexandre Peixoto Ferreira 
1402d2ddce37SAlexandre Peixoto Ferreira 	/* Loop until we have fetched everything we requested */
14035b775f67SGreg Kroah-Hartman 	remaining = count;
1404b690020aSGuido Kiener 	actual = 0;
14055b775f67SGreg Kroah-Hartman 
14065b775f67SGreg Kroah-Hartman 	/* Send bulk URB */
14075b775f67SGreg Kroah-Hartman 	retval = usb_bulk_msg(data->usb_dev,
14085b775f67SGreg Kroah-Hartman 			      usb_rcvbulkpipe(data->usb_dev,
14095b775f67SGreg Kroah-Hartman 					      data->bulk_in),
1410d7604ff0SGuido Kiener 			      buffer, bufsize, &actual,
1411048c6d88SGuido Kiener 			      file_data->timeout);
14125b775f67SGreg Kroah-Hartman 
1413d7604ff0SGuido Kiener 	dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n",
1414d7604ff0SGuido Kiener 		__func__, retval, actual);
1415d2ddce37SAlexandre Peixoto Ferreira 
14165b775f67SGreg Kroah-Hartman 	/* Store bTag (in case we need to abort) */
14175b775f67SGreg Kroah-Hartman 	data->bTag_last_read = data->bTag;
14185b775f67SGreg Kroah-Hartman 
14195b775f67SGreg Kroah-Hartman 	if (retval < 0) {
1420ec34d08eSGuido Kiener 		if (file_data->auto_abort)
1421d2ddce37SAlexandre Peixoto Ferreira 			usbtmc_ioctl_abort_bulk_in(data);
1422d2ddce37SAlexandre Peixoto Ferreira 		goto exit;
1423d2ddce37SAlexandre Peixoto Ferreira 	}
1424d2ddce37SAlexandre Peixoto Ferreira 
1425d2ddce37SAlexandre Peixoto Ferreira 	/* Sanity checks for the header */
1426d2ddce37SAlexandre Peixoto Ferreira 	if (actual < USBTMC_HEADER_SIZE) {
1427d7604ff0SGuido Kiener 		dev_err(dev, "Device sent too small first packet: %u < %u\n",
1428d7604ff0SGuido Kiener 			actual, USBTMC_HEADER_SIZE);
1429ec34d08eSGuido Kiener 		if (file_data->auto_abort)
1430d2ddce37SAlexandre Peixoto Ferreira 			usbtmc_ioctl_abort_bulk_in(data);
1431d2ddce37SAlexandre Peixoto Ferreira 		goto exit;
1432d2ddce37SAlexandre Peixoto Ferreira 	}
1433d2ddce37SAlexandre Peixoto Ferreira 
1434d2ddce37SAlexandre Peixoto Ferreira 	if (buffer[0] != 2) {
1435d7604ff0SGuido Kiener 		dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n",
1436d7604ff0SGuido Kiener 			buffer[0]);
1437ec34d08eSGuido Kiener 		if (file_data->auto_abort)
1438d2ddce37SAlexandre Peixoto Ferreira 			usbtmc_ioctl_abort_bulk_in(data);
1439d2ddce37SAlexandre Peixoto Ferreira 		goto exit;
1440d2ddce37SAlexandre Peixoto Ferreira 	}
1441d2ddce37SAlexandre Peixoto Ferreira 
1442d2ddce37SAlexandre Peixoto Ferreira 	if (buffer[1] != data->bTag_last_write) {
1443d7604ff0SGuido Kiener 		dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n",
1444d7604ff0SGuido Kiener 		buffer[1], data->bTag_last_write);
1445ec34d08eSGuido Kiener 		if (file_data->auto_abort)
14465b775f67SGreg Kroah-Hartman 			usbtmc_ioctl_abort_bulk_in(data);
14475b775f67SGreg Kroah-Hartman 		goto exit;
14485b775f67SGreg Kroah-Hartman 	}
14495b775f67SGreg Kroah-Hartman 
14505b775f67SGreg Kroah-Hartman 	/* How many characters did the instrument send? */
14515b775f67SGreg Kroah-Hartman 	n_characters = buffer[4] +
14525b775f67SGreg Kroah-Hartman 		       (buffer[5] << 8) +
14535b775f67SGreg Kroah-Hartman 		       (buffer[6] << 16) +
14545b775f67SGreg Kroah-Hartman 		       (buffer[7] << 24);
14555b775f67SGreg Kroah-Hartman 
14568409e96fSGuido Kiener 	file_data->bmTransferAttributes = buffer[8];
14578409e96fSGuido Kiener 
1458d7604ff0SGuido Kiener 	dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n",
1459d7604ff0SGuido Kiener 		n_characters, buffer[8]);
1460d7604ff0SGuido Kiener 
1461d7604ff0SGuido Kiener 	if (n_characters > remaining) {
1462d7604ff0SGuido Kiener 		dev_err(dev, "Device wants to return more data than requested: %u > %zu\n",
1463d7604ff0SGuido Kiener 			n_characters, count);
1464ec34d08eSGuido Kiener 		if (file_data->auto_abort)
1465d2ddce37SAlexandre Peixoto Ferreira 			usbtmc_ioctl_abort_bulk_in(data);
1466d2ddce37SAlexandre Peixoto Ferreira 		goto exit;
1467665d7662SGuus Sliepen 	}
1468665d7662SGuus Sliepen 
1469d7604ff0SGuido Kiener 	print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
1470d7604ff0SGuido Kiener 			     16, 1, buffer, actual, true);
1471d7604ff0SGuido Kiener 
1472d7604ff0SGuido Kiener 	remaining = n_characters;
1473d7604ff0SGuido Kiener 
1474d2ddce37SAlexandre Peixoto Ferreira 	/* Remove the USBTMC header */
1475d2ddce37SAlexandre Peixoto Ferreira 	actual -= USBTMC_HEADER_SIZE;
1476d2ddce37SAlexandre Peixoto Ferreira 
1477d2ddce37SAlexandre Peixoto Ferreira 	/* Remove padding if it exists */
1478d2ddce37SAlexandre Peixoto Ferreira 	if (actual > remaining)
1479d2ddce37SAlexandre Peixoto Ferreira 		actual = remaining;
1480d2ddce37SAlexandre Peixoto Ferreira 
1481d2ddce37SAlexandre Peixoto Ferreira 	remaining -= actual;
1482d2ddce37SAlexandre Peixoto Ferreira 
14835b775f67SGreg Kroah-Hartman 	/* Copy buffer to user space */
1484d7604ff0SGuido Kiener 	if (copy_to_user(buf, &buffer[USBTMC_HEADER_SIZE], actual)) {
14855b775f67SGreg Kroah-Hartman 		/* There must have been an addressing problem */
14865b775f67SGreg Kroah-Hartman 		retval = -EFAULT;
14875b775f67SGreg Kroah-Hartman 		goto exit;
14885b775f67SGreg Kroah-Hartman 	}
14895b775f67SGreg Kroah-Hartman 
1490d7604ff0SGuido Kiener 	if ((actual + USBTMC_HEADER_SIZE) == bufsize) {
1491d7604ff0SGuido Kiener 		retval = usbtmc_generic_read(file_data, buf + actual,
1492d7604ff0SGuido Kiener 					     remaining,
1493d7604ff0SGuido Kiener 					     &done,
1494d7604ff0SGuido Kiener 					     USBTMC_FLAG_IGNORE_TRAILER);
1495d7604ff0SGuido Kiener 		if (retval < 0)
1496d2ddce37SAlexandre Peixoto Ferreira 			goto exit;
1497d2ddce37SAlexandre Peixoto Ferreira 	}
1498d2ddce37SAlexandre Peixoto Ferreira 	done += actual;
14995b775f67SGreg Kroah-Hartman 
15005b775f67SGreg Kroah-Hartman 	/* Update file position value */
15015b775f67SGreg Kroah-Hartman 	*f_pos = *f_pos + done;
15025b775f67SGreg Kroah-Hartman 	retval = done;
15035b775f67SGreg Kroah-Hartman 
15045b775f67SGreg Kroah-Hartman exit:
15055b775f67SGreg Kroah-Hartman 	mutex_unlock(&data->io_mutex);
15065b775f67SGreg Kroah-Hartman 	kfree(buffer);
15075b775f67SGreg Kroah-Hartman 	return retval;
15085b775f67SGreg Kroah-Hartman }
15095b775f67SGreg Kroah-Hartman 
usbtmc_write(struct file * filp,const char __user * buf,size_t count,loff_t * f_pos)15105b775f67SGreg Kroah-Hartman static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
15115b775f67SGreg Kroah-Hartman 			    size_t count, loff_t *f_pos)
15125b775f67SGreg Kroah-Hartman {
15134f3c8d6eSGuido Kiener 	struct usbtmc_file_data *file_data;
15145b775f67SGreg Kroah-Hartman 	struct usbtmc_device_data *data;
15154d5e18d9SGuido Kiener 	struct urb *urb = NULL;
15164d5e18d9SGuido Kiener 	ssize_t retval = 0;
15175b775f67SGreg Kroah-Hartman 	u8 *buffer;
15184d5e18d9SGuido Kiener 	u32 remaining, done;
15194d5e18d9SGuido Kiener 	u32 transfersize, aligned, buflen;
15205b775f67SGreg Kroah-Hartman 
15214f3c8d6eSGuido Kiener 	file_data = filp->private_data;
15224f3c8d6eSGuido Kiener 	data = file_data->data;
15235b775f67SGreg Kroah-Hartman 
15245b775f67SGreg Kroah-Hartman 	mutex_lock(&data->io_mutex);
15254d5e18d9SGuido Kiener 
152686286883SOliver Neukum 	if (data->zombie) {
152786286883SOliver Neukum 		retval = -ENODEV;
152886286883SOliver Neukum 		goto exit;
152986286883SOliver Neukum 	}
15305b775f67SGreg Kroah-Hartman 
15315b775f67SGreg Kroah-Hartman 	done = 0;
15325b775f67SGreg Kroah-Hartman 
15334d5e18d9SGuido Kiener 	spin_lock_irq(&file_data->err_lock);
15344d5e18d9SGuido Kiener 	file_data->out_transfer_size = 0;
15354d5e18d9SGuido Kiener 	file_data->out_status = 0;
15364d5e18d9SGuido Kiener 	spin_unlock_irq(&file_data->err_lock);
15374d5e18d9SGuido Kiener 
15384d5e18d9SGuido Kiener 	if (!count)
15394d5e18d9SGuido Kiener 		goto exit;
15404d5e18d9SGuido Kiener 
15414d5e18d9SGuido Kiener 	if (down_trylock(&file_data->limit_write_sem)) {
15424d5e18d9SGuido Kiener 		/* previous calls were async */
15434d5e18d9SGuido Kiener 		retval = -EBUSY;
15444d5e18d9SGuido Kiener 		goto exit;
15454d5e18d9SGuido Kiener 	}
15464d5e18d9SGuido Kiener 
15474d5e18d9SGuido Kiener 	urb = usbtmc_create_urb();
15484d5e18d9SGuido Kiener 	if (!urb) {
15494d5e18d9SGuido Kiener 		retval = -ENOMEM;
15504d5e18d9SGuido Kiener 		up(&file_data->limit_write_sem);
15514d5e18d9SGuido Kiener 		goto exit;
15524d5e18d9SGuido Kiener 	}
15534d5e18d9SGuido Kiener 
15544d5e18d9SGuido Kiener 	buffer = urb->transfer_buffer;
15554d5e18d9SGuido Kiener 	buflen = urb->transfer_buffer_length;
15564d5e18d9SGuido Kiener 
15574d5e18d9SGuido Kiener 	if (count > INT_MAX) {
15584d5e18d9SGuido Kiener 		transfersize = INT_MAX;
15595b775f67SGreg Kroah-Hartman 		buffer[8] = 0;
15605b775f67SGreg Kroah-Hartman 	} else {
15614d5e18d9SGuido Kiener 		transfersize = count;
1562fbd83971SGuido Kiener 		buffer[8] = file_data->eom_val;
15635b775f67SGreg Kroah-Hartman 	}
15645b775f67SGreg Kroah-Hartman 
15655b775f67SGreg Kroah-Hartman 	/* Setup IO buffer for DEV_DEP_MSG_OUT message */
15665b775f67SGreg Kroah-Hartman 	buffer[0] = 1;
15675b775f67SGreg Kroah-Hartman 	buffer[1] = data->bTag;
1568bbf4976eSAndy Shevchenko 	buffer[2] = ~data->bTag;
15695b775f67SGreg Kroah-Hartman 	buffer[3] = 0; /* Reserved */
15704d5e18d9SGuido Kiener 	buffer[4] = transfersize >> 0;
15714d5e18d9SGuido Kiener 	buffer[5] = transfersize >> 8;
15724d5e18d9SGuido Kiener 	buffer[6] = transfersize >> 16;
15734d5e18d9SGuido Kiener 	buffer[7] = transfersize >> 24;
15745b775f67SGreg Kroah-Hartman 	/* buffer[8] is set above... */
15755b775f67SGreg Kroah-Hartman 	buffer[9] = 0; /* Reserved */
15765b775f67SGreg Kroah-Hartman 	buffer[10] = 0; /* Reserved */
15775b775f67SGreg Kroah-Hartman 	buffer[11] = 0; /* Reserved */
15785b775f67SGreg Kroah-Hartman 
15794d5e18d9SGuido Kiener 	remaining = transfersize;
15804d5e18d9SGuido Kiener 
15814d5e18d9SGuido Kiener 	if (transfersize + USBTMC_HEADER_SIZE > buflen) {
15824d5e18d9SGuido Kiener 		transfersize = buflen - USBTMC_HEADER_SIZE;
15834d5e18d9SGuido Kiener 		aligned = buflen;
15844d5e18d9SGuido Kiener 	} else {
15854d5e18d9SGuido Kiener 		aligned = (transfersize + (USBTMC_HEADER_SIZE + 3)) & ~3;
15864d5e18d9SGuido Kiener 	}
15874d5e18d9SGuido Kiener 
15884d5e18d9SGuido Kiener 	if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf, transfersize)) {
15895b775f67SGreg Kroah-Hartman 		retval = -EFAULT;
15904d5e18d9SGuido Kiener 		up(&file_data->limit_write_sem);
15915b775f67SGreg Kroah-Hartman 		goto exit;
15925b775f67SGreg Kroah-Hartman 	}
15935b775f67SGreg Kroah-Hartman 
15944d5e18d9SGuido Kiener 	dev_dbg(&data->intf->dev, "%s(size:%u align:%u)\n", __func__,
15954d5e18d9SGuido Kiener 		(unsigned int)transfersize, (unsigned int)aligned);
15965b775f67SGreg Kroah-Hartman 
15974d5e18d9SGuido Kiener 	print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
15984d5e18d9SGuido Kiener 			     16, 1, buffer, aligned, true);
15994d5e18d9SGuido Kiener 
16004d5e18d9SGuido Kiener 	usb_fill_bulk_urb(urb, data->usb_dev,
16014d5e18d9SGuido Kiener 		usb_sndbulkpipe(data->usb_dev, data->bulk_out),
16024d5e18d9SGuido Kiener 		urb->transfer_buffer, aligned,
16034d5e18d9SGuido Kiener 		usbtmc_write_bulk_cb, file_data);
16044d5e18d9SGuido Kiener 
16054d5e18d9SGuido Kiener 	usb_anchor_urb(urb, &file_data->submitted);
16064d5e18d9SGuido Kiener 	retval = usb_submit_urb(urb, GFP_KERNEL);
16074d5e18d9SGuido Kiener 	if (unlikely(retval)) {
16084d5e18d9SGuido Kiener 		usb_unanchor_urb(urb);
16094d5e18d9SGuido Kiener 		up(&file_data->limit_write_sem);
16104d5e18d9SGuido Kiener 		goto exit;
16114d5e18d9SGuido Kiener 	}
16124d5e18d9SGuido Kiener 
16134d5e18d9SGuido Kiener 	remaining -= transfersize;
16145b775f67SGreg Kroah-Hartman 
16155b775f67SGreg Kroah-Hartman 	data->bTag_last_write = data->bTag;
16165b775f67SGreg Kroah-Hartman 	data->bTag++;
16175b775f67SGreg Kroah-Hartman 
16185b775f67SGreg Kroah-Hartman 	if (!data->bTag)
16195b775f67SGreg Kroah-Hartman 		data->bTag++;
16205b775f67SGreg Kroah-Hartman 
16214d5e18d9SGuido Kiener 	/* call generic_write even when remaining = 0 */
16224d5e18d9SGuido Kiener 	retval = usbtmc_generic_write(file_data, buf + transfersize, remaining,
16234d5e18d9SGuido Kiener 				      &done, USBTMC_FLAG_APPEND);
16244d5e18d9SGuido Kiener 	/* truncate alignment bytes */
16254d5e18d9SGuido Kiener 	if (done > remaining)
16264d5e18d9SGuido Kiener 		done = remaining;
16274d5e18d9SGuido Kiener 
16284d5e18d9SGuido Kiener 	/*add size of first urb*/
16294d5e18d9SGuido Kiener 	done += transfersize;
16304d5e18d9SGuido Kiener 
16315b775f67SGreg Kroah-Hartman 	if (retval < 0) {
16324d5e18d9SGuido Kiener 		usb_kill_anchored_urbs(&file_data->submitted);
16334d5e18d9SGuido Kiener 
16345b775f67SGreg Kroah-Hartman 		dev_err(&data->intf->dev,
16354d5e18d9SGuido Kiener 			"Unable to send data, error %d\n", (int)retval);
1636ec34d08eSGuido Kiener 		if (file_data->auto_abort)
16375b775f67SGreg Kroah-Hartman 			usbtmc_ioctl_abort_bulk_out(data);
16385b775f67SGreg Kroah-Hartman 		goto exit;
16395b775f67SGreg Kroah-Hartman 	}
16405b775f67SGreg Kroah-Hartman 
16414d5e18d9SGuido Kiener 	retval = done;
16425b775f67SGreg Kroah-Hartman exit:
16434d5e18d9SGuido Kiener 	usb_free_urb(urb);
16445b775f67SGreg Kroah-Hartman 	mutex_unlock(&data->io_mutex);
16455b775f67SGreg Kroah-Hartman 	return retval;
16465b775f67SGreg Kroah-Hartman }
16475b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_clear(struct usbtmc_device_data * data)16485b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
16495b775f67SGreg Kroah-Hartman {
16505b775f67SGreg Kroah-Hartman 	struct device *dev;
16515b775f67SGreg Kroah-Hartman 	u8 *buffer;
16525b775f67SGreg Kroah-Hartman 	int rv;
16535b775f67SGreg Kroah-Hartman 	int n;
1654ab53eb97SRickard Strandqvist 	int actual = 0;
16555b775f67SGreg Kroah-Hartman 
16565b775f67SGreg Kroah-Hartman 	dev = &data->intf->dev;
16575b775f67SGreg Kroah-Hartman 
16585b775f67SGreg Kroah-Hartman 	dev_dbg(dev, "Sending INITIATE_CLEAR request\n");
16595b775f67SGreg Kroah-Hartman 
1660dfee02acSGuido Kiener 	buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
16615b775f67SGreg Kroah-Hartman 	if (!buffer)
16625b775f67SGreg Kroah-Hartman 		return -ENOMEM;
16635b775f67SGreg Kroah-Hartman 
16645b775f67SGreg Kroah-Hartman 	rv = usb_control_msg(data->usb_dev,
16655b775f67SGreg Kroah-Hartman 			     usb_rcvctrlpipe(data->usb_dev, 0),
16665b775f67SGreg Kroah-Hartman 			     USBTMC_REQUEST_INITIATE_CLEAR,
16675b775f67SGreg Kroah-Hartman 			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
1668dfee02acSGuido Kiener 			     0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT);
16695b775f67SGreg Kroah-Hartman 	if (rv < 0) {
16705b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_control_msg returned %d\n", rv);
16715b775f67SGreg Kroah-Hartman 		goto exit;
16725b775f67SGreg Kroah-Hartman 	}
16735b775f67SGreg Kroah-Hartman 
16745b775f67SGreg Kroah-Hartman 	dev_dbg(dev, "INITIATE_CLEAR returned %x\n", buffer[0]);
16755b775f67SGreg Kroah-Hartman 
16765b775f67SGreg Kroah-Hartman 	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
16775b775f67SGreg Kroah-Hartman 		dev_err(dev, "INITIATE_CLEAR returned %x\n", buffer[0]);
16785b775f67SGreg Kroah-Hartman 		rv = -EPERM;
16795b775f67SGreg Kroah-Hartman 		goto exit;
16805b775f67SGreg Kroah-Hartman 	}
16815b775f67SGreg Kroah-Hartman 
16825b775f67SGreg Kroah-Hartman 	n = 0;
16835b775f67SGreg Kroah-Hartman 
16845b775f67SGreg Kroah-Hartman usbtmc_clear_check_status:
16855b775f67SGreg Kroah-Hartman 
16865b775f67SGreg Kroah-Hartman 	dev_dbg(dev, "Sending CHECK_CLEAR_STATUS request\n");
16875b775f67SGreg Kroah-Hartman 
16885b775f67SGreg Kroah-Hartman 	rv = usb_control_msg(data->usb_dev,
16895b775f67SGreg Kroah-Hartman 			     usb_rcvctrlpipe(data->usb_dev, 0),
16905b775f67SGreg Kroah-Hartman 			     USBTMC_REQUEST_CHECK_CLEAR_STATUS,
16915b775f67SGreg Kroah-Hartman 			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
1692dfee02acSGuido Kiener 			     0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT);
16935b775f67SGreg Kroah-Hartman 	if (rv < 0) {
16945b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_control_msg returned %d\n", rv);
16955b775f67SGreg Kroah-Hartman 		goto exit;
16965b775f67SGreg Kroah-Hartman 	}
16975b775f67SGreg Kroah-Hartman 
16985b775f67SGreg Kroah-Hartman 	dev_dbg(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]);
16995b775f67SGreg Kroah-Hartman 
17005b775f67SGreg Kroah-Hartman 	if (buffer[0] == USBTMC_STATUS_SUCCESS)
17015b775f67SGreg Kroah-Hartman 		goto usbtmc_clear_bulk_out_halt;
17025b775f67SGreg Kroah-Hartman 
17035b775f67SGreg Kroah-Hartman 	if (buffer[0] != USBTMC_STATUS_PENDING) {
17045b775f67SGreg Kroah-Hartman 		dev_err(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]);
17055b775f67SGreg Kroah-Hartman 		rv = -EPERM;
17065b775f67SGreg Kroah-Hartman 		goto exit;
17075b775f67SGreg Kroah-Hartman 	}
17085b775f67SGreg Kroah-Hartman 
1709dfee02acSGuido Kiener 	if ((buffer[1] & 1) != 0) {
17105b775f67SGreg Kroah-Hartman 		do {
17115b775f67SGreg Kroah-Hartman 			dev_dbg(dev, "Reading from bulk in EP\n");
17125b775f67SGreg Kroah-Hartman 
17139a831903SGuido Kiener 			actual = 0;
17145b775f67SGreg Kroah-Hartman 			rv = usb_bulk_msg(data->usb_dev,
17155b775f67SGreg Kroah-Hartman 					  usb_rcvbulkpipe(data->usb_dev,
17165b775f67SGreg Kroah-Hartman 							  data->bulk_in),
1717dfee02acSGuido Kiener 					  buffer, USBTMC_BUFSIZE,
1718dfee02acSGuido Kiener 					  &actual, USB_CTRL_GET_TIMEOUT);
1719dfee02acSGuido Kiener 
1720dfee02acSGuido Kiener 			print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
1721dfee02acSGuido Kiener 					     16, 1, buffer, actual, true);
1722dfee02acSGuido Kiener 
17235b775f67SGreg Kroah-Hartman 			n++;
17245b775f67SGreg Kroah-Hartman 
17255b775f67SGreg Kroah-Hartman 			if (rv < 0) {
17265b775f67SGreg Kroah-Hartman 				dev_err(dev, "usb_control_msg returned %d\n",
17275b775f67SGreg Kroah-Hartman 					rv);
17285b775f67SGreg Kroah-Hartman 				goto exit;
17295b775f67SGreg Kroah-Hartman 			}
1730dfee02acSGuido Kiener 		} while ((actual == USBTMC_BUFSIZE) &&
17315b775f67SGreg Kroah-Hartman 			  (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
1732dfee02acSGuido Kiener 	} else {
1733dfee02acSGuido Kiener 		/* do not stress device with subsequent requests */
1734dfee02acSGuido Kiener 		msleep(50);
1735dfee02acSGuido Kiener 		n++;
1736dfee02acSGuido Kiener 	}
17375b775f67SGreg Kroah-Hartman 
1738dfee02acSGuido Kiener 	if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) {
17395b775f67SGreg Kroah-Hartman 		dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
17405b775f67SGreg Kroah-Hartman 			USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
17415b775f67SGreg Kroah-Hartman 		rv = -EPERM;
17425b775f67SGreg Kroah-Hartman 		goto exit;
17435b775f67SGreg Kroah-Hartman 	}
17445b775f67SGreg Kroah-Hartman 
17455b775f67SGreg Kroah-Hartman 	goto usbtmc_clear_check_status;
17465b775f67SGreg Kroah-Hartman 
17475b775f67SGreg Kroah-Hartman usbtmc_clear_bulk_out_halt:
17485b775f67SGreg Kroah-Hartman 
17493342ecdaSSarah Sharp 	rv = usb_clear_halt(data->usb_dev,
17503342ecdaSSarah Sharp 			    usb_sndbulkpipe(data->usb_dev, data->bulk_out));
17515b775f67SGreg Kroah-Hartman 	if (rv < 0) {
1752dfee02acSGuido Kiener 		dev_err(dev, "usb_clear_halt returned %d\n", rv);
17535b775f67SGreg Kroah-Hartman 		goto exit;
17545b775f67SGreg Kroah-Hartman 	}
17555b775f67SGreg Kroah-Hartman 	rv = 0;
17565b775f67SGreg Kroah-Hartman 
17575b775f67SGreg Kroah-Hartman exit:
17585b775f67SGreg Kroah-Hartman 	kfree(buffer);
17595b775f67SGreg Kroah-Hartman 	return rv;
17605b775f67SGreg Kroah-Hartman }
17615b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data * data)17625b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
17635b775f67SGreg Kroah-Hartman {
17645b775f67SGreg Kroah-Hartman 	int rv;
17655b775f67SGreg Kroah-Hartman 
17663342ecdaSSarah Sharp 	rv = usb_clear_halt(data->usb_dev,
17673342ecdaSSarah Sharp 			    usb_sndbulkpipe(data->usb_dev, data->bulk_out));
17685b775f67SGreg Kroah-Hartman 
1769fd784cadSGuido Kiener 	if (rv < 0)
1770fd784cadSGuido Kiener 		dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
17715b775f67SGreg Kroah-Hartman 	return rv;
17725b775f67SGreg Kroah-Hartman }
17735b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data * data)17745b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
17755b775f67SGreg Kroah-Hartman {
17765b775f67SGreg Kroah-Hartman 	int rv;
17775b775f67SGreg Kroah-Hartman 
17783342ecdaSSarah Sharp 	rv = usb_clear_halt(data->usb_dev,
17793342ecdaSSarah Sharp 			    usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
17805b775f67SGreg Kroah-Hartman 
1781fd784cadSGuido Kiener 	if (rv < 0)
1782fd784cadSGuido Kiener 		dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
17835b775f67SGreg Kroah-Hartman 	return rv;
17845b775f67SGreg Kroah-Hartman }
17855b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_cancel_io(struct usbtmc_file_data * file_data)17864ddc645fSGuido Kiener static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data)
17874ddc645fSGuido Kiener {
17884ddc645fSGuido Kiener 	spin_lock_irq(&file_data->err_lock);
1789bb99794aSGuido Kiener 	file_data->in_status = -ECANCELED;
17904ddc645fSGuido Kiener 	file_data->out_status = -ECANCELED;
17914ddc645fSGuido Kiener 	spin_unlock_irq(&file_data->err_lock);
17924ddc645fSGuido Kiener 	usb_kill_anchored_urbs(&file_data->submitted);
17934ddc645fSGuido Kiener 	return 0;
17944ddc645fSGuido Kiener }
17954ddc645fSGuido Kiener 
usbtmc_ioctl_cleanup_io(struct usbtmc_file_data * file_data)1796987b8199SGuido Kiener static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data)
1797987b8199SGuido Kiener {
1798987b8199SGuido Kiener 	usb_kill_anchored_urbs(&file_data->submitted);
1799987b8199SGuido Kiener 	usb_scuttle_anchored_urbs(&file_data->in_anchor);
1800987b8199SGuido Kiener 	spin_lock_irq(&file_data->err_lock);
1801987b8199SGuido Kiener 	file_data->in_status = 0;
1802987b8199SGuido Kiener 	file_data->in_transfer_size = 0;
1803987b8199SGuido Kiener 	file_data->out_status = 0;
1804987b8199SGuido Kiener 	file_data->out_transfer_size = 0;
1805987b8199SGuido Kiener 	spin_unlock_irq(&file_data->err_lock);
1806987b8199SGuido Kiener 
1807987b8199SGuido Kiener 	file_data->in_urbs_used = 0;
1808987b8199SGuido Kiener 	return 0;
1809987b8199SGuido Kiener }
1810987b8199SGuido Kiener 
get_capabilities(struct usbtmc_device_data * data)18115b775f67SGreg Kroah-Hartman static int get_capabilities(struct usbtmc_device_data *data)
18125b775f67SGreg Kroah-Hartman {
18135b775f67SGreg Kroah-Hartman 	struct device *dev = &data->usb_dev->dev;
18145b775f67SGreg Kroah-Hartman 	char *buffer;
1815ca157c4aSOliver Neukum 	int rv = 0;
18165b775f67SGreg Kroah-Hartman 
18175b775f67SGreg Kroah-Hartman 	buffer = kmalloc(0x18, GFP_KERNEL);
18185b775f67SGreg Kroah-Hartman 	if (!buffer)
18195b775f67SGreg Kroah-Hartman 		return -ENOMEM;
18205b775f67SGreg Kroah-Hartman 
18215b775f67SGreg Kroah-Hartman 	rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0),
18225b775f67SGreg Kroah-Hartman 			     USBTMC_REQUEST_GET_CAPABILITIES,
18235b775f67SGreg Kroah-Hartman 			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
182463c97bbaSGuido Kiener 			     0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT);
18255b775f67SGreg Kroah-Hartman 	if (rv < 0) {
18265b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_control_msg returned %d\n", rv);
1827ca157c4aSOliver Neukum 		goto err_out;
18285b775f67SGreg Kroah-Hartman 	}
18295b775f67SGreg Kroah-Hartman 
18305b775f67SGreg Kroah-Hartman 	dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
18315b775f67SGreg Kroah-Hartman 	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
18325b775f67SGreg Kroah-Hartman 		dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
1833ca157c4aSOliver Neukum 		rv = -EPERM;
1834ca157c4aSOliver Neukum 		goto err_out;
18355b775f67SGreg Kroah-Hartman 	}
1836d0a38365SGergely Imreh 	dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]);
1837d0a38365SGergely Imreh 	dev_dbg(dev, "Device capabilities are %x\n", buffer[5]);
1838d0a38365SGergely Imreh 	dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]);
1839d0a38365SGergely Imreh 	dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);
18405b775f67SGreg Kroah-Hartman 
18415b775f67SGreg Kroah-Hartman 	data->capabilities.interface_capabilities = buffer[4];
18425b775f67SGreg Kroah-Hartman 	data->capabilities.device_capabilities = buffer[5];
18435b775f67SGreg Kroah-Hartman 	data->capabilities.usb488_interface_capabilities = buffer[14];
18445b775f67SGreg Kroah-Hartman 	data->capabilities.usb488_device_capabilities = buffer[15];
184529779d89SDave Penkler 	data->usb488_caps = (buffer[14] & 0x07) | ((buffer[15] & 0x0f) << 4);
1846d0a38365SGergely Imreh 	rv = 0;
18475b775f67SGreg Kroah-Hartman 
1848ca157c4aSOliver Neukum err_out:
18495b775f67SGreg Kroah-Hartman 	kfree(buffer);
1850ca157c4aSOliver Neukum 	return rv;
18515b775f67SGreg Kroah-Hartman }
18525b775f67SGreg Kroah-Hartman 
18535b775f67SGreg Kroah-Hartman #define capability_attribute(name)					\
18542a6eb8acSGreg Kroah-Hartman static ssize_t name##_show(struct device *dev,				\
18555b775f67SGreg Kroah-Hartman 			   struct device_attribute *attr, char *buf)	\
18565b775f67SGreg Kroah-Hartman {									\
18575b775f67SGreg Kroah-Hartman 	struct usb_interface *intf = to_usb_interface(dev);		\
18585b775f67SGreg Kroah-Hartman 	struct usbtmc_device_data *data = usb_get_intfdata(intf);	\
18595b775f67SGreg Kroah-Hartman 									\
18605b775f67SGreg Kroah-Hartman 	return sprintf(buf, "%d\n", data->capabilities.name);		\
18615b775f67SGreg Kroah-Hartman }									\
18622a6eb8acSGreg Kroah-Hartman static DEVICE_ATTR_RO(name)
18635b775f67SGreg Kroah-Hartman 
18645b775f67SGreg Kroah-Hartman capability_attribute(interface_capabilities);
18655b775f67SGreg Kroah-Hartman capability_attribute(device_capabilities);
18665b775f67SGreg Kroah-Hartman capability_attribute(usb488_interface_capabilities);
18675b775f67SGreg Kroah-Hartman capability_attribute(usb488_device_capabilities);
18685b775f67SGreg Kroah-Hartman 
186904a0625eSGreg Kroah-Hartman static struct attribute *usbtmc_attrs[] = {
18705b775f67SGreg Kroah-Hartman 	&dev_attr_interface_capabilities.attr,
18715b775f67SGreg Kroah-Hartman 	&dev_attr_device_capabilities.attr,
18725b775f67SGreg Kroah-Hartman 	&dev_attr_usb488_interface_capabilities.attr,
18735b775f67SGreg Kroah-Hartman 	&dev_attr_usb488_device_capabilities.attr,
18745b775f67SGreg Kroah-Hartman 	NULL,
18755b775f67SGreg Kroah-Hartman };
187604a0625eSGreg Kroah-Hartman ATTRIBUTE_GROUPS(usbtmc);
18775b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data * data)18785b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
18795b775f67SGreg Kroah-Hartman {
18805b775f67SGreg Kroah-Hartman 	struct device *dev;
18815b775f67SGreg Kroah-Hartman 	u8 *buffer;
18825b775f67SGreg Kroah-Hartman 	int rv;
18835b775f67SGreg Kroah-Hartman 
18845b775f67SGreg Kroah-Hartman 	dev = &data->intf->dev;
18855b775f67SGreg Kroah-Hartman 
18865b775f67SGreg Kroah-Hartman 	buffer = kmalloc(2, GFP_KERNEL);
18875b775f67SGreg Kroah-Hartman 	if (!buffer)
18885b775f67SGreg Kroah-Hartman 		return -ENOMEM;
18895b775f67SGreg Kroah-Hartman 
18905b775f67SGreg Kroah-Hartman 	rv = usb_control_msg(data->usb_dev,
18915b775f67SGreg Kroah-Hartman 			     usb_rcvctrlpipe(data->usb_dev, 0),
18925b775f67SGreg Kroah-Hartman 			     USBTMC_REQUEST_INDICATOR_PULSE,
18935b775f67SGreg Kroah-Hartman 			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
189463c97bbaSGuido Kiener 			     0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT);
18955b775f67SGreg Kroah-Hartman 
18965b775f67SGreg Kroah-Hartman 	if (rv < 0) {
18975b775f67SGreg Kroah-Hartman 		dev_err(dev, "usb_control_msg returned %d\n", rv);
18985b775f67SGreg Kroah-Hartman 		goto exit;
18995b775f67SGreg Kroah-Hartman 	}
19005b775f67SGreg Kroah-Hartman 
19015b775f67SGreg Kroah-Hartman 	dev_dbg(dev, "INDICATOR_PULSE returned %x\n", buffer[0]);
19025b775f67SGreg Kroah-Hartman 
19035b775f67SGreg Kroah-Hartman 	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
19045b775f67SGreg Kroah-Hartman 		dev_err(dev, "INDICATOR_PULSE returned %x\n", buffer[0]);
19055b775f67SGreg Kroah-Hartman 		rv = -EPERM;
19065b775f67SGreg Kroah-Hartman 		goto exit;
19075b775f67SGreg Kroah-Hartman 	}
19085b775f67SGreg Kroah-Hartman 	rv = 0;
19095b775f67SGreg Kroah-Hartman 
19105b775f67SGreg Kroah-Hartman exit:
19115b775f67SGreg Kroah-Hartman 	kfree(buffer);
19125b775f67SGreg Kroah-Hartman 	return rv;
19135b775f67SGreg Kroah-Hartman }
19145b775f67SGreg Kroah-Hartman 
usbtmc_ioctl_request(struct usbtmc_device_data * data,void __user * arg)1915658f24f4SGuido Kiener static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
1916658f24f4SGuido Kiener 				void __user *arg)
1917658f24f4SGuido Kiener {
1918658f24f4SGuido Kiener 	struct device *dev = &data->intf->dev;
1919658f24f4SGuido Kiener 	struct usbtmc_ctrlrequest request;
1920658f24f4SGuido Kiener 	u8 *buffer = NULL;
1921658f24f4SGuido Kiener 	int rv;
1922e9b667a8SAlan Stern 	unsigned int is_in, pipe;
1923658f24f4SGuido Kiener 	unsigned long res;
1924658f24f4SGuido Kiener 
1925658f24f4SGuido Kiener 	res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest));
1926658f24f4SGuido Kiener 	if (res)
1927658f24f4SGuido Kiener 		return -EFAULT;
1928658f24f4SGuido Kiener 
1929658f24f4SGuido Kiener 	if (request.req.wLength > USBTMC_BUFSIZE)
1930658f24f4SGuido Kiener 		return -EMSGSIZE;
1931*94d25e91SAlan Stern 	if (request.req.wLength == 0)	/* Length-0 requests are never IN */
1932*94d25e91SAlan Stern 		request.req.bRequestType &= ~USB_DIR_IN;
1933658f24f4SGuido Kiener 
1934e9b667a8SAlan Stern 	is_in = request.req.bRequestType & USB_DIR_IN;
1935e9b667a8SAlan Stern 
1936658f24f4SGuido Kiener 	if (request.req.wLength) {
1937658f24f4SGuido Kiener 		buffer = kmalloc(request.req.wLength, GFP_KERNEL);
1938658f24f4SGuido Kiener 		if (!buffer)
1939658f24f4SGuido Kiener 			return -ENOMEM;
1940658f24f4SGuido Kiener 
1941e9b667a8SAlan Stern 		if (!is_in) {
1942658f24f4SGuido Kiener 			/* Send control data to device */
1943658f24f4SGuido Kiener 			res = copy_from_user(buffer, request.data,
1944658f24f4SGuido Kiener 					     request.req.wLength);
1945658f24f4SGuido Kiener 			if (res) {
1946658f24f4SGuido Kiener 				rv = -EFAULT;
1947658f24f4SGuido Kiener 				goto exit;
1948658f24f4SGuido Kiener 			}
1949658f24f4SGuido Kiener 		}
1950658f24f4SGuido Kiener 	}
1951658f24f4SGuido Kiener 
1952e9b667a8SAlan Stern 	if (is_in)
1953e9b667a8SAlan Stern 		pipe = usb_rcvctrlpipe(data->usb_dev, 0);
1954e9b667a8SAlan Stern 	else
1955e9b667a8SAlan Stern 		pipe = usb_sndctrlpipe(data->usb_dev, 0);
1956658f24f4SGuido Kiener 	rv = usb_control_msg(data->usb_dev,
1957e9b667a8SAlan Stern 			pipe,
1958658f24f4SGuido Kiener 			request.req.bRequest,
1959658f24f4SGuido Kiener 			request.req.bRequestType,
1960658f24f4SGuido Kiener 			request.req.wValue,
1961658f24f4SGuido Kiener 			request.req.wIndex,
1962658f24f4SGuido Kiener 			buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
1963658f24f4SGuido Kiener 
1964658f24f4SGuido Kiener 	if (rv < 0) {
1965658f24f4SGuido Kiener 		dev_err(dev, "%s failed %d\n", __func__, rv);
1966658f24f4SGuido Kiener 		goto exit;
1967658f24f4SGuido Kiener 	}
1968658f24f4SGuido Kiener 
1969e9b667a8SAlan Stern 	if (rv && is_in) {
1970658f24f4SGuido Kiener 		/* Read control data from device */
1971658f24f4SGuido Kiener 		res = copy_to_user(request.data, buffer, rv);
1972658f24f4SGuido Kiener 		if (res)
1973658f24f4SGuido Kiener 			rv = -EFAULT;
1974658f24f4SGuido Kiener 	}
1975658f24f4SGuido Kiener 
1976658f24f4SGuido Kiener  exit:
1977658f24f4SGuido Kiener 	kfree(buffer);
1978658f24f4SGuido Kiener 	return rv;
1979658f24f4SGuido Kiener }
1980658f24f4SGuido Kiener 
1981048c6d88SGuido Kiener /*
1982048c6d88SGuido Kiener  * Get the usb timeout value
1983048c6d88SGuido Kiener  */
usbtmc_ioctl_get_timeout(struct usbtmc_file_data * file_data,void __user * arg)1984048c6d88SGuido Kiener static int usbtmc_ioctl_get_timeout(struct usbtmc_file_data *file_data,
1985048c6d88SGuido Kiener 				void __user *arg)
1986048c6d88SGuido Kiener {
1987048c6d88SGuido Kiener 	u32 timeout;
1988048c6d88SGuido Kiener 
1989048c6d88SGuido Kiener 	timeout = file_data->timeout;
1990048c6d88SGuido Kiener 
1991048c6d88SGuido Kiener 	return put_user(timeout, (__u32 __user *)arg);
1992048c6d88SGuido Kiener }
1993048c6d88SGuido Kiener 
1994048c6d88SGuido Kiener /*
1995048c6d88SGuido Kiener  * Set the usb timeout value
1996048c6d88SGuido Kiener  */
usbtmc_ioctl_set_timeout(struct usbtmc_file_data * file_data,void __user * arg)1997048c6d88SGuido Kiener static int usbtmc_ioctl_set_timeout(struct usbtmc_file_data *file_data,
1998048c6d88SGuido Kiener 				void __user *arg)
1999048c6d88SGuido Kiener {
2000048c6d88SGuido Kiener 	u32 timeout;
2001048c6d88SGuido Kiener 
2002048c6d88SGuido Kiener 	if (get_user(timeout, (__u32 __user *)arg))
2003048c6d88SGuido Kiener 		return -EFAULT;
2004048c6d88SGuido Kiener 
2005048c6d88SGuido Kiener 	/* Note that timeout = 0 means
2006048c6d88SGuido Kiener 	 * MAX_SCHEDULE_TIMEOUT in usb_control_msg
2007048c6d88SGuido Kiener 	 */
2008048c6d88SGuido Kiener 	if (timeout < USBTMC_MIN_TIMEOUT)
2009048c6d88SGuido Kiener 		return -EINVAL;
2010048c6d88SGuido Kiener 
2011048c6d88SGuido Kiener 	file_data->timeout = timeout;
2012048c6d88SGuido Kiener 
2013048c6d88SGuido Kiener 	return 0;
2014048c6d88SGuido Kiener }
2015048c6d88SGuido Kiener 
2016fbd83971SGuido Kiener /*
2017fbd83971SGuido Kiener  * enables/disables sending EOM on write
2018fbd83971SGuido Kiener  */
usbtmc_ioctl_eom_enable(struct usbtmc_file_data * file_data,void __user * arg)2019fbd83971SGuido Kiener static int usbtmc_ioctl_eom_enable(struct usbtmc_file_data *file_data,
2020fbd83971SGuido Kiener 				void __user *arg)
2021fbd83971SGuido Kiener {
2022fbd83971SGuido Kiener 	u8 eom_enable;
2023fbd83971SGuido Kiener 
2024fbd83971SGuido Kiener 	if (copy_from_user(&eom_enable, arg, sizeof(eom_enable)))
2025fbd83971SGuido Kiener 		return -EFAULT;
2026fbd83971SGuido Kiener 
2027fbd83971SGuido Kiener 	if (eom_enable > 1)
2028fbd83971SGuido Kiener 		return -EINVAL;
2029fbd83971SGuido Kiener 
2030fbd83971SGuido Kiener 	file_data->eom_val = eom_enable;
2031fbd83971SGuido Kiener 
2032fbd83971SGuido Kiener 	return 0;
2033fbd83971SGuido Kiener }
2034fbd83971SGuido Kiener 
203512dcaeb7SGuido Kiener /*
203612dcaeb7SGuido Kiener  * Configure termination character for read()
203712dcaeb7SGuido Kiener  */
usbtmc_ioctl_config_termc(struct usbtmc_file_data * file_data,void __user * arg)203812dcaeb7SGuido Kiener static int usbtmc_ioctl_config_termc(struct usbtmc_file_data *file_data,
203912dcaeb7SGuido Kiener 				void __user *arg)
204012dcaeb7SGuido Kiener {
204112dcaeb7SGuido Kiener 	struct usbtmc_termchar termc;
204212dcaeb7SGuido Kiener 
204312dcaeb7SGuido Kiener 	if (copy_from_user(&termc, arg, sizeof(termc)))
204412dcaeb7SGuido Kiener 		return -EFAULT;
204512dcaeb7SGuido Kiener 
204612dcaeb7SGuido Kiener 	if ((termc.term_char_enabled > 1) ||
204712dcaeb7SGuido Kiener 		(termc.term_char_enabled &&
204812dcaeb7SGuido Kiener 		!(file_data->data->capabilities.device_capabilities & 1)))
204912dcaeb7SGuido Kiener 		return -EINVAL;
205012dcaeb7SGuido Kiener 
205112dcaeb7SGuido Kiener 	file_data->term_char = termc.term_char;
205212dcaeb7SGuido Kiener 	file_data->term_char_enabled = termc.term_char_enabled;
205312dcaeb7SGuido Kiener 
205412dcaeb7SGuido Kiener 	return 0;
205512dcaeb7SGuido Kiener }
205612dcaeb7SGuido Kiener 
usbtmc_ioctl(struct file * file,unsigned int cmd,unsigned long arg)20575b775f67SGreg Kroah-Hartman static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
20585b775f67SGreg Kroah-Hartman {
20594f3c8d6eSGuido Kiener 	struct usbtmc_file_data *file_data;
20605b775f67SGreg Kroah-Hartman 	struct usbtmc_device_data *data;
20615b775f67SGreg Kroah-Hartman 	int retval = -EBADRQC;
2062ec34d08eSGuido Kiener 	__u8 tmp_byte;
20635b775f67SGreg Kroah-Hartman 
20644f3c8d6eSGuido Kiener 	file_data = file->private_data;
20654f3c8d6eSGuido Kiener 	data = file_data->data;
20664f3c8d6eSGuido Kiener 
20675b775f67SGreg Kroah-Hartman 	mutex_lock(&data->io_mutex);
206886286883SOliver Neukum 	if (data->zombie) {
206986286883SOliver Neukum 		retval = -ENODEV;
207086286883SOliver Neukum 		goto skip_io_on_zombie;
207186286883SOliver Neukum 	}
20725b775f67SGreg Kroah-Hartman 
20735b775f67SGreg Kroah-Hartman 	switch (cmd) {
20745b775f67SGreg Kroah-Hartman 	case USBTMC_IOCTL_CLEAR_OUT_HALT:
20755b775f67SGreg Kroah-Hartman 		retval = usbtmc_ioctl_clear_out_halt(data);
2076a92b63e7SGreg Kroah-Hartman 		break;
20775b775f67SGreg Kroah-Hartman 
20785b775f67SGreg Kroah-Hartman 	case USBTMC_IOCTL_CLEAR_IN_HALT:
20795b775f67SGreg Kroah-Hartman 		retval = usbtmc_ioctl_clear_in_halt(data);
2080a92b63e7SGreg Kroah-Hartman 		break;
20815b775f67SGreg Kroah-Hartman 
20825b775f67SGreg Kroah-Hartman 	case USBTMC_IOCTL_INDICATOR_PULSE:
20835b775f67SGreg Kroah-Hartman 		retval = usbtmc_ioctl_indicator_pulse(data);
2084a92b63e7SGreg Kroah-Hartman 		break;
20855b775f67SGreg Kroah-Hartman 
20865b775f67SGreg Kroah-Hartman 	case USBTMC_IOCTL_CLEAR:
20875b775f67SGreg Kroah-Hartman 		retval = usbtmc_ioctl_clear(data);
2088a92b63e7SGreg Kroah-Hartman 		break;
20895b775f67SGreg Kroah-Hartman 
20905b775f67SGreg Kroah-Hartman 	case USBTMC_IOCTL_ABORT_BULK_OUT:
20915b775f67SGreg Kroah-Hartman 		retval = usbtmc_ioctl_abort_bulk_out(data);
2092a92b63e7SGreg Kroah-Hartman 		break;
20935b775f67SGreg Kroah-Hartman 
20945b775f67SGreg Kroah-Hartman 	case USBTMC_IOCTL_ABORT_BULK_IN:
20955b775f67SGreg Kroah-Hartman 		retval = usbtmc_ioctl_abort_bulk_in(data);
2096a92b63e7SGreg Kroah-Hartman 		break;
2097dbf3e7f6SDave Penkler 
2098658f24f4SGuido Kiener 	case USBTMC_IOCTL_CTRL_REQUEST:
2099658f24f4SGuido Kiener 		retval = usbtmc_ioctl_request(data, (void __user *)arg);
2100658f24f4SGuido Kiener 		break;
2101658f24f4SGuido Kiener 
2102048c6d88SGuido Kiener 	case USBTMC_IOCTL_GET_TIMEOUT:
2103048c6d88SGuido Kiener 		retval = usbtmc_ioctl_get_timeout(file_data,
2104048c6d88SGuido Kiener 						  (void __user *)arg);
2105048c6d88SGuido Kiener 		break;
2106048c6d88SGuido Kiener 
2107048c6d88SGuido Kiener 	case USBTMC_IOCTL_SET_TIMEOUT:
2108048c6d88SGuido Kiener 		retval = usbtmc_ioctl_set_timeout(file_data,
2109048c6d88SGuido Kiener 						  (void __user *)arg);
2110048c6d88SGuido Kiener 		break;
2111048c6d88SGuido Kiener 
2112fbd83971SGuido Kiener 	case USBTMC_IOCTL_EOM_ENABLE:
2113fbd83971SGuido Kiener 		retval = usbtmc_ioctl_eom_enable(file_data,
2114fbd83971SGuido Kiener 						 (void __user *)arg);
2115fbd83971SGuido Kiener 		break;
2116fbd83971SGuido Kiener 
211712dcaeb7SGuido Kiener 	case USBTMC_IOCTL_CONFIG_TERMCHAR:
211812dcaeb7SGuido Kiener 		retval = usbtmc_ioctl_config_termc(file_data,
211912dcaeb7SGuido Kiener 						   (void __user *)arg);
212012dcaeb7SGuido Kiener 		break;
212112dcaeb7SGuido Kiener 
21224ddc645fSGuido Kiener 	case USBTMC_IOCTL_WRITE:
21234ddc645fSGuido Kiener 		retval = usbtmc_ioctl_generic_write(file_data,
21244ddc645fSGuido Kiener 						    (void __user *)arg);
21254ddc645fSGuido Kiener 		break;
21264ddc645fSGuido Kiener 
2127bb99794aSGuido Kiener 	case USBTMC_IOCTL_READ:
2128bb99794aSGuido Kiener 		retval = usbtmc_ioctl_generic_read(file_data,
2129bb99794aSGuido Kiener 						   (void __user *)arg);
2130bb99794aSGuido Kiener 		break;
2131bb99794aSGuido Kiener 
2132b1498451SGuido Kiener 	case USBTMC_IOCTL_WRITE_RESULT:
2133b1498451SGuido Kiener 		retval = usbtmc_ioctl_write_result(file_data,
2134b1498451SGuido Kiener 						   (void __user *)arg);
2135b1498451SGuido Kiener 		break;
2136b1498451SGuido Kiener 
2137e013477bSGuido Kiener 	case USBTMC_IOCTL_API_VERSION:
2138e013477bSGuido Kiener 		retval = put_user(USBTMC_API_VERSION,
2139e013477bSGuido Kiener 				  (__u32 __user *)arg);
2140e013477bSGuido Kiener 		break;
2141e013477bSGuido Kiener 
214229779d89SDave Penkler 	case USBTMC488_IOCTL_GET_CAPS:
2143fd784cadSGuido Kiener 		retval = put_user(data->usb488_caps,
2144fd784cadSGuido Kiener 				  (unsigned char __user *)arg);
214529779d89SDave Penkler 		break;
214629779d89SDave Penkler 
2147dbf3e7f6SDave Penkler 	case USBTMC488_IOCTL_READ_STB:
21484f3c8d6eSGuido Kiener 		retval = usbtmc488_ioctl_read_stb(file_data,
21494f3c8d6eSGuido Kiener 						  (void __user *)arg);
2150dbf3e7f6SDave Penkler 		break;
2151379d3d33SDave Penkler 
2152379d3d33SDave Penkler 	case USBTMC488_IOCTL_REN_CONTROL:
2153379d3d33SDave Penkler 		retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
2154379d3d33SDave Penkler 						USBTMC488_REQUEST_REN_CONTROL);
2155379d3d33SDave Penkler 		break;
2156379d3d33SDave Penkler 
2157379d3d33SDave Penkler 	case USBTMC488_IOCTL_GOTO_LOCAL:
2158379d3d33SDave Penkler 		retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
2159379d3d33SDave Penkler 						USBTMC488_REQUEST_GOTO_LOCAL);
2160379d3d33SDave Penkler 		break;
2161379d3d33SDave Penkler 
2162379d3d33SDave Penkler 	case USBTMC488_IOCTL_LOCAL_LOCKOUT:
2163379d3d33SDave Penkler 		retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
2164379d3d33SDave Penkler 						USBTMC488_REQUEST_LOCAL_LOCKOUT);
2165379d3d33SDave Penkler 		break;
2166fe78a7c6SGuido Kiener 
2167fe78a7c6SGuido Kiener 	case USBTMC488_IOCTL_TRIGGER:
2168fe78a7c6SGuido Kiener 		retval = usbtmc488_ioctl_trigger(file_data);
2169fe78a7c6SGuido Kiener 		break;
217046ecc9d5SGuido Kiener 
2171739240a9SGuido Kiener 	case USBTMC488_IOCTL_WAIT_SRQ:
2172739240a9SGuido Kiener 		retval = usbtmc488_ioctl_wait_srq(file_data,
2173739240a9SGuido Kiener 						  (__u32 __user *)arg);
2174739240a9SGuido Kiener 		break;
2175739240a9SGuido Kiener 
21768409e96fSGuido Kiener 	case USBTMC_IOCTL_MSG_IN_ATTR:
21778409e96fSGuido Kiener 		retval = put_user(file_data->bmTransferAttributes,
21788409e96fSGuido Kiener 				  (__u8 __user *)arg);
21798409e96fSGuido Kiener 		break;
21808409e96fSGuido Kiener 
2181ec34d08eSGuido Kiener 	case USBTMC_IOCTL_AUTO_ABORT:
2182ec34d08eSGuido Kiener 		retval = get_user(tmp_byte, (unsigned char __user *)arg);
2183ec34d08eSGuido Kiener 		if (retval == 0)
2184ec34d08eSGuido Kiener 			file_data->auto_abort = !!tmp_byte;
2185ec34d08eSGuido Kiener 		break;
2186ec34d08eSGuido Kiener 
2187c9784e23SDave Penkler 	case USBTMC_IOCTL_GET_STB:
2188c9784e23SDave Penkler 		retval = usbtmc_get_stb(file_data, &tmp_byte);
2189c9784e23SDave Penkler 		if (retval > 0)
2190c9784e23SDave Penkler 			retval = put_user(tmp_byte, (__u8 __user *)arg);
2191c9784e23SDave Penkler 		break;
2192c9784e23SDave Penkler 
2193d1d9defdSDave Penkler 	case USBTMC_IOCTL_GET_SRQ_STB:
2194d1d9defdSDave Penkler 		retval = usbtmc_ioctl_get_srq_stb(file_data,
2195d1d9defdSDave Penkler 						  (void __user *)arg);
2196d1d9defdSDave Penkler 		break;
2197d1d9defdSDave Penkler 
219846ecc9d5SGuido Kiener 	case USBTMC_IOCTL_CANCEL_IO:
219946ecc9d5SGuido Kiener 		retval = usbtmc_ioctl_cancel_io(file_data);
220046ecc9d5SGuido Kiener 		break;
2201987b8199SGuido Kiener 
2202987b8199SGuido Kiener 	case USBTMC_IOCTL_CLEANUP_IO:
2203987b8199SGuido Kiener 		retval = usbtmc_ioctl_cleanup_io(file_data);
2204987b8199SGuido Kiener 		break;
22055b775f67SGreg Kroah-Hartman 	}
22065b775f67SGreg Kroah-Hartman 
220786286883SOliver Neukum skip_io_on_zombie:
22085b775f67SGreg Kroah-Hartman 	mutex_unlock(&data->io_mutex);
22095b775f67SGreg Kroah-Hartman 	return retval;
22105b775f67SGreg Kroah-Hartman }
22115b775f67SGreg Kroah-Hartman 
usbtmc_fasync(int fd,struct file * file,int on)221282ed3381SDave Penkler static int usbtmc_fasync(int fd, struct file *file, int on)
221382ed3381SDave Penkler {
22144f3c8d6eSGuido Kiener 	struct usbtmc_file_data *file_data = file->private_data;
221582ed3381SDave Penkler 
22164f3c8d6eSGuido Kiener 	return fasync_helper(fd, file, on, &file_data->data->fasync);
221782ed3381SDave Penkler }
221882ed3381SDave Penkler 
usbtmc_poll(struct file * file,poll_table * wait)2219afc9a42bSAl Viro static __poll_t usbtmc_poll(struct file *file, poll_table *wait)
2220eb6b92ecSDave Penkler {
22214f3c8d6eSGuido Kiener 	struct usbtmc_file_data *file_data = file->private_data;
22224f3c8d6eSGuido Kiener 	struct usbtmc_device_data *data = file_data->data;
2223afc9a42bSAl Viro 	__poll_t mask;
2224eb6b92ecSDave Penkler 
2225eb6b92ecSDave Penkler 	mutex_lock(&data->io_mutex);
2226eb6b92ecSDave Penkler 
2227eb6b92ecSDave Penkler 	if (data->zombie) {
2228a9a08845SLinus Torvalds 		mask = EPOLLHUP | EPOLLERR;
2229eb6b92ecSDave Penkler 		goto no_poll;
2230eb6b92ecSDave Penkler 	}
2231eb6b92ecSDave Penkler 
2232eb6b92ecSDave Penkler 	poll_wait(file, &data->waitq, wait);
2233eb6b92ecSDave Penkler 
2234bb99794aSGuido Kiener 	/* Note that EPOLLPRI is now assigned to SRQ, and
2235bb99794aSGuido Kiener 	 * EPOLLIN|EPOLLRDNORM to normal read data.
2236bb99794aSGuido Kiener 	 */
22374ddc645fSGuido Kiener 	mask = 0;
22384ddc645fSGuido Kiener 	if (atomic_read(&file_data->srq_asserted))
22394ddc645fSGuido Kiener 		mask |= EPOLLPRI;
22404ddc645fSGuido Kiener 
2241bb99794aSGuido Kiener 	/* Note that the anchor submitted includes all urbs for BULK IN
2242bb99794aSGuido Kiener 	 * and OUT. So EPOLLOUT is signaled when BULK OUT is empty and
2243bb99794aSGuido Kiener 	 * all BULK IN urbs are completed and moved to in_anchor.
2244bb99794aSGuido Kiener 	 */
22454ddc645fSGuido Kiener 	if (usb_anchor_empty(&file_data->submitted))
22464ddc645fSGuido Kiener 		mask |= (EPOLLOUT | EPOLLWRNORM);
2247bb99794aSGuido Kiener 	if (!usb_anchor_empty(&file_data->in_anchor))
2248bb99794aSGuido Kiener 		mask |= (EPOLLIN | EPOLLRDNORM);
22494ddc645fSGuido Kiener 
22504ddc645fSGuido Kiener 	spin_lock_irq(&file_data->err_lock);
2251bb99794aSGuido Kiener 	if (file_data->in_status || file_data->out_status)
22524ddc645fSGuido Kiener 		mask |= EPOLLERR;
22534ddc645fSGuido Kiener 	spin_unlock_irq(&file_data->err_lock);
22544ddc645fSGuido Kiener 
22554ddc645fSGuido Kiener 	dev_dbg(&data->intf->dev, "poll mask = %x\n", mask);
2256eb6b92ecSDave Penkler 
2257eb6b92ecSDave Penkler no_poll:
2258eb6b92ecSDave Penkler 	mutex_unlock(&data->io_mutex);
2259eb6b92ecSDave Penkler 	return mask;
2260eb6b92ecSDave Penkler }
2261eb6b92ecSDave Penkler 
2262828c0950SAlexey Dobriyan static const struct file_operations fops = {
22635b775f67SGreg Kroah-Hartman 	.owner		= THIS_MODULE,
22645b775f67SGreg Kroah-Hartman 	.read		= usbtmc_read,
22655b775f67SGreg Kroah-Hartman 	.write		= usbtmc_write,
22665b775f67SGreg Kroah-Hartman 	.open		= usbtmc_open,
22675b775f67SGreg Kroah-Hartman 	.release	= usbtmc_release,
22684ddc645fSGuido Kiener 	.flush		= usbtmc_flush,
22695b775f67SGreg Kroah-Hartman 	.unlocked_ioctl	= usbtmc_ioctl,
22701832f2d8SArnd Bergmann 	.compat_ioctl	= compat_ptr_ioctl,
227182ed3381SDave Penkler 	.fasync         = usbtmc_fasync,
2272eb6b92ecSDave Penkler 	.poll           = usbtmc_poll,
22736038f373SArnd Bergmann 	.llseek		= default_llseek,
22745b775f67SGreg Kroah-Hartman };
22755b775f67SGreg Kroah-Hartman 
22765b775f67SGreg Kroah-Hartman static struct usb_class_driver usbtmc_class = {
22775b775f67SGreg Kroah-Hartman 	.name =		"usbtmc%d",
22785b775f67SGreg Kroah-Hartman 	.fops =		&fops,
22795b775f67SGreg Kroah-Hartman 	.minor_base =	USBTMC_MINOR_BASE,
22805b775f67SGreg Kroah-Hartman };
22815b775f67SGreg Kroah-Hartman 
usbtmc_interrupt(struct urb * urb)2282dbf3e7f6SDave Penkler static void usbtmc_interrupt(struct urb *urb)
2283dbf3e7f6SDave Penkler {
2284dbf3e7f6SDave Penkler 	struct usbtmc_device_data *data = urb->context;
2285dbf3e7f6SDave Penkler 	struct device *dev = &data->intf->dev;
2286dbf3e7f6SDave Penkler 	int status = urb->status;
2287dbf3e7f6SDave Penkler 	int rv;
2288dbf3e7f6SDave Penkler 
2289dbf3e7f6SDave Penkler 	dev_dbg(&data->intf->dev, "int status: %d len %d\n",
2290dbf3e7f6SDave Penkler 		status, urb->actual_length);
2291dbf3e7f6SDave Penkler 
2292dbf3e7f6SDave Penkler 	switch (status) {
2293dbf3e7f6SDave Penkler 	case 0: /* SUCCESS */
2294dbf3e7f6SDave Penkler 		/* check for valid STB notification */
2295dbf3e7f6SDave Penkler 		if (data->iin_buffer[0] > 0x81) {
2296dbf3e7f6SDave Penkler 			data->bNotify1 = data->iin_buffer[0];
2297dbf3e7f6SDave Penkler 			data->bNotify2 = data->iin_buffer[1];
2298dbf3e7f6SDave Penkler 			atomic_set(&data->iin_data_valid, 1);
2299dbf3e7f6SDave Penkler 			wake_up_interruptible(&data->waitq);
2300dbf3e7f6SDave Penkler 			goto exit;
2301dbf3e7f6SDave Penkler 		}
230282ed3381SDave Penkler 		/* check for SRQ notification */
230382ed3381SDave Penkler 		if (data->iin_buffer[0] == 0x81) {
23044f3c8d6eSGuido Kiener 			unsigned long flags;
23054f3c8d6eSGuido Kiener 			struct list_head *elem;
23064f3c8d6eSGuido Kiener 
230782ed3381SDave Penkler 			if (data->fasync)
230882ed3381SDave Penkler 				kill_fasync(&data->fasync,
23094f3c8d6eSGuido Kiener 					SIGIO, POLL_PRI);
231082ed3381SDave Penkler 
23114f3c8d6eSGuido Kiener 			spin_lock_irqsave(&data->dev_lock, flags);
23124f3c8d6eSGuido Kiener 			list_for_each(elem, &data->file_list) {
23134f3c8d6eSGuido Kiener 				struct usbtmc_file_data *file_data;
23144f3c8d6eSGuido Kiener 
23154f3c8d6eSGuido Kiener 				file_data = list_entry(elem,
23164f3c8d6eSGuido Kiener 						       struct usbtmc_file_data,
23174f3c8d6eSGuido Kiener 						       file_elem);
23184f3c8d6eSGuido Kiener 				file_data->srq_byte = data->iin_buffer[1];
23194f3c8d6eSGuido Kiener 				atomic_set(&file_data->srq_asserted, 1);
23204f3c8d6eSGuido Kiener 			}
23214f3c8d6eSGuido Kiener 			spin_unlock_irqrestore(&data->dev_lock, flags);
23224f3c8d6eSGuido Kiener 
23234f3c8d6eSGuido Kiener 			dev_dbg(dev, "srq received bTag %x stb %x\n",
23244f3c8d6eSGuido Kiener 				(unsigned int)data->iin_buffer[0],
23254f3c8d6eSGuido Kiener 				(unsigned int)data->iin_buffer[1]);
23264f3c8d6eSGuido Kiener 			wake_up_interruptible_all(&data->waitq);
232782ed3381SDave Penkler 			goto exit;
232882ed3381SDave Penkler 		}
23294f3c8d6eSGuido Kiener 		dev_warn(dev, "invalid notification: %x\n",
23304f3c8d6eSGuido Kiener 			 data->iin_buffer[0]);
2331dbf3e7f6SDave Penkler 		break;
2332dbf3e7f6SDave Penkler 	case -EOVERFLOW:
2333dbf3e7f6SDave Penkler 		dev_err(dev, "overflow with length %d, actual length is %d\n",
2334dbf3e7f6SDave Penkler 			data->iin_wMaxPacketSize, urb->actual_length);
23350d9b6d49SGustavo A. R. Silva 		fallthrough;
233630fad76cSQiang.zhang 	default:
2337dbf3e7f6SDave Penkler 		/* urb terminated, clean up */
2338dbf3e7f6SDave Penkler 		dev_dbg(dev, "urb terminated, status: %d\n", status);
2339dbf3e7f6SDave Penkler 		return;
2340dbf3e7f6SDave Penkler 	}
2341dbf3e7f6SDave Penkler exit:
2342dbf3e7f6SDave Penkler 	rv = usb_submit_urb(urb, GFP_ATOMIC);
2343dbf3e7f6SDave Penkler 	if (rv)
2344dbf3e7f6SDave Penkler 		dev_err(dev, "usb_submit_urb failed: %d\n", rv);
2345dbf3e7f6SDave Penkler }
2346dbf3e7f6SDave Penkler 
usbtmc_free_int(struct usbtmc_device_data * data)2347dbf3e7f6SDave Penkler static void usbtmc_free_int(struct usbtmc_device_data *data)
2348dbf3e7f6SDave Penkler {
2349dbf3e7f6SDave Penkler 	if (!data->iin_ep_present || !data->iin_urb)
2350dbf3e7f6SDave Penkler 		return;
2351dbf3e7f6SDave Penkler 	usb_kill_urb(data->iin_urb);
2352dbf3e7f6SDave Penkler 	kfree(data->iin_buffer);
2353b19bbdc5SGuido Kiener 	data->iin_buffer = NULL;
2354dbf3e7f6SDave Penkler 	usb_free_urb(data->iin_urb);
2355b19bbdc5SGuido Kiener 	data->iin_urb = NULL;
2356dbf3e7f6SDave Penkler 	kref_put(&data->kref, usbtmc_delete);
2357dbf3e7f6SDave Penkler }
23585b775f67SGreg Kroah-Hartman 
usbtmc_probe(struct usb_interface * intf,const struct usb_device_id * id)23595b775f67SGreg Kroah-Hartman static int usbtmc_probe(struct usb_interface *intf,
23605b775f67SGreg Kroah-Hartman 			const struct usb_device_id *id)
23615b775f67SGreg Kroah-Hartman {
23625b775f67SGreg Kroah-Hartman 	struct usbtmc_device_data *data;
23635b775f67SGreg Kroah-Hartman 	struct usb_host_interface *iface_desc;
2364041370ccSJohan Hovold 	struct usb_endpoint_descriptor *bulk_in, *bulk_out, *int_in;
23655b775f67SGreg Kroah-Hartman 	int retcode;
23665b775f67SGreg Kroah-Hartman 
23675b775f67SGreg Kroah-Hartman 	dev_dbg(&intf->dev, "%s called\n", __func__);
23685b775f67SGreg Kroah-Hartman 
2369687e0687SJohan Hovold 	data = kzalloc(sizeof(*data), GFP_KERNEL);
2370b8f2854bSPeter Chen 	if (!data)
23715b775f67SGreg Kroah-Hartman 		return -ENOMEM;
23725b775f67SGreg Kroah-Hartman 
23735b775f67SGreg Kroah-Hartman 	data->intf = intf;
23745b775f67SGreg Kroah-Hartman 	data->id = id;
23755b775f67SGreg Kroah-Hartman 	data->usb_dev = usb_get_dev(interface_to_usbdev(intf));
23765b775f67SGreg Kroah-Hartman 	usb_set_intfdata(intf, data);
23775b775f67SGreg Kroah-Hartman 	kref_init(&data->kref);
23785b775f67SGreg Kroah-Hartman 	mutex_init(&data->io_mutex);
2379dbf3e7f6SDave Penkler 	init_waitqueue_head(&data->waitq);
2380dbf3e7f6SDave Penkler 	atomic_set(&data->iin_data_valid, 0);
23814f3c8d6eSGuido Kiener 	INIT_LIST_HEAD(&data->file_list);
23824f3c8d6eSGuido Kiener 	spin_lock_init(&data->dev_lock);
23834f3c8d6eSGuido Kiener 
238486286883SOliver Neukum 	data->zombie = 0;
23855b775f67SGreg Kroah-Hartman 
23865b775f67SGreg Kroah-Hartman 	/* Initialize USBTMC bTag and other fields */
23875b775f67SGreg Kroah-Hartman 	data->bTag	= 1;
2388dbf3e7f6SDave Penkler 	/*  2 <= bTag <= 127   USBTMC-USB488 subclass specification 4.3.1 */
2389dbf3e7f6SDave Penkler 	data->iin_bTag = 2;
23905b775f67SGreg Kroah-Hartman 
23915b775f67SGreg Kroah-Hartman 	/* USBTMC devices have only one setting, so use that */
23925b775f67SGreg Kroah-Hartman 	iface_desc = data->intf->cur_altsetting;
2393dbf3e7f6SDave Penkler 	data->ifnum = iface_desc->desc.bInterfaceNumber;
23945b775f67SGreg Kroah-Hartman 
2395041370ccSJohan Hovold 	/* Find bulk endpoints */
2396041370ccSJohan Hovold 	retcode = usb_find_common_endpoints(iface_desc,
2397041370ccSJohan Hovold 			&bulk_in, &bulk_out, NULL, NULL);
2398041370ccSJohan Hovold 	if (retcode) {
2399687e0687SJohan Hovold 		dev_err(&intf->dev, "bulk endpoints not found\n");
2400687e0687SJohan Hovold 		goto err_put;
2401687e0687SJohan Hovold 	}
2402687e0687SJohan Hovold 
2403de7b9aa6SOliver Neukum 	retcode = -EINVAL;
2404041370ccSJohan Hovold 	data->bulk_in = bulk_in->bEndpointAddress;
2405bb99794aSGuido Kiener 	data->wMaxPacketSize = usb_endpoint_maxp(bulk_in);
2406de7b9aa6SOliver Neukum 	if (!data->wMaxPacketSize)
2407de7b9aa6SOliver Neukum 		goto err_put;
2408041370ccSJohan Hovold 	dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in);
2409dbf3e7f6SDave Penkler 
2410041370ccSJohan Hovold 	data->bulk_out = bulk_out->bEndpointAddress;
2411041370ccSJohan Hovold 	dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", data->bulk_out);
2412041370ccSJohan Hovold 
2413041370ccSJohan Hovold 	/* Find int endpoint */
2414041370ccSJohan Hovold 	retcode = usb_find_int_in_endpoint(iface_desc, &int_in);
2415041370ccSJohan Hovold 	if (!retcode) {
2416dbf3e7f6SDave Penkler 		data->iin_ep_present = 1;
2417041370ccSJohan Hovold 		data->iin_ep = int_in->bEndpointAddress;
2418041370ccSJohan Hovold 		data->iin_wMaxPacketSize = usb_endpoint_maxp(int_in);
2419041370ccSJohan Hovold 		data->iin_interval = int_in->bInterval;
2420dbf3e7f6SDave Penkler 		dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
2421dbf3e7f6SDave Penkler 				data->iin_ep);
2422dbf3e7f6SDave Penkler 	}
24235b775f67SGreg Kroah-Hartman 
24245b775f67SGreg Kroah-Hartman 	retcode = get_capabilities(data);
24255b775f67SGreg Kroah-Hartman 	if (retcode)
24265b775f67SGreg Kroah-Hartman 		dev_err(&intf->dev, "can't read capabilities\n");
24275b775f67SGreg Kroah-Hartman 
2428dbf3e7f6SDave Penkler 	if (data->iin_ep_present) {
2429dbf3e7f6SDave Penkler 		/* allocate int urb */
2430dbf3e7f6SDave Penkler 		data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
24312e47c535SJohan Hovold 		if (!data->iin_urb) {
24322e47c535SJohan Hovold 			retcode = -ENOMEM;
2433dbf3e7f6SDave Penkler 			goto error_register;
24342e47c535SJohan Hovold 		}
2435dbf3e7f6SDave Penkler 
243688aecde4SDave Penkler 		/* Protect interrupt in endpoint data until iin_urb is freed */
2437dbf3e7f6SDave Penkler 		kref_get(&data->kref);
2438dbf3e7f6SDave Penkler 
2439dbf3e7f6SDave Penkler 		/* allocate buffer for interrupt in */
2440dbf3e7f6SDave Penkler 		data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
2441dbf3e7f6SDave Penkler 					GFP_KERNEL);
24422e47c535SJohan Hovold 		if (!data->iin_buffer) {
24432e47c535SJohan Hovold 			retcode = -ENOMEM;
2444dbf3e7f6SDave Penkler 			goto error_register;
24452e47c535SJohan Hovold 		}
2446dbf3e7f6SDave Penkler 
2447dbf3e7f6SDave Penkler 		/* fill interrupt urb */
2448dbf3e7f6SDave Penkler 		usb_fill_int_urb(data->iin_urb, data->usb_dev,
2449dbf3e7f6SDave Penkler 				usb_rcvintpipe(data->usb_dev, data->iin_ep),
2450dbf3e7f6SDave Penkler 				data->iin_buffer, data->iin_wMaxPacketSize,
2451dbf3e7f6SDave Penkler 				usbtmc_interrupt,
2452dbf3e7f6SDave Penkler 				data, data->iin_interval);
2453dbf3e7f6SDave Penkler 
2454dbf3e7f6SDave Penkler 		retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
2455dbf3e7f6SDave Penkler 		if (retcode) {
2456dbf3e7f6SDave Penkler 			dev_err(&intf->dev, "Failed to submit iin_urb\n");
2457dbf3e7f6SDave Penkler 			goto error_register;
2458dbf3e7f6SDave Penkler 		}
2459dbf3e7f6SDave Penkler 	}
2460dbf3e7f6SDave Penkler 
24615b775f67SGreg Kroah-Hartman 	retcode = usb_register_dev(intf, &usbtmc_class);
24625b775f67SGreg Kroah-Hartman 	if (retcode) {
246358488283SGuido Kiener 		dev_err(&intf->dev, "Not able to get a minor (base %u, slice default): %d\n",
246458488283SGuido Kiener 			USBTMC_MINOR_BASE,
24655b775f67SGreg Kroah-Hartman 			retcode);
24665b775f67SGreg Kroah-Hartman 		goto error_register;
24675b775f67SGreg Kroah-Hartman 	}
24685b775f67SGreg Kroah-Hartman 	dev_dbg(&intf->dev, "Using minor number %d\n", intf->minor);
24695b775f67SGreg Kroah-Hartman 
24705b775f67SGreg Kroah-Hartman 	return 0;
24715b775f67SGreg Kroah-Hartman 
24725b775f67SGreg Kroah-Hartman error_register:
2473dbf3e7f6SDave Penkler 	usbtmc_free_int(data);
2474687e0687SJohan Hovold err_put:
24755b775f67SGreg Kroah-Hartman 	kref_put(&data->kref, usbtmc_delete);
24765b775f67SGreg Kroah-Hartman 	return retcode;
24775b775f67SGreg Kroah-Hartman }
24785b775f67SGreg Kroah-Hartman 
usbtmc_disconnect(struct usb_interface * intf)24795b775f67SGreg Kroah-Hartman static void usbtmc_disconnect(struct usb_interface *intf)
24805b775f67SGreg Kroah-Hartman {
24814f3c8d6eSGuido Kiener 	struct usbtmc_device_data *data  = usb_get_intfdata(intf);
24824ddc645fSGuido Kiener 	struct list_head *elem;
24835b775f67SGreg Kroah-Hartman 
24845b775f67SGreg Kroah-Hartman 	usb_deregister_dev(intf, &usbtmc_class);
248586286883SOliver Neukum 	mutex_lock(&data->io_mutex);
248686286883SOliver Neukum 	data->zombie = 1;
24874f3c8d6eSGuido Kiener 	wake_up_interruptible_all(&data->waitq);
24884ddc645fSGuido Kiener 	list_for_each(elem, &data->file_list) {
24894ddc645fSGuido Kiener 		struct usbtmc_file_data *file_data;
24904ddc645fSGuido Kiener 
24914ddc645fSGuido Kiener 		file_data = list_entry(elem,
24924ddc645fSGuido Kiener 				       struct usbtmc_file_data,
24934ddc645fSGuido Kiener 				       file_elem);
24944ddc645fSGuido Kiener 		usb_kill_anchored_urbs(&file_data->submitted);
2495bb99794aSGuido Kiener 		usb_scuttle_anchored_urbs(&file_data->in_anchor);
24964ddc645fSGuido Kiener 	}
249786286883SOliver Neukum 	mutex_unlock(&data->io_mutex);
2498f9cfabceSDave Penkler 	usbtmc_free_int(data);
24995b775f67SGreg Kroah-Hartman 	kref_put(&data->kref, usbtmc_delete);
25005b775f67SGreg Kroah-Hartman }
25015b775f67SGreg Kroah-Hartman 
usbtmc_draw_down(struct usbtmc_file_data * file_data)25024ddc645fSGuido Kiener static void usbtmc_draw_down(struct usbtmc_file_data *file_data)
25034ddc645fSGuido Kiener {
25044ddc645fSGuido Kiener 	int time;
25054ddc645fSGuido Kiener 
25064ddc645fSGuido Kiener 	time = usb_wait_anchor_empty_timeout(&file_data->submitted, 1000);
25074ddc645fSGuido Kiener 	if (!time)
25084ddc645fSGuido Kiener 		usb_kill_anchored_urbs(&file_data->submitted);
2509bb99794aSGuido Kiener 	usb_scuttle_anchored_urbs(&file_data->in_anchor);
25104ddc645fSGuido Kiener }
25114ddc645fSGuido Kiener 
usbtmc_suspend(struct usb_interface * intf,pm_message_t message)2512a4708103SOliver Neukum static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message)
2513a4708103SOliver Neukum {
25144ddc645fSGuido Kiener 	struct usbtmc_device_data *data = usb_get_intfdata(intf);
25154ddc645fSGuido Kiener 	struct list_head *elem;
25164ddc645fSGuido Kiener 
25174ddc645fSGuido Kiener 	if (!data)
25184ddc645fSGuido Kiener 		return 0;
25194ddc645fSGuido Kiener 
25204ddc645fSGuido Kiener 	mutex_lock(&data->io_mutex);
25214ddc645fSGuido Kiener 	list_for_each(elem, &data->file_list) {
25224ddc645fSGuido Kiener 		struct usbtmc_file_data *file_data;
25234ddc645fSGuido Kiener 
25244ddc645fSGuido Kiener 		file_data = list_entry(elem,
25254ddc645fSGuido Kiener 				       struct usbtmc_file_data,
25264ddc645fSGuido Kiener 				       file_elem);
25274ddc645fSGuido Kiener 		usbtmc_draw_down(file_data);
25284ddc645fSGuido Kiener 	}
2529b19bbdc5SGuido Kiener 
2530b19bbdc5SGuido Kiener 	if (data->iin_ep_present && data->iin_urb)
2531b19bbdc5SGuido Kiener 		usb_kill_urb(data->iin_urb);
2532b19bbdc5SGuido Kiener 
25334ddc645fSGuido Kiener 	mutex_unlock(&data->io_mutex);
2534a4708103SOliver Neukum 	return 0;
2535a4708103SOliver Neukum }
2536a4708103SOliver Neukum 
usbtmc_resume(struct usb_interface * intf)2537a4708103SOliver Neukum static int usbtmc_resume(struct usb_interface *intf)
2538a4708103SOliver Neukum {
2539b19bbdc5SGuido Kiener 	struct usbtmc_device_data *data = usb_get_intfdata(intf);
2540b19bbdc5SGuido Kiener 	int retcode = 0;
2541b19bbdc5SGuido Kiener 
2542b19bbdc5SGuido Kiener 	if (data->iin_ep_present && data->iin_urb)
2543b19bbdc5SGuido Kiener 		retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
2544b19bbdc5SGuido Kiener 	if (retcode)
2545b19bbdc5SGuido Kiener 		dev_err(&intf->dev, "Failed to submit iin_urb\n");
2546b19bbdc5SGuido Kiener 
2547b19bbdc5SGuido Kiener 	return retcode;
2548a4708103SOliver Neukum }
2549a4708103SOliver Neukum 
usbtmc_pre_reset(struct usb_interface * intf)25504ddc645fSGuido Kiener static int usbtmc_pre_reset(struct usb_interface *intf)
25514ddc645fSGuido Kiener {
25524ddc645fSGuido Kiener 	struct usbtmc_device_data *data  = usb_get_intfdata(intf);
25534ddc645fSGuido Kiener 	struct list_head *elem;
25544ddc645fSGuido Kiener 
25554ddc645fSGuido Kiener 	if (!data)
25564ddc645fSGuido Kiener 		return 0;
25574ddc645fSGuido Kiener 
25584ddc645fSGuido Kiener 	mutex_lock(&data->io_mutex);
25594ddc645fSGuido Kiener 
25604ddc645fSGuido Kiener 	list_for_each(elem, &data->file_list) {
25614ddc645fSGuido Kiener 		struct usbtmc_file_data *file_data;
25624ddc645fSGuido Kiener 
25634ddc645fSGuido Kiener 		file_data = list_entry(elem,
25644ddc645fSGuido Kiener 				       struct usbtmc_file_data,
25654ddc645fSGuido Kiener 				       file_elem);
25664ddc645fSGuido Kiener 		usbtmc_ioctl_cancel_io(file_data);
25674ddc645fSGuido Kiener 	}
25684ddc645fSGuido Kiener 
25694ddc645fSGuido Kiener 	return 0;
25704ddc645fSGuido Kiener }
25714ddc645fSGuido Kiener 
usbtmc_post_reset(struct usb_interface * intf)25724ddc645fSGuido Kiener static int usbtmc_post_reset(struct usb_interface *intf)
25734ddc645fSGuido Kiener {
25744ddc645fSGuido Kiener 	struct usbtmc_device_data *data  = usb_get_intfdata(intf);
25754ddc645fSGuido Kiener 
25764ddc645fSGuido Kiener 	mutex_unlock(&data->io_mutex);
25774ddc645fSGuido Kiener 
25784ddc645fSGuido Kiener 	return 0;
25794ddc645fSGuido Kiener }
25804ddc645fSGuido Kiener 
25815b775f67SGreg Kroah-Hartman static struct usb_driver usbtmc_driver = {
25825b775f67SGreg Kroah-Hartman 	.name		= "usbtmc",
25835b775f67SGreg Kroah-Hartman 	.id_table	= usbtmc_devices,
25845b775f67SGreg Kroah-Hartman 	.probe		= usbtmc_probe,
2585a4708103SOliver Neukum 	.disconnect	= usbtmc_disconnect,
2586a4708103SOliver Neukum 	.suspend	= usbtmc_suspend,
2587a4708103SOliver Neukum 	.resume		= usbtmc_resume,
25884ddc645fSGuido Kiener 	.pre_reset	= usbtmc_pre_reset,
25894ddc645fSGuido Kiener 	.post_reset	= usbtmc_post_reset,
259004a0625eSGreg Kroah-Hartman 	.dev_groups	= usbtmc_groups,
25915b775f67SGreg Kroah-Hartman };
25925b775f67SGreg Kroah-Hartman 
259365db4305SGreg Kroah-Hartman module_usb_driver(usbtmc_driver);
25945b775f67SGreg Kroah-Hartman 
25955b775f67SGreg Kroah-Hartman MODULE_LICENSE("GPL");
2596