18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * drivers/usb/class/usbtmc.c - USB Test & Measurement class driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Novell, Inc.
78c2ecf20Sopenharmony_ci * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
88c2ecf20Sopenharmony_ci * Copyright (C) 2018 IVI Foundation, Inc.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/fs.h>
168c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
178c2ecf20Sopenharmony_ci#include <linux/kref.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci#include <linux/poll.h>
208c2ecf20Sopenharmony_ci#include <linux/mutex.h>
218c2ecf20Sopenharmony_ci#include <linux/usb.h>
228c2ecf20Sopenharmony_ci#include <linux/compat.h>
238c2ecf20Sopenharmony_ci#include <linux/usb/tmc.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* Increment API VERSION when changing tmc.h with new flags or ioctls
268c2ecf20Sopenharmony_ci * or when changing a significant behavior of the driver.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci#define USBTMC_API_VERSION (2)
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define USBTMC_HEADER_SIZE	12
318c2ecf20Sopenharmony_ci#define USBTMC_MINOR_BASE	176
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* Minimum USB timeout (in milliseconds) */
348c2ecf20Sopenharmony_ci#define USBTMC_MIN_TIMEOUT	100
358c2ecf20Sopenharmony_ci/* Default USB timeout (in milliseconds) */
368c2ecf20Sopenharmony_ci#define USBTMC_TIMEOUT		5000
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* Max number of urbs used in write transfers */
398c2ecf20Sopenharmony_ci#define MAX_URBS_IN_FLIGHT	16
408c2ecf20Sopenharmony_ci/* I/O buffer size used in generic read/write functions */
418c2ecf20Sopenharmony_ci#define USBTMC_BUFSIZE		(4096)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * Maximum number of read cycles to empty bulk in endpoint during CLEAR and
458c2ecf20Sopenharmony_ci * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short
468c2ecf20Sopenharmony_ci * packet is never read.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci#define USBTMC_MAX_READS_TO_CLEAR_BULK_IN	100
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic const struct usb_device_id usbtmc_devices[] = {
518c2ecf20Sopenharmony_ci	{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), },
528c2ecf20Sopenharmony_ci	{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), },
538c2ecf20Sopenharmony_ci	{ 0, } /* terminating entry */
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, usbtmc_devices);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/*
588c2ecf20Sopenharmony_ci * This structure is the capabilities for the device
598c2ecf20Sopenharmony_ci * See section 4.2.1.8 of the USBTMC specification,
608c2ecf20Sopenharmony_ci * and section 4.2.2 of the USBTMC usb488 subclass
618c2ecf20Sopenharmony_ci * specification for details.
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_cistruct usbtmc_dev_capabilities {
648c2ecf20Sopenharmony_ci	__u8 interface_capabilities;
658c2ecf20Sopenharmony_ci	__u8 device_capabilities;
668c2ecf20Sopenharmony_ci	__u8 usb488_interface_capabilities;
678c2ecf20Sopenharmony_ci	__u8 usb488_device_capabilities;
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/* This structure holds private data for each USBTMC device. One copy is
718c2ecf20Sopenharmony_ci * allocated for each USBTMC device in the driver's probe function.
728c2ecf20Sopenharmony_ci */
738c2ecf20Sopenharmony_cistruct usbtmc_device_data {
748c2ecf20Sopenharmony_ci	const struct usb_device_id *id;
758c2ecf20Sopenharmony_ci	struct usb_device *usb_dev;
768c2ecf20Sopenharmony_ci	struct usb_interface *intf;
778c2ecf20Sopenharmony_ci	struct list_head file_list;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	unsigned int bulk_in;
808c2ecf20Sopenharmony_ci	unsigned int bulk_out;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	u8 bTag;
838c2ecf20Sopenharmony_ci	u8 bTag_last_write;	/* needed for abort */
848c2ecf20Sopenharmony_ci	u8 bTag_last_read;	/* needed for abort */
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/* packet size of IN bulk */
878c2ecf20Sopenharmony_ci	u16            wMaxPacketSize;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* data for interrupt in endpoint handling */
908c2ecf20Sopenharmony_ci	u8             bNotify1;
918c2ecf20Sopenharmony_ci	u8             bNotify2;
928c2ecf20Sopenharmony_ci	u16            ifnum;
938c2ecf20Sopenharmony_ci	u8             iin_bTag;
948c2ecf20Sopenharmony_ci	u8            *iin_buffer;
958c2ecf20Sopenharmony_ci	atomic_t       iin_data_valid;
968c2ecf20Sopenharmony_ci	unsigned int   iin_ep;
978c2ecf20Sopenharmony_ci	int            iin_ep_present;
988c2ecf20Sopenharmony_ci	int            iin_interval;
998c2ecf20Sopenharmony_ci	struct urb    *iin_urb;
1008c2ecf20Sopenharmony_ci	u16            iin_wMaxPacketSize;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/* coalesced usb488_caps from usbtmc_dev_capabilities */
1038c2ecf20Sopenharmony_ci	__u8 usb488_caps;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	bool zombie; /* fd of disconnected device */
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	struct usbtmc_dev_capabilities	capabilities;
1088c2ecf20Sopenharmony_ci	struct kref kref;
1098c2ecf20Sopenharmony_ci	struct mutex io_mutex;	/* only one i/o function running at a time */
1108c2ecf20Sopenharmony_ci	wait_queue_head_t waitq;
1118c2ecf20Sopenharmony_ci	struct fasync_struct *fasync;
1128c2ecf20Sopenharmony_ci	spinlock_t dev_lock; /* lock for file_list */
1138c2ecf20Sopenharmony_ci};
1148c2ecf20Sopenharmony_ci#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci/*
1178c2ecf20Sopenharmony_ci * This structure holds private data for each USBTMC file handle.
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_cistruct usbtmc_file_data {
1208c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data;
1218c2ecf20Sopenharmony_ci	struct list_head file_elem;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	u32            timeout;
1248c2ecf20Sopenharmony_ci	u8             srq_byte;
1258c2ecf20Sopenharmony_ci	atomic_t       srq_asserted;
1268c2ecf20Sopenharmony_ci	atomic_t       closing;
1278c2ecf20Sopenharmony_ci	u8             bmTransferAttributes; /* member of DEV_DEP_MSG_IN */
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	u8             eom_val;
1308c2ecf20Sopenharmony_ci	u8             term_char;
1318c2ecf20Sopenharmony_ci	bool           term_char_enabled;
1328c2ecf20Sopenharmony_ci	bool           auto_abort;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	spinlock_t     err_lock; /* lock for errors */
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	struct usb_anchor submitted;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* data for generic_write */
1398c2ecf20Sopenharmony_ci	struct semaphore limit_write_sem;
1408c2ecf20Sopenharmony_ci	u32 out_transfer_size;
1418c2ecf20Sopenharmony_ci	int out_status;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/* data for generic_read */
1448c2ecf20Sopenharmony_ci	u32 in_transfer_size;
1458c2ecf20Sopenharmony_ci	int in_status;
1468c2ecf20Sopenharmony_ci	int in_urbs_used;
1478c2ecf20Sopenharmony_ci	struct usb_anchor in_anchor;
1488c2ecf20Sopenharmony_ci	wait_queue_head_t wait_bulk_in;
1498c2ecf20Sopenharmony_ci};
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/* Forward declarations */
1528c2ecf20Sopenharmony_cistatic struct usb_driver usbtmc_driver;
1538c2ecf20Sopenharmony_cistatic void usbtmc_draw_down(struct usbtmc_file_data *file_data);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic void usbtmc_delete(struct kref *kref)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = to_usbtmc_data(kref);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	usb_put_dev(data->usb_dev);
1608c2ecf20Sopenharmony_ci	kfree(data);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int usbtmc_open(struct inode *inode, struct file *filp)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct usb_interface *intf;
1668c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data;
1678c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	intf = usb_find_interface(&usbtmc_driver, iminor(inode));
1708c2ecf20Sopenharmony_ci	if (!intf) {
1718c2ecf20Sopenharmony_ci		pr_err("can not find device for minor %d", iminor(inode));
1728c2ecf20Sopenharmony_ci		return -ENODEV;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
1768c2ecf20Sopenharmony_ci	if (!file_data)
1778c2ecf20Sopenharmony_ci		return -ENOMEM;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	spin_lock_init(&file_data->err_lock);
1808c2ecf20Sopenharmony_ci	sema_init(&file_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
1818c2ecf20Sopenharmony_ci	init_usb_anchor(&file_data->submitted);
1828c2ecf20Sopenharmony_ci	init_usb_anchor(&file_data->in_anchor);
1838c2ecf20Sopenharmony_ci	init_waitqueue_head(&file_data->wait_bulk_in);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	data = usb_get_intfdata(intf);
1868c2ecf20Sopenharmony_ci	/* Protect reference to data from file structure until release */
1878c2ecf20Sopenharmony_ci	kref_get(&data->kref);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
1908c2ecf20Sopenharmony_ci	file_data->data = data;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	atomic_set(&file_data->closing, 0);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	file_data->timeout = USBTMC_TIMEOUT;
1958c2ecf20Sopenharmony_ci	file_data->term_char = '\n';
1968c2ecf20Sopenharmony_ci	file_data->term_char_enabled = 0;
1978c2ecf20Sopenharmony_ci	file_data->auto_abort = 0;
1988c2ecf20Sopenharmony_ci	file_data->eom_val = 1;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&file_data->file_elem);
2018c2ecf20Sopenharmony_ci	spin_lock_irq(&data->dev_lock);
2028c2ecf20Sopenharmony_ci	list_add_tail(&file_data->file_elem, &data->file_list);
2038c2ecf20Sopenharmony_ci	spin_unlock_irq(&data->dev_lock);
2048c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* Store pointer in file structure's private data field */
2078c2ecf20Sopenharmony_ci	filp->private_data = file_data;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	return 0;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/*
2138c2ecf20Sopenharmony_ci * usbtmc_flush - called before file handle is closed
2148c2ecf20Sopenharmony_ci */
2158c2ecf20Sopenharmony_cistatic int usbtmc_flush(struct file *file, fl_owner_t id)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data;
2188c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	file_data = file->private_data;
2218c2ecf20Sopenharmony_ci	if (file_data == NULL)
2228c2ecf20Sopenharmony_ci		return -ENODEV;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	atomic_set(&file_data->closing, 1);
2258c2ecf20Sopenharmony_ci	data = file_data->data;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/* wait for io to stop */
2288c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	usbtmc_draw_down(file_data);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->err_lock);
2338c2ecf20Sopenharmony_ci	file_data->in_status = 0;
2348c2ecf20Sopenharmony_ci	file_data->in_transfer_size = 0;
2358c2ecf20Sopenharmony_ci	file_data->in_urbs_used = 0;
2368c2ecf20Sopenharmony_ci	file_data->out_status = 0;
2378c2ecf20Sopenharmony_ci	file_data->out_transfer_size = 0;
2388c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->err_lock);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	wake_up_interruptible_all(&data->waitq);
2418c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return 0;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic int usbtmc_release(struct inode *inode, struct file *file)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data = file->private_data;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	/* prevent IO _AND_ usbtmc_interrupt */
2518c2ecf20Sopenharmony_ci	mutex_lock(&file_data->data->io_mutex);
2528c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->data->dev_lock);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	list_del(&file_data->file_elem);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->data->dev_lock);
2578c2ecf20Sopenharmony_ci	mutex_unlock(&file_data->data->io_mutex);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	kref_put(&file_data->data->kref, usbtmc_delete);
2608c2ecf20Sopenharmony_ci	file_data->data = NULL;
2618c2ecf20Sopenharmony_ci	kfree(file_data);
2628c2ecf20Sopenharmony_ci	return 0;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data,
2668c2ecf20Sopenharmony_ci					  u8 tag)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	u8 *buffer;
2698c2ecf20Sopenharmony_ci	struct device *dev;
2708c2ecf20Sopenharmony_ci	int rv;
2718c2ecf20Sopenharmony_ci	int n;
2728c2ecf20Sopenharmony_ci	int actual;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	dev = &data->intf->dev;
2758c2ecf20Sopenharmony_ci	buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
2768c2ecf20Sopenharmony_ci	if (!buffer)
2778c2ecf20Sopenharmony_ci		return -ENOMEM;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
2808c2ecf20Sopenharmony_ci			     usb_rcvctrlpipe(data->usb_dev, 0),
2818c2ecf20Sopenharmony_ci			     USBTMC_REQUEST_INITIATE_ABORT_BULK_IN,
2828c2ecf20Sopenharmony_ci			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
2838c2ecf20Sopenharmony_ci			     tag, data->bulk_in,
2848c2ecf20Sopenharmony_ci			     buffer, 2, USB_CTRL_GET_TIMEOUT);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (rv < 0) {
2878c2ecf20Sopenharmony_ci		dev_err(dev, "usb_control_msg returned %d\n", rv);
2888c2ecf20Sopenharmony_ci		goto exit;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n",
2928c2ecf20Sopenharmony_ci		buffer[0], buffer[1]);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (buffer[0] == USBTMC_STATUS_FAILED) {
2958c2ecf20Sopenharmony_ci		/* No transfer in progress and the Bulk-OUT FIFO is empty. */
2968c2ecf20Sopenharmony_ci		rv = 0;
2978c2ecf20Sopenharmony_ci		goto exit;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) {
3018c2ecf20Sopenharmony_ci		/* The device returns this status if either:
3028c2ecf20Sopenharmony_ci		 * - There is a transfer in progress, but the specified bTag
3038c2ecf20Sopenharmony_ci		 *   does not match.
3048c2ecf20Sopenharmony_ci		 * - There is no transfer in progress, but the Bulk-OUT FIFO
3058c2ecf20Sopenharmony_ci		 *   is not empty.
3068c2ecf20Sopenharmony_ci		 */
3078c2ecf20Sopenharmony_ci		rv = -ENOMSG;
3088c2ecf20Sopenharmony_ci		goto exit;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
3128c2ecf20Sopenharmony_ci		dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
3138c2ecf20Sopenharmony_ci			buffer[0]);
3148c2ecf20Sopenharmony_ci		rv = -EPERM;
3158c2ecf20Sopenharmony_ci		goto exit;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	n = 0;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ciusbtmc_abort_bulk_in_status:
3218c2ecf20Sopenharmony_ci	dev_dbg(dev, "Reading from bulk in EP\n");
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	/* Data must be present. So use low timeout 300 ms */
3248c2ecf20Sopenharmony_ci	actual = 0;
3258c2ecf20Sopenharmony_ci	rv = usb_bulk_msg(data->usb_dev,
3268c2ecf20Sopenharmony_ci			  usb_rcvbulkpipe(data->usb_dev,
3278c2ecf20Sopenharmony_ci					  data->bulk_in),
3288c2ecf20Sopenharmony_ci			  buffer, USBTMC_BUFSIZE,
3298c2ecf20Sopenharmony_ci			  &actual, 300);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1,
3328c2ecf20Sopenharmony_ci			     buffer, actual, true);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	n++;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (rv < 0) {
3378c2ecf20Sopenharmony_ci		dev_err(dev, "usb_bulk_msg returned %d\n", rv);
3388c2ecf20Sopenharmony_ci		if (rv != -ETIMEDOUT)
3398c2ecf20Sopenharmony_ci			goto exit;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (actual == USBTMC_BUFSIZE)
3438c2ecf20Sopenharmony_ci		goto usbtmc_abort_bulk_in_status;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) {
3468c2ecf20Sopenharmony_ci		dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
3478c2ecf20Sopenharmony_ci			USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
3488c2ecf20Sopenharmony_ci		rv = -EPERM;
3498c2ecf20Sopenharmony_ci		goto exit;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
3538c2ecf20Sopenharmony_ci			     usb_rcvctrlpipe(data->usb_dev, 0),
3548c2ecf20Sopenharmony_ci			     USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS,
3558c2ecf20Sopenharmony_ci			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
3568c2ecf20Sopenharmony_ci			     0, data->bulk_in, buffer, 0x08,
3578c2ecf20Sopenharmony_ci			     USB_CTRL_GET_TIMEOUT);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (rv < 0) {
3608c2ecf20Sopenharmony_ci		dev_err(dev, "usb_control_msg returned %d\n", rv);
3618c2ecf20Sopenharmony_ci		goto exit;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	dev_dbg(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (buffer[0] == USBTMC_STATUS_SUCCESS) {
3678c2ecf20Sopenharmony_ci		rv = 0;
3688c2ecf20Sopenharmony_ci		goto exit;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (buffer[0] != USBTMC_STATUS_PENDING) {
3728c2ecf20Sopenharmony_ci		dev_err(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]);
3738c2ecf20Sopenharmony_ci		rv = -EPERM;
3748c2ecf20Sopenharmony_ci		goto exit;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	if ((buffer[1] & 1) > 0) {
3788c2ecf20Sopenharmony_ci		/* The device has 1 or more queued packets the Host can read */
3798c2ecf20Sopenharmony_ci		goto usbtmc_abort_bulk_in_status;
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/* The Host must send CHECK_ABORT_BULK_IN_STATUS at a later time. */
3838c2ecf20Sopenharmony_ci	rv = -EAGAIN;
3848c2ecf20Sopenharmony_ciexit:
3858c2ecf20Sopenharmony_ci	kfree(buffer);
3868c2ecf20Sopenharmony_ci	return rv;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data,
3958c2ecf20Sopenharmony_ci					   u8 tag)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	struct device *dev;
3988c2ecf20Sopenharmony_ci	u8 *buffer;
3998c2ecf20Sopenharmony_ci	int rv;
4008c2ecf20Sopenharmony_ci	int n;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	dev = &data->intf->dev;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	buffer = kmalloc(8, GFP_KERNEL);
4058c2ecf20Sopenharmony_ci	if (!buffer)
4068c2ecf20Sopenharmony_ci		return -ENOMEM;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
4098c2ecf20Sopenharmony_ci			     usb_rcvctrlpipe(data->usb_dev, 0),
4108c2ecf20Sopenharmony_ci			     USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT,
4118c2ecf20Sopenharmony_ci			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
4128c2ecf20Sopenharmony_ci			     tag, data->bulk_out,
4138c2ecf20Sopenharmony_ci			     buffer, 2, USB_CTRL_GET_TIMEOUT);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (rv < 0) {
4168c2ecf20Sopenharmony_ci		dev_err(dev, "usb_control_msg returned %d\n", rv);
4178c2ecf20Sopenharmony_ci		goto exit;
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	dev_dbg(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", buffer[0]);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
4238c2ecf20Sopenharmony_ci		dev_err(dev, "INITIATE_ABORT_BULK_OUT returned %x\n",
4248c2ecf20Sopenharmony_ci			buffer[0]);
4258c2ecf20Sopenharmony_ci		rv = -EPERM;
4268c2ecf20Sopenharmony_ci		goto exit;
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	n = 0;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciusbtmc_abort_bulk_out_check_status:
4328c2ecf20Sopenharmony_ci	/* do not stress device with subsequent requests */
4338c2ecf20Sopenharmony_ci	msleep(50);
4348c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
4358c2ecf20Sopenharmony_ci			     usb_rcvctrlpipe(data->usb_dev, 0),
4368c2ecf20Sopenharmony_ci			     USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS,
4378c2ecf20Sopenharmony_ci			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
4388c2ecf20Sopenharmony_ci			     0, data->bulk_out, buffer, 0x08,
4398c2ecf20Sopenharmony_ci			     USB_CTRL_GET_TIMEOUT);
4408c2ecf20Sopenharmony_ci	n++;
4418c2ecf20Sopenharmony_ci	if (rv < 0) {
4428c2ecf20Sopenharmony_ci		dev_err(dev, "usb_control_msg returned %d\n", rv);
4438c2ecf20Sopenharmony_ci		goto exit;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	dev_dbg(dev, "CHECK_ABORT_BULK_OUT returned %x\n", buffer[0]);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (buffer[0] == USBTMC_STATUS_SUCCESS)
4498c2ecf20Sopenharmony_ci		goto usbtmc_abort_bulk_out_clear_halt;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if ((buffer[0] == USBTMC_STATUS_PENDING) &&
4528c2ecf20Sopenharmony_ci	    (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN))
4538c2ecf20Sopenharmony_ci		goto usbtmc_abort_bulk_out_check_status;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	rv = -EPERM;
4568c2ecf20Sopenharmony_ci	goto exit;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ciusbtmc_abort_bulk_out_clear_halt:
4598c2ecf20Sopenharmony_ci	rv = usb_clear_halt(data->usb_dev,
4608c2ecf20Sopenharmony_ci			    usb_sndbulkpipe(data->usb_dev, data->bulk_out));
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (rv < 0) {
4638c2ecf20Sopenharmony_ci		dev_err(dev, "usb_control_msg returned %d\n", rv);
4648c2ecf20Sopenharmony_ci		goto exit;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci	rv = 0;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ciexit:
4698c2ecf20Sopenharmony_ci	kfree(buffer);
4708c2ecf20Sopenharmony_ci	return rv;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write);
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
4798c2ecf20Sopenharmony_ci				void __user *arg)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = file_data->data;
4828c2ecf20Sopenharmony_ci	struct device *dev = &data->intf->dev;
4838c2ecf20Sopenharmony_ci	int srq_asserted = 0;
4848c2ecf20Sopenharmony_ci	u8 *buffer;
4858c2ecf20Sopenharmony_ci	u8 tag;
4868c2ecf20Sopenharmony_ci	__u8 stb;
4878c2ecf20Sopenharmony_ci	int rv;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
4908c2ecf20Sopenharmony_ci		data->iin_ep_present);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	spin_lock_irq(&data->dev_lock);
4938c2ecf20Sopenharmony_ci	srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted);
4948c2ecf20Sopenharmony_ci	if (srq_asserted) {
4958c2ecf20Sopenharmony_ci		/* a STB with SRQ is already received */
4968c2ecf20Sopenharmony_ci		stb = file_data->srq_byte;
4978c2ecf20Sopenharmony_ci		spin_unlock_irq(&data->dev_lock);
4988c2ecf20Sopenharmony_ci		rv = put_user(stb, (__u8 __user *)arg);
4998c2ecf20Sopenharmony_ci		dev_dbg(dev, "stb:0x%02x with srq received %d\n",
5008c2ecf20Sopenharmony_ci			(unsigned int)stb, rv);
5018c2ecf20Sopenharmony_ci		return rv;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci	spin_unlock_irq(&data->dev_lock);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	buffer = kmalloc(8, GFP_KERNEL);
5068c2ecf20Sopenharmony_ci	if (!buffer)
5078c2ecf20Sopenharmony_ci		return -ENOMEM;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	atomic_set(&data->iin_data_valid, 0);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
5128c2ecf20Sopenharmony_ci			usb_rcvctrlpipe(data->usb_dev, 0),
5138c2ecf20Sopenharmony_ci			USBTMC488_REQUEST_READ_STATUS_BYTE,
5148c2ecf20Sopenharmony_ci			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
5158c2ecf20Sopenharmony_ci			data->iin_bTag,
5168c2ecf20Sopenharmony_ci			data->ifnum,
5178c2ecf20Sopenharmony_ci			buffer, 0x03, USB_CTRL_GET_TIMEOUT);
5188c2ecf20Sopenharmony_ci	if (rv < 0) {
5198c2ecf20Sopenharmony_ci		dev_err(dev, "stb usb_control_msg returned %d\n", rv);
5208c2ecf20Sopenharmony_ci		goto exit;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
5248c2ecf20Sopenharmony_ci		dev_err(dev, "control status returned %x\n", buffer[0]);
5258c2ecf20Sopenharmony_ci		rv = -EIO;
5268c2ecf20Sopenharmony_ci		goto exit;
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (data->iin_ep_present) {
5308c2ecf20Sopenharmony_ci		rv = wait_event_interruptible_timeout(
5318c2ecf20Sopenharmony_ci			data->waitq,
5328c2ecf20Sopenharmony_ci			atomic_read(&data->iin_data_valid) != 0,
5338c2ecf20Sopenharmony_ci			file_data->timeout);
5348c2ecf20Sopenharmony_ci		if (rv < 0) {
5358c2ecf20Sopenharmony_ci			dev_dbg(dev, "wait interrupted %d\n", rv);
5368c2ecf20Sopenharmony_ci			goto exit;
5378c2ecf20Sopenharmony_ci		}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		if (rv == 0) {
5408c2ecf20Sopenharmony_ci			dev_dbg(dev, "wait timed out\n");
5418c2ecf20Sopenharmony_ci			rv = -ETIMEDOUT;
5428c2ecf20Sopenharmony_ci			goto exit;
5438c2ecf20Sopenharmony_ci		}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci		tag = data->bNotify1 & 0x7f;
5468c2ecf20Sopenharmony_ci		if (tag != data->iin_bTag) {
5478c2ecf20Sopenharmony_ci			dev_err(dev, "expected bTag %x got %x\n",
5488c2ecf20Sopenharmony_ci				data->iin_bTag, tag);
5498c2ecf20Sopenharmony_ci		}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		stb = data->bNotify2;
5528c2ecf20Sopenharmony_ci	} else {
5538c2ecf20Sopenharmony_ci		stb = buffer[2];
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	rv = put_user(stb, (__u8 __user *)arg);
5578c2ecf20Sopenharmony_ci	dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)stb, rv);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci exit:
5608c2ecf20Sopenharmony_ci	/* bump interrupt bTag */
5618c2ecf20Sopenharmony_ci	data->iin_bTag += 1;
5628c2ecf20Sopenharmony_ci	if (data->iin_bTag > 127)
5638c2ecf20Sopenharmony_ci		/* 1 is for SRQ see USBTMC-USB488 subclass spec section 4.3.1 */
5648c2ecf20Sopenharmony_ci		data->iin_bTag = 2;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	kfree(buffer);
5678c2ecf20Sopenharmony_ci	return rv;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data,
5718c2ecf20Sopenharmony_ci				    __u32 __user *arg)
5728c2ecf20Sopenharmony_ci{
5738c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = file_data->data;
5748c2ecf20Sopenharmony_ci	struct device *dev = &data->intf->dev;
5758c2ecf20Sopenharmony_ci	int rv;
5768c2ecf20Sopenharmony_ci	u32 timeout;
5778c2ecf20Sopenharmony_ci	unsigned long expire;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	if (!data->iin_ep_present) {
5808c2ecf20Sopenharmony_ci		dev_dbg(dev, "no interrupt endpoint present\n");
5818c2ecf20Sopenharmony_ci		return -EFAULT;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	if (get_user(timeout, arg))
5858c2ecf20Sopenharmony_ci		return -EFAULT;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	expire = msecs_to_jiffies(timeout);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	rv = wait_event_interruptible_timeout(
5928c2ecf20Sopenharmony_ci			data->waitq,
5938c2ecf20Sopenharmony_ci			atomic_read(&file_data->srq_asserted) != 0 ||
5948c2ecf20Sopenharmony_ci			atomic_read(&file_data->closing),
5958c2ecf20Sopenharmony_ci			expire);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	/* Note! disconnect or close could be called in the meantime */
6008c2ecf20Sopenharmony_ci	if (atomic_read(&file_data->closing) || data->zombie)
6018c2ecf20Sopenharmony_ci		rv = -ENODEV;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if (rv < 0) {
6048c2ecf20Sopenharmony_ci		/* dev can be invalid now! */
6058c2ecf20Sopenharmony_ci		pr_debug("%s - wait interrupted %d\n", __func__, rv);
6068c2ecf20Sopenharmony_ci		return rv;
6078c2ecf20Sopenharmony_ci	}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	if (rv == 0) {
6108c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s - wait timed out\n", __func__);
6118c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s - srq asserted\n", __func__);
6158c2ecf20Sopenharmony_ci	return 0;
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
6198c2ecf20Sopenharmony_ci				void __user *arg, unsigned int cmd)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct device *dev = &data->intf->dev;
6228c2ecf20Sopenharmony_ci	__u8 val;
6238c2ecf20Sopenharmony_ci	u8 *buffer;
6248c2ecf20Sopenharmony_ci	u16 wValue;
6258c2ecf20Sopenharmony_ci	int rv;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (!(data->usb488_caps & USBTMC488_CAPABILITY_SIMPLE))
6288c2ecf20Sopenharmony_ci		return -EINVAL;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	buffer = kmalloc(8, GFP_KERNEL);
6318c2ecf20Sopenharmony_ci	if (!buffer)
6328c2ecf20Sopenharmony_ci		return -ENOMEM;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	if (cmd == USBTMC488_REQUEST_REN_CONTROL) {
6358c2ecf20Sopenharmony_ci		rv = copy_from_user(&val, arg, sizeof(val));
6368c2ecf20Sopenharmony_ci		if (rv) {
6378c2ecf20Sopenharmony_ci			rv = -EFAULT;
6388c2ecf20Sopenharmony_ci			goto exit;
6398c2ecf20Sopenharmony_ci		}
6408c2ecf20Sopenharmony_ci		wValue = val ? 1 : 0;
6418c2ecf20Sopenharmony_ci	} else {
6428c2ecf20Sopenharmony_ci		wValue = 0;
6438c2ecf20Sopenharmony_ci	}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
6468c2ecf20Sopenharmony_ci			usb_rcvctrlpipe(data->usb_dev, 0),
6478c2ecf20Sopenharmony_ci			cmd,
6488c2ecf20Sopenharmony_ci			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
6498c2ecf20Sopenharmony_ci			wValue,
6508c2ecf20Sopenharmony_ci			data->ifnum,
6518c2ecf20Sopenharmony_ci			buffer, 0x01, USB_CTRL_GET_TIMEOUT);
6528c2ecf20Sopenharmony_ci	if (rv < 0) {
6538c2ecf20Sopenharmony_ci		dev_err(dev, "simple usb_control_msg failed %d\n", rv);
6548c2ecf20Sopenharmony_ci		goto exit;
6558c2ecf20Sopenharmony_ci	} else if (rv != 1) {
6568c2ecf20Sopenharmony_ci		dev_warn(dev, "simple usb_control_msg returned %d\n", rv);
6578c2ecf20Sopenharmony_ci		rv = -EIO;
6588c2ecf20Sopenharmony_ci		goto exit;
6598c2ecf20Sopenharmony_ci	}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
6628c2ecf20Sopenharmony_ci		dev_err(dev, "simple control status returned %x\n", buffer[0]);
6638c2ecf20Sopenharmony_ci		rv = -EIO;
6648c2ecf20Sopenharmony_ci		goto exit;
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci	rv = 0;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci exit:
6698c2ecf20Sopenharmony_ci	kfree(buffer);
6708c2ecf20Sopenharmony_ci	return rv;
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci/*
6748c2ecf20Sopenharmony_ci * Sends a TRIGGER Bulk-OUT command message
6758c2ecf20Sopenharmony_ci * See the USBTMC-USB488 specification, Table 2.
6768c2ecf20Sopenharmony_ci *
6778c2ecf20Sopenharmony_ci * Also updates bTag_last_write.
6788c2ecf20Sopenharmony_ci */
6798c2ecf20Sopenharmony_cistatic int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = file_data->data;
6828c2ecf20Sopenharmony_ci	int retval;
6838c2ecf20Sopenharmony_ci	u8 *buffer;
6848c2ecf20Sopenharmony_ci	int actual;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	buffer = kzalloc(USBTMC_HEADER_SIZE, GFP_KERNEL);
6878c2ecf20Sopenharmony_ci	if (!buffer)
6888c2ecf20Sopenharmony_ci		return -ENOMEM;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	buffer[0] = 128;
6918c2ecf20Sopenharmony_ci	buffer[1] = data->bTag;
6928c2ecf20Sopenharmony_ci	buffer[2] = ~data->bTag;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	retval = usb_bulk_msg(data->usb_dev,
6958c2ecf20Sopenharmony_ci			      usb_sndbulkpipe(data->usb_dev,
6968c2ecf20Sopenharmony_ci					      data->bulk_out),
6978c2ecf20Sopenharmony_ci			      buffer, USBTMC_HEADER_SIZE,
6988c2ecf20Sopenharmony_ci			      &actual, file_data->timeout);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	/* Store bTag (in case we need to abort) */
7018c2ecf20Sopenharmony_ci	data->bTag_last_write = data->bTag;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	/* Increment bTag -- and increment again if zero */
7048c2ecf20Sopenharmony_ci	data->bTag++;
7058c2ecf20Sopenharmony_ci	if (!data->bTag)
7068c2ecf20Sopenharmony_ci		data->bTag++;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	kfree(buffer);
7098c2ecf20Sopenharmony_ci	if (retval < 0) {
7108c2ecf20Sopenharmony_ci		dev_err(&data->intf->dev, "%s returned %d\n",
7118c2ecf20Sopenharmony_ci			__func__, retval);
7128c2ecf20Sopenharmony_ci		return retval;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	return 0;
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_cistatic struct urb *usbtmc_create_urb(void)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	const size_t bufsize = USBTMC_BUFSIZE;
7218c2ecf20Sopenharmony_ci	u8 *dmabuf = NULL;
7228c2ecf20Sopenharmony_ci	struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	if (!urb)
7258c2ecf20Sopenharmony_ci		return NULL;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	dmabuf = kmalloc(bufsize, GFP_KERNEL);
7288c2ecf20Sopenharmony_ci	if (!dmabuf) {
7298c2ecf20Sopenharmony_ci		usb_free_urb(urb);
7308c2ecf20Sopenharmony_ci		return NULL;
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	urb->transfer_buffer = dmabuf;
7348c2ecf20Sopenharmony_ci	urb->transfer_buffer_length = bufsize;
7358c2ecf20Sopenharmony_ci	urb->transfer_flags |= URB_FREE_BUFFER;
7368c2ecf20Sopenharmony_ci	return urb;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic void usbtmc_read_bulk_cb(struct urb *urb)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data = urb->context;
7428c2ecf20Sopenharmony_ci	int status = urb->status;
7438c2ecf20Sopenharmony_ci	unsigned long flags;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	/* sync/async unlink faults aren't errors */
7468c2ecf20Sopenharmony_ci	if (status) {
7478c2ecf20Sopenharmony_ci		if (!(/* status == -ENOENT || */
7488c2ecf20Sopenharmony_ci			status == -ECONNRESET ||
7498c2ecf20Sopenharmony_ci			status == -EREMOTEIO || /* Short packet */
7508c2ecf20Sopenharmony_ci			status == -ESHUTDOWN))
7518c2ecf20Sopenharmony_ci			dev_err(&file_data->data->intf->dev,
7528c2ecf20Sopenharmony_ci			"%s - nonzero read bulk status received: %d\n",
7538c2ecf20Sopenharmony_ci			__func__, status);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		spin_lock_irqsave(&file_data->err_lock, flags);
7568c2ecf20Sopenharmony_ci		if (!file_data->in_status)
7578c2ecf20Sopenharmony_ci			file_data->in_status = status;
7588c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&file_data->err_lock, flags);
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	spin_lock_irqsave(&file_data->err_lock, flags);
7628c2ecf20Sopenharmony_ci	file_data->in_transfer_size += urb->actual_length;
7638c2ecf20Sopenharmony_ci	dev_dbg(&file_data->data->intf->dev,
7648c2ecf20Sopenharmony_ci		"%s - total size: %u current: %d status: %d\n",
7658c2ecf20Sopenharmony_ci		__func__, file_data->in_transfer_size,
7668c2ecf20Sopenharmony_ci		urb->actual_length, status);
7678c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&file_data->err_lock, flags);
7688c2ecf20Sopenharmony_ci	usb_anchor_urb(urb, &file_data->in_anchor);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	wake_up_interruptible(&file_data->wait_bulk_in);
7718c2ecf20Sopenharmony_ci	wake_up_interruptible(&file_data->data->waitq);
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_cistatic inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data)
7758c2ecf20Sopenharmony_ci{
7768c2ecf20Sopenharmony_ci	bool data_or_error;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->err_lock);
7798c2ecf20Sopenharmony_ci	data_or_error = !usb_anchor_empty(&file_data->in_anchor)
7808c2ecf20Sopenharmony_ci			|| file_data->in_status;
7818c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->err_lock);
7828c2ecf20Sopenharmony_ci	dev_dbg(&file_data->data->intf->dev, "%s: returns %d\n", __func__,
7838c2ecf20Sopenharmony_ci		data_or_error);
7848c2ecf20Sopenharmony_ci	return data_or_error;
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data,
7888c2ecf20Sopenharmony_ci				   void __user *user_buffer,
7898c2ecf20Sopenharmony_ci				   u32 transfer_size,
7908c2ecf20Sopenharmony_ci				   u32 *transferred,
7918c2ecf20Sopenharmony_ci				   u32 flags)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = file_data->data;
7948c2ecf20Sopenharmony_ci	struct device *dev = &data->intf->dev;
7958c2ecf20Sopenharmony_ci	u32 done = 0;
7968c2ecf20Sopenharmony_ci	u32 remaining;
7978c2ecf20Sopenharmony_ci	const u32 bufsize = USBTMC_BUFSIZE;
7988c2ecf20Sopenharmony_ci	int retval = 0;
7998c2ecf20Sopenharmony_ci	u32 max_transfer_size;
8008c2ecf20Sopenharmony_ci	unsigned long expire;
8018c2ecf20Sopenharmony_ci	int bufcount = 1;
8028c2ecf20Sopenharmony_ci	int again = 0;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	/* mutex already locked */
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	*transferred = done;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	max_transfer_size = transfer_size;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	if (flags & USBTMC_FLAG_IGNORE_TRAILER) {
8118c2ecf20Sopenharmony_ci		/* The device may send extra alignment bytes (up to
8128c2ecf20Sopenharmony_ci		 * wMaxPacketSize – 1) to avoid sending a zero-length
8138c2ecf20Sopenharmony_ci		 * packet
8148c2ecf20Sopenharmony_ci		 */
8158c2ecf20Sopenharmony_ci		remaining = transfer_size;
8168c2ecf20Sopenharmony_ci		if ((max_transfer_size % data->wMaxPacketSize) == 0)
8178c2ecf20Sopenharmony_ci			max_transfer_size += (data->wMaxPacketSize - 1);
8188c2ecf20Sopenharmony_ci	} else {
8198c2ecf20Sopenharmony_ci		/* round down to bufsize to avoid truncated data left */
8208c2ecf20Sopenharmony_ci		if (max_transfer_size > bufsize) {
8218c2ecf20Sopenharmony_ci			max_transfer_size =
8228c2ecf20Sopenharmony_ci				roundup(max_transfer_size + 1 - bufsize,
8238c2ecf20Sopenharmony_ci					bufsize);
8248c2ecf20Sopenharmony_ci		}
8258c2ecf20Sopenharmony_ci		remaining = max_transfer_size;
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->err_lock);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (file_data->in_status) {
8318c2ecf20Sopenharmony_ci		/* return the very first error */
8328c2ecf20Sopenharmony_ci		retval = file_data->in_status;
8338c2ecf20Sopenharmony_ci		spin_unlock_irq(&file_data->err_lock);
8348c2ecf20Sopenharmony_ci		goto error;
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (flags & USBTMC_FLAG_ASYNC) {
8388c2ecf20Sopenharmony_ci		if (usb_anchor_empty(&file_data->in_anchor))
8398c2ecf20Sopenharmony_ci			again = 1;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci		if (file_data->in_urbs_used == 0) {
8428c2ecf20Sopenharmony_ci			file_data->in_transfer_size = 0;
8438c2ecf20Sopenharmony_ci			file_data->in_status = 0;
8448c2ecf20Sopenharmony_ci		}
8458c2ecf20Sopenharmony_ci	} else {
8468c2ecf20Sopenharmony_ci		file_data->in_transfer_size = 0;
8478c2ecf20Sopenharmony_ci		file_data->in_status = 0;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	if (max_transfer_size == 0) {
8518c2ecf20Sopenharmony_ci		bufcount = 0;
8528c2ecf20Sopenharmony_ci	} else {
8538c2ecf20Sopenharmony_ci		bufcount = roundup(max_transfer_size, bufsize) / bufsize;
8548c2ecf20Sopenharmony_ci		if (bufcount > file_data->in_urbs_used)
8558c2ecf20Sopenharmony_ci			bufcount -= file_data->in_urbs_used;
8568c2ecf20Sopenharmony_ci		else
8578c2ecf20Sopenharmony_ci			bufcount = 0;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci		if (bufcount + file_data->in_urbs_used > MAX_URBS_IN_FLIGHT) {
8608c2ecf20Sopenharmony_ci			bufcount = MAX_URBS_IN_FLIGHT -
8618c2ecf20Sopenharmony_ci					file_data->in_urbs_used;
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->err_lock);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: requested=%u flags=0x%X size=%u bufs=%d used=%d\n",
8678c2ecf20Sopenharmony_ci		__func__, transfer_size, flags,
8688c2ecf20Sopenharmony_ci		max_transfer_size, bufcount, file_data->in_urbs_used);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	while (bufcount > 0) {
8718c2ecf20Sopenharmony_ci		u8 *dmabuf = NULL;
8728c2ecf20Sopenharmony_ci		struct urb *urb = usbtmc_create_urb();
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci		if (!urb) {
8758c2ecf20Sopenharmony_ci			retval = -ENOMEM;
8768c2ecf20Sopenharmony_ci			goto error;
8778c2ecf20Sopenharmony_ci		}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci		dmabuf = urb->transfer_buffer;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci		usb_fill_bulk_urb(urb, data->usb_dev,
8828c2ecf20Sopenharmony_ci			usb_rcvbulkpipe(data->usb_dev, data->bulk_in),
8838c2ecf20Sopenharmony_ci			dmabuf, bufsize,
8848c2ecf20Sopenharmony_ci			usbtmc_read_bulk_cb, file_data);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci		usb_anchor_urb(urb, &file_data->submitted);
8878c2ecf20Sopenharmony_ci		retval = usb_submit_urb(urb, GFP_KERNEL);
8888c2ecf20Sopenharmony_ci		/* urb is anchored. We can release our reference. */
8898c2ecf20Sopenharmony_ci		usb_free_urb(urb);
8908c2ecf20Sopenharmony_ci		if (unlikely(retval)) {
8918c2ecf20Sopenharmony_ci			usb_unanchor_urb(urb);
8928c2ecf20Sopenharmony_ci			goto error;
8938c2ecf20Sopenharmony_ci		}
8948c2ecf20Sopenharmony_ci		file_data->in_urbs_used++;
8958c2ecf20Sopenharmony_ci		bufcount--;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (again) {
8998c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s: ret=again\n", __func__);
9008c2ecf20Sopenharmony_ci		return -EAGAIN;
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	if (user_buffer == NULL)
9048c2ecf20Sopenharmony_ci		return -EINVAL;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	expire = msecs_to_jiffies(file_data->timeout);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	while (max_transfer_size > 0) {
9098c2ecf20Sopenharmony_ci		u32 this_part;
9108c2ecf20Sopenharmony_ci		struct urb *urb = NULL;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci		if (!(flags & USBTMC_FLAG_ASYNC)) {
9138c2ecf20Sopenharmony_ci			dev_dbg(dev, "%s: before wait time %lu\n",
9148c2ecf20Sopenharmony_ci				__func__, expire);
9158c2ecf20Sopenharmony_ci			retval = wait_event_interruptible_timeout(
9168c2ecf20Sopenharmony_ci				file_data->wait_bulk_in,
9178c2ecf20Sopenharmony_ci				usbtmc_do_transfer(file_data),
9188c2ecf20Sopenharmony_ci				expire);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci			dev_dbg(dev, "%s: wait returned %d\n",
9218c2ecf20Sopenharmony_ci				__func__, retval);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci			if (retval <= 0) {
9248c2ecf20Sopenharmony_ci				if (retval == 0)
9258c2ecf20Sopenharmony_ci					retval = -ETIMEDOUT;
9268c2ecf20Sopenharmony_ci				goto error;
9278c2ecf20Sopenharmony_ci			}
9288c2ecf20Sopenharmony_ci		}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci		urb = usb_get_from_anchor(&file_data->in_anchor);
9318c2ecf20Sopenharmony_ci		if (!urb) {
9328c2ecf20Sopenharmony_ci			if (!(flags & USBTMC_FLAG_ASYNC)) {
9338c2ecf20Sopenharmony_ci				/* synchronous case: must not happen */
9348c2ecf20Sopenharmony_ci				retval = -EFAULT;
9358c2ecf20Sopenharmony_ci				goto error;
9368c2ecf20Sopenharmony_ci			}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci			/* asynchronous case: ready, do not block or wait */
9398c2ecf20Sopenharmony_ci			*transferred = done;
9408c2ecf20Sopenharmony_ci			dev_dbg(dev, "%s: (async) done=%u ret=0\n",
9418c2ecf20Sopenharmony_ci				__func__, done);
9428c2ecf20Sopenharmony_ci			return 0;
9438c2ecf20Sopenharmony_ci		}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci		file_data->in_urbs_used--;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci		if (max_transfer_size > urb->actual_length)
9488c2ecf20Sopenharmony_ci			max_transfer_size -= urb->actual_length;
9498c2ecf20Sopenharmony_ci		else
9508c2ecf20Sopenharmony_ci			max_transfer_size = 0;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci		if (remaining > urb->actual_length)
9538c2ecf20Sopenharmony_ci			this_part = urb->actual_length;
9548c2ecf20Sopenharmony_ci		else
9558c2ecf20Sopenharmony_ci			this_part = remaining;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci		print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1,
9588c2ecf20Sopenharmony_ci			urb->transfer_buffer, urb->actual_length, true);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci		if (copy_to_user(user_buffer + done,
9618c2ecf20Sopenharmony_ci				 urb->transfer_buffer, this_part)) {
9628c2ecf20Sopenharmony_ci			usb_free_urb(urb);
9638c2ecf20Sopenharmony_ci			retval = -EFAULT;
9648c2ecf20Sopenharmony_ci			goto error;
9658c2ecf20Sopenharmony_ci		}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		remaining -= this_part;
9688c2ecf20Sopenharmony_ci		done += this_part;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci		spin_lock_irq(&file_data->err_lock);
9718c2ecf20Sopenharmony_ci		if (urb->status) {
9728c2ecf20Sopenharmony_ci			/* return the very first error */
9738c2ecf20Sopenharmony_ci			retval = file_data->in_status;
9748c2ecf20Sopenharmony_ci			spin_unlock_irq(&file_data->err_lock);
9758c2ecf20Sopenharmony_ci			usb_free_urb(urb);
9768c2ecf20Sopenharmony_ci			goto error;
9778c2ecf20Sopenharmony_ci		}
9788c2ecf20Sopenharmony_ci		spin_unlock_irq(&file_data->err_lock);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci		if (urb->actual_length < bufsize) {
9818c2ecf20Sopenharmony_ci			/* short packet or ZLP received => ready */
9828c2ecf20Sopenharmony_ci			usb_free_urb(urb);
9838c2ecf20Sopenharmony_ci			retval = 1;
9848c2ecf20Sopenharmony_ci			break;
9858c2ecf20Sopenharmony_ci		}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci		if (!(flags & USBTMC_FLAG_ASYNC) &&
9888c2ecf20Sopenharmony_ci		    max_transfer_size > (bufsize * file_data->in_urbs_used)) {
9898c2ecf20Sopenharmony_ci			/* resubmit, since other buffers still not enough */
9908c2ecf20Sopenharmony_ci			usb_anchor_urb(urb, &file_data->submitted);
9918c2ecf20Sopenharmony_ci			retval = usb_submit_urb(urb, GFP_KERNEL);
9928c2ecf20Sopenharmony_ci			if (unlikely(retval)) {
9938c2ecf20Sopenharmony_ci				usb_unanchor_urb(urb);
9948c2ecf20Sopenharmony_ci				usb_free_urb(urb);
9958c2ecf20Sopenharmony_ci				goto error;
9968c2ecf20Sopenharmony_ci			}
9978c2ecf20Sopenharmony_ci			file_data->in_urbs_used++;
9988c2ecf20Sopenharmony_ci		}
9998c2ecf20Sopenharmony_ci		usb_free_urb(urb);
10008c2ecf20Sopenharmony_ci		retval = 0;
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_cierror:
10048c2ecf20Sopenharmony_ci	*transferred = done;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: before kill\n", __func__);
10078c2ecf20Sopenharmony_ci	/* Attention: killing urbs can take long time (2 ms) */
10088c2ecf20Sopenharmony_ci	usb_kill_anchored_urbs(&file_data->submitted);
10098c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: after kill\n", __func__);
10108c2ecf20Sopenharmony_ci	usb_scuttle_anchored_urbs(&file_data->in_anchor);
10118c2ecf20Sopenharmony_ci	file_data->in_urbs_used = 0;
10128c2ecf20Sopenharmony_ci	file_data->in_status = 0; /* no spinlock needed here */
10138c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: done=%u ret=%d\n", __func__, done, retval);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	return retval;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic ssize_t usbtmc_ioctl_generic_read(struct usbtmc_file_data *file_data,
10198c2ecf20Sopenharmony_ci					 void __user *arg)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct usbtmc_message msg;
10228c2ecf20Sopenharmony_ci	ssize_t retval = 0;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	/* mutex already locked */
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message)))
10278c2ecf20Sopenharmony_ci		return -EFAULT;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	retval = usbtmc_generic_read(file_data, msg.message,
10308c2ecf20Sopenharmony_ci				     msg.transfer_size, &msg.transferred,
10318c2ecf20Sopenharmony_ci				     msg.flags);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	if (put_user(msg.transferred,
10348c2ecf20Sopenharmony_ci		     &((struct usbtmc_message __user *)arg)->transferred))
10358c2ecf20Sopenharmony_ci		return -EFAULT;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	return retval;
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_cistatic void usbtmc_write_bulk_cb(struct urb *urb)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data = urb->context;
10438c2ecf20Sopenharmony_ci	int wakeup = 0;
10448c2ecf20Sopenharmony_ci	unsigned long flags;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	spin_lock_irqsave(&file_data->err_lock, flags);
10478c2ecf20Sopenharmony_ci	file_data->out_transfer_size += urb->actual_length;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	/* sync/async unlink faults aren't errors */
10508c2ecf20Sopenharmony_ci	if (urb->status) {
10518c2ecf20Sopenharmony_ci		if (!(urb->status == -ENOENT ||
10528c2ecf20Sopenharmony_ci			urb->status == -ECONNRESET ||
10538c2ecf20Sopenharmony_ci			urb->status == -ESHUTDOWN))
10548c2ecf20Sopenharmony_ci			dev_err(&file_data->data->intf->dev,
10558c2ecf20Sopenharmony_ci				"%s - nonzero write bulk status received: %d\n",
10568c2ecf20Sopenharmony_ci				__func__, urb->status);
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci		if (!file_data->out_status) {
10598c2ecf20Sopenharmony_ci			file_data->out_status = urb->status;
10608c2ecf20Sopenharmony_ci			wakeup = 1;
10618c2ecf20Sopenharmony_ci		}
10628c2ecf20Sopenharmony_ci	}
10638c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&file_data->err_lock, flags);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	dev_dbg(&file_data->data->intf->dev,
10668c2ecf20Sopenharmony_ci		"%s - write bulk total size: %u\n",
10678c2ecf20Sopenharmony_ci		__func__, file_data->out_transfer_size);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	up(&file_data->limit_write_sem);
10708c2ecf20Sopenharmony_ci	if (usb_anchor_empty(&file_data->submitted) || wakeup)
10718c2ecf20Sopenharmony_ci		wake_up_interruptible(&file_data->data->waitq);
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_cistatic ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data,
10758c2ecf20Sopenharmony_ci				    const void __user *user_buffer,
10768c2ecf20Sopenharmony_ci				    u32 transfer_size,
10778c2ecf20Sopenharmony_ci				    u32 *transferred,
10788c2ecf20Sopenharmony_ci				    u32 flags)
10798c2ecf20Sopenharmony_ci{
10808c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = file_data->data;
10818c2ecf20Sopenharmony_ci	struct device *dev;
10828c2ecf20Sopenharmony_ci	u32 done = 0;
10838c2ecf20Sopenharmony_ci	u32 remaining;
10848c2ecf20Sopenharmony_ci	unsigned long expire;
10858c2ecf20Sopenharmony_ci	const u32 bufsize = USBTMC_BUFSIZE;
10868c2ecf20Sopenharmony_ci	struct urb *urb = NULL;
10878c2ecf20Sopenharmony_ci	int retval = 0;
10888c2ecf20Sopenharmony_ci	u32 timeout;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	*transferred = 0;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	/* Get pointer to private data structure */
10938c2ecf20Sopenharmony_ci	dev = &data->intf->dev;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: size=%u flags=0x%X sema=%u\n",
10968c2ecf20Sopenharmony_ci		__func__, transfer_size, flags,
10978c2ecf20Sopenharmony_ci		file_data->limit_write_sem.count);
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	if (flags & USBTMC_FLAG_APPEND) {
11008c2ecf20Sopenharmony_ci		spin_lock_irq(&file_data->err_lock);
11018c2ecf20Sopenharmony_ci		retval = file_data->out_status;
11028c2ecf20Sopenharmony_ci		spin_unlock_irq(&file_data->err_lock);
11038c2ecf20Sopenharmony_ci		if (retval < 0)
11048c2ecf20Sopenharmony_ci			return retval;
11058c2ecf20Sopenharmony_ci	} else {
11068c2ecf20Sopenharmony_ci		spin_lock_irq(&file_data->err_lock);
11078c2ecf20Sopenharmony_ci		file_data->out_transfer_size = 0;
11088c2ecf20Sopenharmony_ci		file_data->out_status = 0;
11098c2ecf20Sopenharmony_ci		spin_unlock_irq(&file_data->err_lock);
11108c2ecf20Sopenharmony_ci	}
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	remaining = transfer_size;
11138c2ecf20Sopenharmony_ci	if (remaining > INT_MAX)
11148c2ecf20Sopenharmony_ci		remaining = INT_MAX;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	timeout = file_data->timeout;
11178c2ecf20Sopenharmony_ci	expire = msecs_to_jiffies(timeout);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	while (remaining > 0) {
11208c2ecf20Sopenharmony_ci		u32 this_part, aligned;
11218c2ecf20Sopenharmony_ci		u8 *buffer = NULL;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci		if (flags & USBTMC_FLAG_ASYNC) {
11248c2ecf20Sopenharmony_ci			if (down_trylock(&file_data->limit_write_sem)) {
11258c2ecf20Sopenharmony_ci				retval = (done)?(0):(-EAGAIN);
11268c2ecf20Sopenharmony_ci				goto exit;
11278c2ecf20Sopenharmony_ci			}
11288c2ecf20Sopenharmony_ci		} else {
11298c2ecf20Sopenharmony_ci			retval = down_timeout(&file_data->limit_write_sem,
11308c2ecf20Sopenharmony_ci					      expire);
11318c2ecf20Sopenharmony_ci			if (retval < 0) {
11328c2ecf20Sopenharmony_ci				retval = -ETIMEDOUT;
11338c2ecf20Sopenharmony_ci				goto error;
11348c2ecf20Sopenharmony_ci			}
11358c2ecf20Sopenharmony_ci		}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci		spin_lock_irq(&file_data->err_lock);
11388c2ecf20Sopenharmony_ci		retval = file_data->out_status;
11398c2ecf20Sopenharmony_ci		spin_unlock_irq(&file_data->err_lock);
11408c2ecf20Sopenharmony_ci		if (retval < 0) {
11418c2ecf20Sopenharmony_ci			up(&file_data->limit_write_sem);
11428c2ecf20Sopenharmony_ci			goto error;
11438c2ecf20Sopenharmony_ci		}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci		/* prepare next urb to send */
11468c2ecf20Sopenharmony_ci		urb = usbtmc_create_urb();
11478c2ecf20Sopenharmony_ci		if (!urb) {
11488c2ecf20Sopenharmony_ci			retval = -ENOMEM;
11498c2ecf20Sopenharmony_ci			up(&file_data->limit_write_sem);
11508c2ecf20Sopenharmony_ci			goto error;
11518c2ecf20Sopenharmony_ci		}
11528c2ecf20Sopenharmony_ci		buffer = urb->transfer_buffer;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci		if (remaining > bufsize)
11558c2ecf20Sopenharmony_ci			this_part = bufsize;
11568c2ecf20Sopenharmony_ci		else
11578c2ecf20Sopenharmony_ci			this_part = remaining;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci		if (copy_from_user(buffer, user_buffer + done, this_part)) {
11608c2ecf20Sopenharmony_ci			retval = -EFAULT;
11618c2ecf20Sopenharmony_ci			up(&file_data->limit_write_sem);
11628c2ecf20Sopenharmony_ci			goto error;
11638c2ecf20Sopenharmony_ci		}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci		print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
11668c2ecf20Sopenharmony_ci			16, 1, buffer, this_part, true);
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci		/* fill bulk with 32 bit alignment to meet USBTMC specification
11698c2ecf20Sopenharmony_ci		 * (size + 3 & ~3) rounds up and simplifies user code
11708c2ecf20Sopenharmony_ci		 */
11718c2ecf20Sopenharmony_ci		aligned = (this_part + 3) & ~3;
11728c2ecf20Sopenharmony_ci		dev_dbg(dev, "write(size:%u align:%u done:%u)\n",
11738c2ecf20Sopenharmony_ci			(unsigned int)this_part,
11748c2ecf20Sopenharmony_ci			(unsigned int)aligned,
11758c2ecf20Sopenharmony_ci			(unsigned int)done);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci		usb_fill_bulk_urb(urb, data->usb_dev,
11788c2ecf20Sopenharmony_ci			usb_sndbulkpipe(data->usb_dev, data->bulk_out),
11798c2ecf20Sopenharmony_ci			urb->transfer_buffer, aligned,
11808c2ecf20Sopenharmony_ci			usbtmc_write_bulk_cb, file_data);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci		usb_anchor_urb(urb, &file_data->submitted);
11838c2ecf20Sopenharmony_ci		retval = usb_submit_urb(urb, GFP_KERNEL);
11848c2ecf20Sopenharmony_ci		if (unlikely(retval)) {
11858c2ecf20Sopenharmony_ci			usb_unanchor_urb(urb);
11868c2ecf20Sopenharmony_ci			up(&file_data->limit_write_sem);
11878c2ecf20Sopenharmony_ci			goto error;
11888c2ecf20Sopenharmony_ci		}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci		usb_free_urb(urb);
11918c2ecf20Sopenharmony_ci		urb = NULL; /* urb will be finally released by usb driver */
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci		remaining -= this_part;
11948c2ecf20Sopenharmony_ci		done += this_part;
11958c2ecf20Sopenharmony_ci	}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	/* All urbs are on the fly */
11988c2ecf20Sopenharmony_ci	if (!(flags & USBTMC_FLAG_ASYNC)) {
11998c2ecf20Sopenharmony_ci		if (!usb_wait_anchor_empty_timeout(&file_data->submitted,
12008c2ecf20Sopenharmony_ci						   timeout)) {
12018c2ecf20Sopenharmony_ci			retval = -ETIMEDOUT;
12028c2ecf20Sopenharmony_ci			goto error;
12038c2ecf20Sopenharmony_ci		}
12048c2ecf20Sopenharmony_ci	}
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	retval = 0;
12078c2ecf20Sopenharmony_ci	goto exit;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cierror:
12108c2ecf20Sopenharmony_ci	usb_kill_anchored_urbs(&file_data->submitted);
12118c2ecf20Sopenharmony_ciexit:
12128c2ecf20Sopenharmony_ci	usb_free_urb(urb);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->err_lock);
12158c2ecf20Sopenharmony_ci	if (!(flags & USBTMC_FLAG_ASYNC))
12168c2ecf20Sopenharmony_ci		done = file_data->out_transfer_size;
12178c2ecf20Sopenharmony_ci	if (!retval && file_data->out_status)
12188c2ecf20Sopenharmony_ci		retval = file_data->out_status;
12198c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->err_lock);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	*transferred = done;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: done=%u, retval=%d, urbstat=%d\n",
12248c2ecf20Sopenharmony_ci		__func__, done, retval, file_data->out_status);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	return retval;
12278c2ecf20Sopenharmony_ci}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_cistatic ssize_t usbtmc_ioctl_generic_write(struct usbtmc_file_data *file_data,
12308c2ecf20Sopenharmony_ci					  void __user *arg)
12318c2ecf20Sopenharmony_ci{
12328c2ecf20Sopenharmony_ci	struct usbtmc_message msg;
12338c2ecf20Sopenharmony_ci	ssize_t retval = 0;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	/* mutex already locked */
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message)))
12388c2ecf20Sopenharmony_ci		return -EFAULT;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	retval = usbtmc_generic_write(file_data, msg.message,
12418c2ecf20Sopenharmony_ci				      msg.transfer_size, &msg.transferred,
12428c2ecf20Sopenharmony_ci				      msg.flags);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	if (put_user(msg.transferred,
12458c2ecf20Sopenharmony_ci		     &((struct usbtmc_message __user *)arg)->transferred))
12468c2ecf20Sopenharmony_ci		return -EFAULT;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	return retval;
12498c2ecf20Sopenharmony_ci}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci/*
12528c2ecf20Sopenharmony_ci * Get the generic write result
12538c2ecf20Sopenharmony_ci */
12548c2ecf20Sopenharmony_cistatic ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data,
12558c2ecf20Sopenharmony_ci				void __user *arg)
12568c2ecf20Sopenharmony_ci{
12578c2ecf20Sopenharmony_ci	u32 transferred;
12588c2ecf20Sopenharmony_ci	int retval;
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->err_lock);
12618c2ecf20Sopenharmony_ci	transferred = file_data->out_transfer_size;
12628c2ecf20Sopenharmony_ci	retval = file_data->out_status;
12638c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->err_lock);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	if (put_user(transferred, (__u32 __user *)arg))
12668c2ecf20Sopenharmony_ci		return -EFAULT;
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	return retval;
12698c2ecf20Sopenharmony_ci}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci/*
12728c2ecf20Sopenharmony_ci * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
12738c2ecf20Sopenharmony_ci * @transfer_size: number of bytes to request from the device.
12748c2ecf20Sopenharmony_ci *
12758c2ecf20Sopenharmony_ci * See the USBTMC specification, Table 4.
12768c2ecf20Sopenharmony_ci *
12778c2ecf20Sopenharmony_ci * Also updates bTag_last_write.
12788c2ecf20Sopenharmony_ci */
12798c2ecf20Sopenharmony_cistatic int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
12808c2ecf20Sopenharmony_ci				       u32 transfer_size)
12818c2ecf20Sopenharmony_ci{
12828c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = file_data->data;
12838c2ecf20Sopenharmony_ci	int retval;
12848c2ecf20Sopenharmony_ci	u8 *buffer;
12858c2ecf20Sopenharmony_ci	int actual;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	buffer = kmalloc(USBTMC_HEADER_SIZE, GFP_KERNEL);
12888c2ecf20Sopenharmony_ci	if (!buffer)
12898c2ecf20Sopenharmony_ci		return -ENOMEM;
12908c2ecf20Sopenharmony_ci	/* Setup IO buffer for REQUEST_DEV_DEP_MSG_IN message
12918c2ecf20Sopenharmony_ci	 * Refer to class specs for details
12928c2ecf20Sopenharmony_ci	 */
12938c2ecf20Sopenharmony_ci	buffer[0] = 2;
12948c2ecf20Sopenharmony_ci	buffer[1] = data->bTag;
12958c2ecf20Sopenharmony_ci	buffer[2] = ~data->bTag;
12968c2ecf20Sopenharmony_ci	buffer[3] = 0; /* Reserved */
12978c2ecf20Sopenharmony_ci	buffer[4] = transfer_size >> 0;
12988c2ecf20Sopenharmony_ci	buffer[5] = transfer_size >> 8;
12998c2ecf20Sopenharmony_ci	buffer[6] = transfer_size >> 16;
13008c2ecf20Sopenharmony_ci	buffer[7] = transfer_size >> 24;
13018c2ecf20Sopenharmony_ci	buffer[8] = file_data->term_char_enabled * 2;
13028c2ecf20Sopenharmony_ci	/* Use term character? */
13038c2ecf20Sopenharmony_ci	buffer[9] = file_data->term_char;
13048c2ecf20Sopenharmony_ci	buffer[10] = 0; /* Reserved */
13058c2ecf20Sopenharmony_ci	buffer[11] = 0; /* Reserved */
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	/* Send bulk URB */
13088c2ecf20Sopenharmony_ci	retval = usb_bulk_msg(data->usb_dev,
13098c2ecf20Sopenharmony_ci			      usb_sndbulkpipe(data->usb_dev,
13108c2ecf20Sopenharmony_ci					      data->bulk_out),
13118c2ecf20Sopenharmony_ci			      buffer, USBTMC_HEADER_SIZE,
13128c2ecf20Sopenharmony_ci			      &actual, file_data->timeout);
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	/* Store bTag (in case we need to abort) */
13158c2ecf20Sopenharmony_ci	data->bTag_last_write = data->bTag;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	/* Increment bTag -- and increment again if zero */
13188c2ecf20Sopenharmony_ci	data->bTag++;
13198c2ecf20Sopenharmony_ci	if (!data->bTag)
13208c2ecf20Sopenharmony_ci		data->bTag++;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	kfree(buffer);
13238c2ecf20Sopenharmony_ci	if (retval < 0)
13248c2ecf20Sopenharmony_ci		dev_err(&data->intf->dev, "%s returned %d\n",
13258c2ecf20Sopenharmony_ci			__func__, retval);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	return retval;
13288c2ecf20Sopenharmony_ci}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_cistatic ssize_t usbtmc_read(struct file *filp, char __user *buf,
13318c2ecf20Sopenharmony_ci			   size_t count, loff_t *f_pos)
13328c2ecf20Sopenharmony_ci{
13338c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data;
13348c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data;
13358c2ecf20Sopenharmony_ci	struct device *dev;
13368c2ecf20Sopenharmony_ci	const u32 bufsize = USBTMC_BUFSIZE;
13378c2ecf20Sopenharmony_ci	u32 n_characters;
13388c2ecf20Sopenharmony_ci	u8 *buffer;
13398c2ecf20Sopenharmony_ci	int actual;
13408c2ecf20Sopenharmony_ci	u32 done = 0;
13418c2ecf20Sopenharmony_ci	u32 remaining;
13428c2ecf20Sopenharmony_ci	int retval;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	/* Get pointer to private data structure */
13458c2ecf20Sopenharmony_ci	file_data = filp->private_data;
13468c2ecf20Sopenharmony_ci	data = file_data->data;
13478c2ecf20Sopenharmony_ci	dev = &data->intf->dev;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	buffer = kmalloc(bufsize, GFP_KERNEL);
13508c2ecf20Sopenharmony_ci	if (!buffer)
13518c2ecf20Sopenharmony_ci		return -ENOMEM;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
13548c2ecf20Sopenharmony_ci	if (data->zombie) {
13558c2ecf20Sopenharmony_ci		retval = -ENODEV;
13568c2ecf20Sopenharmony_ci		goto exit;
13578c2ecf20Sopenharmony_ci	}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	if (count > INT_MAX)
13608c2ecf20Sopenharmony_ci		count = INT_MAX;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s(count:%zu)\n", __func__, count);
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	retval = send_request_dev_dep_msg_in(file_data, count);
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	if (retval < 0) {
13678c2ecf20Sopenharmony_ci		if (file_data->auto_abort)
13688c2ecf20Sopenharmony_ci			usbtmc_ioctl_abort_bulk_out(data);
13698c2ecf20Sopenharmony_ci		goto exit;
13708c2ecf20Sopenharmony_ci	}
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	/* Loop until we have fetched everything we requested */
13738c2ecf20Sopenharmony_ci	remaining = count;
13748c2ecf20Sopenharmony_ci	actual = 0;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	/* Send bulk URB */
13778c2ecf20Sopenharmony_ci	retval = usb_bulk_msg(data->usb_dev,
13788c2ecf20Sopenharmony_ci			      usb_rcvbulkpipe(data->usb_dev,
13798c2ecf20Sopenharmony_ci					      data->bulk_in),
13808c2ecf20Sopenharmony_ci			      buffer, bufsize, &actual,
13818c2ecf20Sopenharmony_ci			      file_data->timeout);
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n",
13848c2ecf20Sopenharmony_ci		__func__, retval, actual);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	/* Store bTag (in case we need to abort) */
13878c2ecf20Sopenharmony_ci	data->bTag_last_read = data->bTag;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	if (retval < 0) {
13908c2ecf20Sopenharmony_ci		if (file_data->auto_abort)
13918c2ecf20Sopenharmony_ci			usbtmc_ioctl_abort_bulk_in(data);
13928c2ecf20Sopenharmony_ci		goto exit;
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	/* Sanity checks for the header */
13968c2ecf20Sopenharmony_ci	if (actual < USBTMC_HEADER_SIZE) {
13978c2ecf20Sopenharmony_ci		dev_err(dev, "Device sent too small first packet: %u < %u\n",
13988c2ecf20Sopenharmony_ci			actual, USBTMC_HEADER_SIZE);
13998c2ecf20Sopenharmony_ci		if (file_data->auto_abort)
14008c2ecf20Sopenharmony_ci			usbtmc_ioctl_abort_bulk_in(data);
14018c2ecf20Sopenharmony_ci		goto exit;
14028c2ecf20Sopenharmony_ci	}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	if (buffer[0] != 2) {
14058c2ecf20Sopenharmony_ci		dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n",
14068c2ecf20Sopenharmony_ci			buffer[0]);
14078c2ecf20Sopenharmony_ci		if (file_data->auto_abort)
14088c2ecf20Sopenharmony_ci			usbtmc_ioctl_abort_bulk_in(data);
14098c2ecf20Sopenharmony_ci		goto exit;
14108c2ecf20Sopenharmony_ci	}
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (buffer[1] != data->bTag_last_write) {
14138c2ecf20Sopenharmony_ci		dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n",
14148c2ecf20Sopenharmony_ci		buffer[1], data->bTag_last_write);
14158c2ecf20Sopenharmony_ci		if (file_data->auto_abort)
14168c2ecf20Sopenharmony_ci			usbtmc_ioctl_abort_bulk_in(data);
14178c2ecf20Sopenharmony_ci		goto exit;
14188c2ecf20Sopenharmony_ci	}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	/* How many characters did the instrument send? */
14218c2ecf20Sopenharmony_ci	n_characters = buffer[4] +
14228c2ecf20Sopenharmony_ci		       (buffer[5] << 8) +
14238c2ecf20Sopenharmony_ci		       (buffer[6] << 16) +
14248c2ecf20Sopenharmony_ci		       (buffer[7] << 24);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	file_data->bmTransferAttributes = buffer[8];
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n",
14298c2ecf20Sopenharmony_ci		n_characters, buffer[8]);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	if (n_characters > remaining) {
14328c2ecf20Sopenharmony_ci		dev_err(dev, "Device wants to return more data than requested: %u > %zu\n",
14338c2ecf20Sopenharmony_ci			n_characters, count);
14348c2ecf20Sopenharmony_ci		if (file_data->auto_abort)
14358c2ecf20Sopenharmony_ci			usbtmc_ioctl_abort_bulk_in(data);
14368c2ecf20Sopenharmony_ci		goto exit;
14378c2ecf20Sopenharmony_ci	}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
14408c2ecf20Sopenharmony_ci			     16, 1, buffer, actual, true);
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	remaining = n_characters;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	/* Remove the USBTMC header */
14458c2ecf20Sopenharmony_ci	actual -= USBTMC_HEADER_SIZE;
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	/* Remove padding if it exists */
14488c2ecf20Sopenharmony_ci	if (actual > remaining)
14498c2ecf20Sopenharmony_ci		actual = remaining;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	remaining -= actual;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	/* Copy buffer to user space */
14548c2ecf20Sopenharmony_ci	if (copy_to_user(buf, &buffer[USBTMC_HEADER_SIZE], actual)) {
14558c2ecf20Sopenharmony_ci		/* There must have been an addressing problem */
14568c2ecf20Sopenharmony_ci		retval = -EFAULT;
14578c2ecf20Sopenharmony_ci		goto exit;
14588c2ecf20Sopenharmony_ci	}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	if ((actual + USBTMC_HEADER_SIZE) == bufsize) {
14618c2ecf20Sopenharmony_ci		retval = usbtmc_generic_read(file_data, buf + actual,
14628c2ecf20Sopenharmony_ci					     remaining,
14638c2ecf20Sopenharmony_ci					     &done,
14648c2ecf20Sopenharmony_ci					     USBTMC_FLAG_IGNORE_TRAILER);
14658c2ecf20Sopenharmony_ci		if (retval < 0)
14668c2ecf20Sopenharmony_ci			goto exit;
14678c2ecf20Sopenharmony_ci	}
14688c2ecf20Sopenharmony_ci	done += actual;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	/* Update file position value */
14718c2ecf20Sopenharmony_ci	*f_pos = *f_pos + done;
14728c2ecf20Sopenharmony_ci	retval = done;
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ciexit:
14758c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
14768c2ecf20Sopenharmony_ci	kfree(buffer);
14778c2ecf20Sopenharmony_ci	return retval;
14788c2ecf20Sopenharmony_ci}
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_cistatic ssize_t usbtmc_write(struct file *filp, const char __user *buf,
14818c2ecf20Sopenharmony_ci			    size_t count, loff_t *f_pos)
14828c2ecf20Sopenharmony_ci{
14838c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data;
14848c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data;
14858c2ecf20Sopenharmony_ci	struct urb *urb = NULL;
14868c2ecf20Sopenharmony_ci	ssize_t retval = 0;
14878c2ecf20Sopenharmony_ci	u8 *buffer;
14888c2ecf20Sopenharmony_ci	u32 remaining, done;
14898c2ecf20Sopenharmony_ci	u32 transfersize, aligned, buflen;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	file_data = filp->private_data;
14928c2ecf20Sopenharmony_ci	data = file_data->data;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	if (data->zombie) {
14978c2ecf20Sopenharmony_ci		retval = -ENODEV;
14988c2ecf20Sopenharmony_ci		goto exit;
14998c2ecf20Sopenharmony_ci	}
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	done = 0;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->err_lock);
15048c2ecf20Sopenharmony_ci	file_data->out_transfer_size = 0;
15058c2ecf20Sopenharmony_ci	file_data->out_status = 0;
15068c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->err_lock);
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	if (!count)
15098c2ecf20Sopenharmony_ci		goto exit;
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	if (down_trylock(&file_data->limit_write_sem)) {
15128c2ecf20Sopenharmony_ci		/* previous calls were async */
15138c2ecf20Sopenharmony_ci		retval = -EBUSY;
15148c2ecf20Sopenharmony_ci		goto exit;
15158c2ecf20Sopenharmony_ci	}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	urb = usbtmc_create_urb();
15188c2ecf20Sopenharmony_ci	if (!urb) {
15198c2ecf20Sopenharmony_ci		retval = -ENOMEM;
15208c2ecf20Sopenharmony_ci		up(&file_data->limit_write_sem);
15218c2ecf20Sopenharmony_ci		goto exit;
15228c2ecf20Sopenharmony_ci	}
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	buffer = urb->transfer_buffer;
15258c2ecf20Sopenharmony_ci	buflen = urb->transfer_buffer_length;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	if (count > INT_MAX) {
15288c2ecf20Sopenharmony_ci		transfersize = INT_MAX;
15298c2ecf20Sopenharmony_ci		buffer[8] = 0;
15308c2ecf20Sopenharmony_ci	} else {
15318c2ecf20Sopenharmony_ci		transfersize = count;
15328c2ecf20Sopenharmony_ci		buffer[8] = file_data->eom_val;
15338c2ecf20Sopenharmony_ci	}
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	/* Setup IO buffer for DEV_DEP_MSG_OUT message */
15368c2ecf20Sopenharmony_ci	buffer[0] = 1;
15378c2ecf20Sopenharmony_ci	buffer[1] = data->bTag;
15388c2ecf20Sopenharmony_ci	buffer[2] = ~data->bTag;
15398c2ecf20Sopenharmony_ci	buffer[3] = 0; /* Reserved */
15408c2ecf20Sopenharmony_ci	buffer[4] = transfersize >> 0;
15418c2ecf20Sopenharmony_ci	buffer[5] = transfersize >> 8;
15428c2ecf20Sopenharmony_ci	buffer[6] = transfersize >> 16;
15438c2ecf20Sopenharmony_ci	buffer[7] = transfersize >> 24;
15448c2ecf20Sopenharmony_ci	/* buffer[8] is set above... */
15458c2ecf20Sopenharmony_ci	buffer[9] = 0; /* Reserved */
15468c2ecf20Sopenharmony_ci	buffer[10] = 0; /* Reserved */
15478c2ecf20Sopenharmony_ci	buffer[11] = 0; /* Reserved */
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	remaining = transfersize;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	if (transfersize + USBTMC_HEADER_SIZE > buflen) {
15528c2ecf20Sopenharmony_ci		transfersize = buflen - USBTMC_HEADER_SIZE;
15538c2ecf20Sopenharmony_ci		aligned = buflen;
15548c2ecf20Sopenharmony_ci	} else {
15558c2ecf20Sopenharmony_ci		aligned = (transfersize + (USBTMC_HEADER_SIZE + 3)) & ~3;
15568c2ecf20Sopenharmony_ci	}
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf, transfersize)) {
15598c2ecf20Sopenharmony_ci		retval = -EFAULT;
15608c2ecf20Sopenharmony_ci		up(&file_data->limit_write_sem);
15618c2ecf20Sopenharmony_ci		goto exit;
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	dev_dbg(&data->intf->dev, "%s(size:%u align:%u)\n", __func__,
15658c2ecf20Sopenharmony_ci		(unsigned int)transfersize, (unsigned int)aligned);
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
15688c2ecf20Sopenharmony_ci			     16, 1, buffer, aligned, true);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	usb_fill_bulk_urb(urb, data->usb_dev,
15718c2ecf20Sopenharmony_ci		usb_sndbulkpipe(data->usb_dev, data->bulk_out),
15728c2ecf20Sopenharmony_ci		urb->transfer_buffer, aligned,
15738c2ecf20Sopenharmony_ci		usbtmc_write_bulk_cb, file_data);
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	usb_anchor_urb(urb, &file_data->submitted);
15768c2ecf20Sopenharmony_ci	retval = usb_submit_urb(urb, GFP_KERNEL);
15778c2ecf20Sopenharmony_ci	if (unlikely(retval)) {
15788c2ecf20Sopenharmony_ci		usb_unanchor_urb(urb);
15798c2ecf20Sopenharmony_ci		up(&file_data->limit_write_sem);
15808c2ecf20Sopenharmony_ci		goto exit;
15818c2ecf20Sopenharmony_ci	}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	remaining -= transfersize;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	data->bTag_last_write = data->bTag;
15868c2ecf20Sopenharmony_ci	data->bTag++;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	if (!data->bTag)
15898c2ecf20Sopenharmony_ci		data->bTag++;
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	/* call generic_write even when remaining = 0 */
15928c2ecf20Sopenharmony_ci	retval = usbtmc_generic_write(file_data, buf + transfersize, remaining,
15938c2ecf20Sopenharmony_ci				      &done, USBTMC_FLAG_APPEND);
15948c2ecf20Sopenharmony_ci	/* truncate alignment bytes */
15958c2ecf20Sopenharmony_ci	if (done > remaining)
15968c2ecf20Sopenharmony_ci		done = remaining;
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	/*add size of first urb*/
15998c2ecf20Sopenharmony_ci	done += transfersize;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	if (retval < 0) {
16028c2ecf20Sopenharmony_ci		usb_kill_anchored_urbs(&file_data->submitted);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci		dev_err(&data->intf->dev,
16058c2ecf20Sopenharmony_ci			"Unable to send data, error %d\n", (int)retval);
16068c2ecf20Sopenharmony_ci		if (file_data->auto_abort)
16078c2ecf20Sopenharmony_ci			usbtmc_ioctl_abort_bulk_out(data);
16088c2ecf20Sopenharmony_ci		goto exit;
16098c2ecf20Sopenharmony_ci	}
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	retval = done;
16128c2ecf20Sopenharmony_ciexit:
16138c2ecf20Sopenharmony_ci	usb_free_urb(urb);
16148c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
16158c2ecf20Sopenharmony_ci	return retval;
16168c2ecf20Sopenharmony_ci}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
16198c2ecf20Sopenharmony_ci{
16208c2ecf20Sopenharmony_ci	struct device *dev;
16218c2ecf20Sopenharmony_ci	u8 *buffer;
16228c2ecf20Sopenharmony_ci	int rv;
16238c2ecf20Sopenharmony_ci	int n;
16248c2ecf20Sopenharmony_ci	int actual = 0;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	dev = &data->intf->dev;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	dev_dbg(dev, "Sending INITIATE_CLEAR request\n");
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
16318c2ecf20Sopenharmony_ci	if (!buffer)
16328c2ecf20Sopenharmony_ci		return -ENOMEM;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
16358c2ecf20Sopenharmony_ci			     usb_rcvctrlpipe(data->usb_dev, 0),
16368c2ecf20Sopenharmony_ci			     USBTMC_REQUEST_INITIATE_CLEAR,
16378c2ecf20Sopenharmony_ci			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
16388c2ecf20Sopenharmony_ci			     0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT);
16398c2ecf20Sopenharmony_ci	if (rv < 0) {
16408c2ecf20Sopenharmony_ci		dev_err(dev, "usb_control_msg returned %d\n", rv);
16418c2ecf20Sopenharmony_ci		goto exit;
16428c2ecf20Sopenharmony_ci	}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	dev_dbg(dev, "INITIATE_CLEAR returned %x\n", buffer[0]);
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
16478c2ecf20Sopenharmony_ci		dev_err(dev, "INITIATE_CLEAR returned %x\n", buffer[0]);
16488c2ecf20Sopenharmony_ci		rv = -EPERM;
16498c2ecf20Sopenharmony_ci		goto exit;
16508c2ecf20Sopenharmony_ci	}
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	n = 0;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ciusbtmc_clear_check_status:
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	dev_dbg(dev, "Sending CHECK_CLEAR_STATUS request\n");
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
16598c2ecf20Sopenharmony_ci			     usb_rcvctrlpipe(data->usb_dev, 0),
16608c2ecf20Sopenharmony_ci			     USBTMC_REQUEST_CHECK_CLEAR_STATUS,
16618c2ecf20Sopenharmony_ci			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
16628c2ecf20Sopenharmony_ci			     0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT);
16638c2ecf20Sopenharmony_ci	if (rv < 0) {
16648c2ecf20Sopenharmony_ci		dev_err(dev, "usb_control_msg returned %d\n", rv);
16658c2ecf20Sopenharmony_ci		goto exit;
16668c2ecf20Sopenharmony_ci	}
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	dev_dbg(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]);
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	if (buffer[0] == USBTMC_STATUS_SUCCESS)
16718c2ecf20Sopenharmony_ci		goto usbtmc_clear_bulk_out_halt;
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	if (buffer[0] != USBTMC_STATUS_PENDING) {
16748c2ecf20Sopenharmony_ci		dev_err(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]);
16758c2ecf20Sopenharmony_ci		rv = -EPERM;
16768c2ecf20Sopenharmony_ci		goto exit;
16778c2ecf20Sopenharmony_ci	}
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	if ((buffer[1] & 1) != 0) {
16808c2ecf20Sopenharmony_ci		do {
16818c2ecf20Sopenharmony_ci			dev_dbg(dev, "Reading from bulk in EP\n");
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci			actual = 0;
16848c2ecf20Sopenharmony_ci			rv = usb_bulk_msg(data->usb_dev,
16858c2ecf20Sopenharmony_ci					  usb_rcvbulkpipe(data->usb_dev,
16868c2ecf20Sopenharmony_ci							  data->bulk_in),
16878c2ecf20Sopenharmony_ci					  buffer, USBTMC_BUFSIZE,
16888c2ecf20Sopenharmony_ci					  &actual, USB_CTRL_GET_TIMEOUT);
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci			print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
16918c2ecf20Sopenharmony_ci					     16, 1, buffer, actual, true);
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci			n++;
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci			if (rv < 0) {
16968c2ecf20Sopenharmony_ci				dev_err(dev, "usb_control_msg returned %d\n",
16978c2ecf20Sopenharmony_ci					rv);
16988c2ecf20Sopenharmony_ci				goto exit;
16998c2ecf20Sopenharmony_ci			}
17008c2ecf20Sopenharmony_ci		} while ((actual == USBTMC_BUFSIZE) &&
17018c2ecf20Sopenharmony_ci			  (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
17028c2ecf20Sopenharmony_ci	} else {
17038c2ecf20Sopenharmony_ci		/* do not stress device with subsequent requests */
17048c2ecf20Sopenharmony_ci		msleep(50);
17058c2ecf20Sopenharmony_ci		n++;
17068c2ecf20Sopenharmony_ci	}
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) {
17098c2ecf20Sopenharmony_ci		dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
17108c2ecf20Sopenharmony_ci			USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
17118c2ecf20Sopenharmony_ci		rv = -EPERM;
17128c2ecf20Sopenharmony_ci		goto exit;
17138c2ecf20Sopenharmony_ci	}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	goto usbtmc_clear_check_status;
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ciusbtmc_clear_bulk_out_halt:
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	rv = usb_clear_halt(data->usb_dev,
17208c2ecf20Sopenharmony_ci			    usb_sndbulkpipe(data->usb_dev, data->bulk_out));
17218c2ecf20Sopenharmony_ci	if (rv < 0) {
17228c2ecf20Sopenharmony_ci		dev_err(dev, "usb_clear_halt returned %d\n", rv);
17238c2ecf20Sopenharmony_ci		goto exit;
17248c2ecf20Sopenharmony_ci	}
17258c2ecf20Sopenharmony_ci	rv = 0;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ciexit:
17288c2ecf20Sopenharmony_ci	kfree(buffer);
17298c2ecf20Sopenharmony_ci	return rv;
17308c2ecf20Sopenharmony_ci}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
17338c2ecf20Sopenharmony_ci{
17348c2ecf20Sopenharmony_ci	int rv;
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	rv = usb_clear_halt(data->usb_dev,
17378c2ecf20Sopenharmony_ci			    usb_sndbulkpipe(data->usb_dev, data->bulk_out));
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	if (rv < 0)
17408c2ecf20Sopenharmony_ci		dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
17418c2ecf20Sopenharmony_ci	return rv;
17428c2ecf20Sopenharmony_ci}
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
17458c2ecf20Sopenharmony_ci{
17468c2ecf20Sopenharmony_ci	int rv;
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	rv = usb_clear_halt(data->usb_dev,
17498c2ecf20Sopenharmony_ci			    usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	if (rv < 0)
17528c2ecf20Sopenharmony_ci		dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
17538c2ecf20Sopenharmony_ci	return rv;
17548c2ecf20Sopenharmony_ci}
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data)
17578c2ecf20Sopenharmony_ci{
17588c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->err_lock);
17598c2ecf20Sopenharmony_ci	file_data->in_status = -ECANCELED;
17608c2ecf20Sopenharmony_ci	file_data->out_status = -ECANCELED;
17618c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->err_lock);
17628c2ecf20Sopenharmony_ci	usb_kill_anchored_urbs(&file_data->submitted);
17638c2ecf20Sopenharmony_ci	return 0;
17648c2ecf20Sopenharmony_ci}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data)
17678c2ecf20Sopenharmony_ci{
17688c2ecf20Sopenharmony_ci	usb_kill_anchored_urbs(&file_data->submitted);
17698c2ecf20Sopenharmony_ci	usb_scuttle_anchored_urbs(&file_data->in_anchor);
17708c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->err_lock);
17718c2ecf20Sopenharmony_ci	file_data->in_status = 0;
17728c2ecf20Sopenharmony_ci	file_data->in_transfer_size = 0;
17738c2ecf20Sopenharmony_ci	file_data->out_status = 0;
17748c2ecf20Sopenharmony_ci	file_data->out_transfer_size = 0;
17758c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->err_lock);
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	file_data->in_urbs_used = 0;
17788c2ecf20Sopenharmony_ci	return 0;
17798c2ecf20Sopenharmony_ci}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_cistatic int get_capabilities(struct usbtmc_device_data *data)
17828c2ecf20Sopenharmony_ci{
17838c2ecf20Sopenharmony_ci	struct device *dev = &data->usb_dev->dev;
17848c2ecf20Sopenharmony_ci	char *buffer;
17858c2ecf20Sopenharmony_ci	int rv = 0;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	buffer = kmalloc(0x18, GFP_KERNEL);
17888c2ecf20Sopenharmony_ci	if (!buffer)
17898c2ecf20Sopenharmony_ci		return -ENOMEM;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0),
17928c2ecf20Sopenharmony_ci			     USBTMC_REQUEST_GET_CAPABILITIES,
17938c2ecf20Sopenharmony_ci			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
17948c2ecf20Sopenharmony_ci			     0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT);
17958c2ecf20Sopenharmony_ci	if (rv < 0) {
17968c2ecf20Sopenharmony_ci		dev_err(dev, "usb_control_msg returned %d\n", rv);
17978c2ecf20Sopenharmony_ci		goto err_out;
17988c2ecf20Sopenharmony_ci	}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
18018c2ecf20Sopenharmony_ci	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
18028c2ecf20Sopenharmony_ci		dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
18038c2ecf20Sopenharmony_ci		rv = -EPERM;
18048c2ecf20Sopenharmony_ci		goto err_out;
18058c2ecf20Sopenharmony_ci	}
18068c2ecf20Sopenharmony_ci	dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]);
18078c2ecf20Sopenharmony_ci	dev_dbg(dev, "Device capabilities are %x\n", buffer[5]);
18088c2ecf20Sopenharmony_ci	dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]);
18098c2ecf20Sopenharmony_ci	dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	data->capabilities.interface_capabilities = buffer[4];
18128c2ecf20Sopenharmony_ci	data->capabilities.device_capabilities = buffer[5];
18138c2ecf20Sopenharmony_ci	data->capabilities.usb488_interface_capabilities = buffer[14];
18148c2ecf20Sopenharmony_ci	data->capabilities.usb488_device_capabilities = buffer[15];
18158c2ecf20Sopenharmony_ci	data->usb488_caps = (buffer[14] & 0x07) | ((buffer[15] & 0x0f) << 4);
18168c2ecf20Sopenharmony_ci	rv = 0;
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_cierr_out:
18198c2ecf20Sopenharmony_ci	kfree(buffer);
18208c2ecf20Sopenharmony_ci	return rv;
18218c2ecf20Sopenharmony_ci}
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci#define capability_attribute(name)					\
18248c2ecf20Sopenharmony_cistatic ssize_t name##_show(struct device *dev,				\
18258c2ecf20Sopenharmony_ci			   struct device_attribute *attr, char *buf)	\
18268c2ecf20Sopenharmony_ci{									\
18278c2ecf20Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(dev);		\
18288c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = usb_get_intfdata(intf);	\
18298c2ecf20Sopenharmony_ci									\
18308c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", data->capabilities.name);		\
18318c2ecf20Sopenharmony_ci}									\
18328c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name)
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_cicapability_attribute(interface_capabilities);
18358c2ecf20Sopenharmony_cicapability_attribute(device_capabilities);
18368c2ecf20Sopenharmony_cicapability_attribute(usb488_interface_capabilities);
18378c2ecf20Sopenharmony_cicapability_attribute(usb488_device_capabilities);
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_cistatic struct attribute *usbtmc_attrs[] = {
18408c2ecf20Sopenharmony_ci	&dev_attr_interface_capabilities.attr,
18418c2ecf20Sopenharmony_ci	&dev_attr_device_capabilities.attr,
18428c2ecf20Sopenharmony_ci	&dev_attr_usb488_interface_capabilities.attr,
18438c2ecf20Sopenharmony_ci	&dev_attr_usb488_device_capabilities.attr,
18448c2ecf20Sopenharmony_ci	NULL,
18458c2ecf20Sopenharmony_ci};
18468c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(usbtmc);
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
18498c2ecf20Sopenharmony_ci{
18508c2ecf20Sopenharmony_ci	struct device *dev;
18518c2ecf20Sopenharmony_ci	u8 *buffer;
18528c2ecf20Sopenharmony_ci	int rv;
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	dev = &data->intf->dev;
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	buffer = kmalloc(2, GFP_KERNEL);
18578c2ecf20Sopenharmony_ci	if (!buffer)
18588c2ecf20Sopenharmony_ci		return -ENOMEM;
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
18618c2ecf20Sopenharmony_ci			     usb_rcvctrlpipe(data->usb_dev, 0),
18628c2ecf20Sopenharmony_ci			     USBTMC_REQUEST_INDICATOR_PULSE,
18638c2ecf20Sopenharmony_ci			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
18648c2ecf20Sopenharmony_ci			     0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	if (rv < 0) {
18678c2ecf20Sopenharmony_ci		dev_err(dev, "usb_control_msg returned %d\n", rv);
18688c2ecf20Sopenharmony_ci		goto exit;
18698c2ecf20Sopenharmony_ci	}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	dev_dbg(dev, "INDICATOR_PULSE returned %x\n", buffer[0]);
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
18748c2ecf20Sopenharmony_ci		dev_err(dev, "INDICATOR_PULSE returned %x\n", buffer[0]);
18758c2ecf20Sopenharmony_ci		rv = -EPERM;
18768c2ecf20Sopenharmony_ci		goto exit;
18778c2ecf20Sopenharmony_ci	}
18788c2ecf20Sopenharmony_ci	rv = 0;
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ciexit:
18818c2ecf20Sopenharmony_ci	kfree(buffer);
18828c2ecf20Sopenharmony_ci	return rv;
18838c2ecf20Sopenharmony_ci}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_request(struct usbtmc_device_data *data,
18868c2ecf20Sopenharmony_ci				void __user *arg)
18878c2ecf20Sopenharmony_ci{
18888c2ecf20Sopenharmony_ci	struct device *dev = &data->intf->dev;
18898c2ecf20Sopenharmony_ci	struct usbtmc_ctrlrequest request;
18908c2ecf20Sopenharmony_ci	u8 *buffer = NULL;
18918c2ecf20Sopenharmony_ci	int rv;
18928c2ecf20Sopenharmony_ci	unsigned int is_in, pipe;
18938c2ecf20Sopenharmony_ci	unsigned long res;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest));
18968c2ecf20Sopenharmony_ci	if (res)
18978c2ecf20Sopenharmony_ci		return -EFAULT;
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	if (request.req.wLength > USBTMC_BUFSIZE)
19008c2ecf20Sopenharmony_ci		return -EMSGSIZE;
19018c2ecf20Sopenharmony_ci	if (request.req.wLength == 0)	/* Length-0 requests are never IN */
19028c2ecf20Sopenharmony_ci		request.req.bRequestType &= ~USB_DIR_IN;
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci	is_in = request.req.bRequestType & USB_DIR_IN;
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	if (request.req.wLength) {
19078c2ecf20Sopenharmony_ci		buffer = kmalloc(request.req.wLength, GFP_KERNEL);
19088c2ecf20Sopenharmony_ci		if (!buffer)
19098c2ecf20Sopenharmony_ci			return -ENOMEM;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci		if (!is_in) {
19128c2ecf20Sopenharmony_ci			/* Send control data to device */
19138c2ecf20Sopenharmony_ci			res = copy_from_user(buffer, request.data,
19148c2ecf20Sopenharmony_ci					     request.req.wLength);
19158c2ecf20Sopenharmony_ci			if (res) {
19168c2ecf20Sopenharmony_ci				rv = -EFAULT;
19178c2ecf20Sopenharmony_ci				goto exit;
19188c2ecf20Sopenharmony_ci			}
19198c2ecf20Sopenharmony_ci		}
19208c2ecf20Sopenharmony_ci	}
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	if (is_in)
19238c2ecf20Sopenharmony_ci		pipe = usb_rcvctrlpipe(data->usb_dev, 0);
19248c2ecf20Sopenharmony_ci	else
19258c2ecf20Sopenharmony_ci		pipe = usb_sndctrlpipe(data->usb_dev, 0);
19268c2ecf20Sopenharmony_ci	rv = usb_control_msg(data->usb_dev,
19278c2ecf20Sopenharmony_ci			pipe,
19288c2ecf20Sopenharmony_ci			request.req.bRequest,
19298c2ecf20Sopenharmony_ci			request.req.bRequestType,
19308c2ecf20Sopenharmony_ci			request.req.wValue,
19318c2ecf20Sopenharmony_ci			request.req.wIndex,
19328c2ecf20Sopenharmony_ci			buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	if (rv < 0) {
19358c2ecf20Sopenharmony_ci		dev_err(dev, "%s failed %d\n", __func__, rv);
19368c2ecf20Sopenharmony_ci		goto exit;
19378c2ecf20Sopenharmony_ci	}
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	if (rv && is_in) {
19408c2ecf20Sopenharmony_ci		/* Read control data from device */
19418c2ecf20Sopenharmony_ci		res = copy_to_user(request.data, buffer, rv);
19428c2ecf20Sopenharmony_ci		if (res)
19438c2ecf20Sopenharmony_ci			rv = -EFAULT;
19448c2ecf20Sopenharmony_ci	}
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci exit:
19478c2ecf20Sopenharmony_ci	kfree(buffer);
19488c2ecf20Sopenharmony_ci	return rv;
19498c2ecf20Sopenharmony_ci}
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci/*
19528c2ecf20Sopenharmony_ci * Get the usb timeout value
19538c2ecf20Sopenharmony_ci */
19548c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_get_timeout(struct usbtmc_file_data *file_data,
19558c2ecf20Sopenharmony_ci				void __user *arg)
19568c2ecf20Sopenharmony_ci{
19578c2ecf20Sopenharmony_ci	u32 timeout;
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	timeout = file_data->timeout;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	return put_user(timeout, (__u32 __user *)arg);
19628c2ecf20Sopenharmony_ci}
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci/*
19658c2ecf20Sopenharmony_ci * Set the usb timeout value
19668c2ecf20Sopenharmony_ci */
19678c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_set_timeout(struct usbtmc_file_data *file_data,
19688c2ecf20Sopenharmony_ci				void __user *arg)
19698c2ecf20Sopenharmony_ci{
19708c2ecf20Sopenharmony_ci	u32 timeout;
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	if (get_user(timeout, (__u32 __user *)arg))
19738c2ecf20Sopenharmony_ci		return -EFAULT;
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	/* Note that timeout = 0 means
19768c2ecf20Sopenharmony_ci	 * MAX_SCHEDULE_TIMEOUT in usb_control_msg
19778c2ecf20Sopenharmony_ci	 */
19788c2ecf20Sopenharmony_ci	if (timeout < USBTMC_MIN_TIMEOUT)
19798c2ecf20Sopenharmony_ci		return -EINVAL;
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	file_data->timeout = timeout;
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	return 0;
19848c2ecf20Sopenharmony_ci}
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci/*
19878c2ecf20Sopenharmony_ci * enables/disables sending EOM on write
19888c2ecf20Sopenharmony_ci */
19898c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_eom_enable(struct usbtmc_file_data *file_data,
19908c2ecf20Sopenharmony_ci				void __user *arg)
19918c2ecf20Sopenharmony_ci{
19928c2ecf20Sopenharmony_ci	u8 eom_enable;
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	if (copy_from_user(&eom_enable, arg, sizeof(eom_enable)))
19958c2ecf20Sopenharmony_ci		return -EFAULT;
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	if (eom_enable > 1)
19988c2ecf20Sopenharmony_ci		return -EINVAL;
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	file_data->eom_val = eom_enable;
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci	return 0;
20038c2ecf20Sopenharmony_ci}
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci/*
20068c2ecf20Sopenharmony_ci * Configure termination character for read()
20078c2ecf20Sopenharmony_ci */
20088c2ecf20Sopenharmony_cistatic int usbtmc_ioctl_config_termc(struct usbtmc_file_data *file_data,
20098c2ecf20Sopenharmony_ci				void __user *arg)
20108c2ecf20Sopenharmony_ci{
20118c2ecf20Sopenharmony_ci	struct usbtmc_termchar termc;
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	if (copy_from_user(&termc, arg, sizeof(termc)))
20148c2ecf20Sopenharmony_ci		return -EFAULT;
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	if ((termc.term_char_enabled > 1) ||
20178c2ecf20Sopenharmony_ci		(termc.term_char_enabled &&
20188c2ecf20Sopenharmony_ci		!(file_data->data->capabilities.device_capabilities & 1)))
20198c2ecf20Sopenharmony_ci		return -EINVAL;
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	file_data->term_char = termc.term_char;
20228c2ecf20Sopenharmony_ci	file_data->term_char_enabled = termc.term_char_enabled;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	return 0;
20258c2ecf20Sopenharmony_ci}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_cistatic long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
20288c2ecf20Sopenharmony_ci{
20298c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data;
20308c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data;
20318c2ecf20Sopenharmony_ci	int retval = -EBADRQC;
20328c2ecf20Sopenharmony_ci	__u8 tmp_byte;
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci	file_data = file->private_data;
20358c2ecf20Sopenharmony_ci	data = file_data->data;
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
20388c2ecf20Sopenharmony_ci	if (data->zombie) {
20398c2ecf20Sopenharmony_ci		retval = -ENODEV;
20408c2ecf20Sopenharmony_ci		goto skip_io_on_zombie;
20418c2ecf20Sopenharmony_ci	}
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	switch (cmd) {
20448c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_CLEAR_OUT_HALT:
20458c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_clear_out_halt(data);
20468c2ecf20Sopenharmony_ci		break;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_CLEAR_IN_HALT:
20498c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_clear_in_halt(data);
20508c2ecf20Sopenharmony_ci		break;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_INDICATOR_PULSE:
20538c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_indicator_pulse(data);
20548c2ecf20Sopenharmony_ci		break;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_CLEAR:
20578c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_clear(data);
20588c2ecf20Sopenharmony_ci		break;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_ABORT_BULK_OUT:
20618c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_abort_bulk_out(data);
20628c2ecf20Sopenharmony_ci		break;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_ABORT_BULK_IN:
20658c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_abort_bulk_in(data);
20668c2ecf20Sopenharmony_ci		break;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_CTRL_REQUEST:
20698c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_request(data, (void __user *)arg);
20708c2ecf20Sopenharmony_ci		break;
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_GET_TIMEOUT:
20738c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_get_timeout(file_data,
20748c2ecf20Sopenharmony_ci						  (void __user *)arg);
20758c2ecf20Sopenharmony_ci		break;
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_SET_TIMEOUT:
20788c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_set_timeout(file_data,
20798c2ecf20Sopenharmony_ci						  (void __user *)arg);
20808c2ecf20Sopenharmony_ci		break;
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_EOM_ENABLE:
20838c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_eom_enable(file_data,
20848c2ecf20Sopenharmony_ci						 (void __user *)arg);
20858c2ecf20Sopenharmony_ci		break;
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_CONFIG_TERMCHAR:
20888c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_config_termc(file_data,
20898c2ecf20Sopenharmony_ci						   (void __user *)arg);
20908c2ecf20Sopenharmony_ci		break;
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_WRITE:
20938c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_generic_write(file_data,
20948c2ecf20Sopenharmony_ci						    (void __user *)arg);
20958c2ecf20Sopenharmony_ci		break;
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_READ:
20988c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_generic_read(file_data,
20998c2ecf20Sopenharmony_ci						   (void __user *)arg);
21008c2ecf20Sopenharmony_ci		break;
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_WRITE_RESULT:
21038c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_write_result(file_data,
21048c2ecf20Sopenharmony_ci						   (void __user *)arg);
21058c2ecf20Sopenharmony_ci		break;
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_API_VERSION:
21088c2ecf20Sopenharmony_ci		retval = put_user(USBTMC_API_VERSION,
21098c2ecf20Sopenharmony_ci				  (__u32 __user *)arg);
21108c2ecf20Sopenharmony_ci		break;
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	case USBTMC488_IOCTL_GET_CAPS:
21138c2ecf20Sopenharmony_ci		retval = put_user(data->usb488_caps,
21148c2ecf20Sopenharmony_ci				  (unsigned char __user *)arg);
21158c2ecf20Sopenharmony_ci		break;
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	case USBTMC488_IOCTL_READ_STB:
21188c2ecf20Sopenharmony_ci		retval = usbtmc488_ioctl_read_stb(file_data,
21198c2ecf20Sopenharmony_ci						  (void __user *)arg);
21208c2ecf20Sopenharmony_ci		break;
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	case USBTMC488_IOCTL_REN_CONTROL:
21238c2ecf20Sopenharmony_ci		retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
21248c2ecf20Sopenharmony_ci						USBTMC488_REQUEST_REN_CONTROL);
21258c2ecf20Sopenharmony_ci		break;
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	case USBTMC488_IOCTL_GOTO_LOCAL:
21288c2ecf20Sopenharmony_ci		retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
21298c2ecf20Sopenharmony_ci						USBTMC488_REQUEST_GOTO_LOCAL);
21308c2ecf20Sopenharmony_ci		break;
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci	case USBTMC488_IOCTL_LOCAL_LOCKOUT:
21338c2ecf20Sopenharmony_ci		retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
21348c2ecf20Sopenharmony_ci						USBTMC488_REQUEST_LOCAL_LOCKOUT);
21358c2ecf20Sopenharmony_ci		break;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	case USBTMC488_IOCTL_TRIGGER:
21388c2ecf20Sopenharmony_ci		retval = usbtmc488_ioctl_trigger(file_data);
21398c2ecf20Sopenharmony_ci		break;
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci	case USBTMC488_IOCTL_WAIT_SRQ:
21428c2ecf20Sopenharmony_ci		retval = usbtmc488_ioctl_wait_srq(file_data,
21438c2ecf20Sopenharmony_ci						  (__u32 __user *)arg);
21448c2ecf20Sopenharmony_ci		break;
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_MSG_IN_ATTR:
21478c2ecf20Sopenharmony_ci		retval = put_user(file_data->bmTransferAttributes,
21488c2ecf20Sopenharmony_ci				  (__u8 __user *)arg);
21498c2ecf20Sopenharmony_ci		break;
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_AUTO_ABORT:
21528c2ecf20Sopenharmony_ci		retval = get_user(tmp_byte, (unsigned char __user *)arg);
21538c2ecf20Sopenharmony_ci		if (retval == 0)
21548c2ecf20Sopenharmony_ci			file_data->auto_abort = !!tmp_byte;
21558c2ecf20Sopenharmony_ci		break;
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_CANCEL_IO:
21588c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_cancel_io(file_data);
21598c2ecf20Sopenharmony_ci		break;
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	case USBTMC_IOCTL_CLEANUP_IO:
21628c2ecf20Sopenharmony_ci		retval = usbtmc_ioctl_cleanup_io(file_data);
21638c2ecf20Sopenharmony_ci		break;
21648c2ecf20Sopenharmony_ci	}
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ciskip_io_on_zombie:
21678c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
21688c2ecf20Sopenharmony_ci	return retval;
21698c2ecf20Sopenharmony_ci}
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_cistatic int usbtmc_fasync(int fd, struct file *file, int on)
21728c2ecf20Sopenharmony_ci{
21738c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data = file->private_data;
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	return fasync_helper(fd, file, on, &file_data->data->fasync);
21768c2ecf20Sopenharmony_ci}
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_cistatic __poll_t usbtmc_poll(struct file *file, poll_table *wait)
21798c2ecf20Sopenharmony_ci{
21808c2ecf20Sopenharmony_ci	struct usbtmc_file_data *file_data = file->private_data;
21818c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = file_data->data;
21828c2ecf20Sopenharmony_ci	__poll_t mask;
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	if (data->zombie) {
21878c2ecf20Sopenharmony_ci		mask = EPOLLHUP | EPOLLERR;
21888c2ecf20Sopenharmony_ci		goto no_poll;
21898c2ecf20Sopenharmony_ci	}
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	poll_wait(file, &data->waitq, wait);
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	/* Note that EPOLLPRI is now assigned to SRQ, and
21948c2ecf20Sopenharmony_ci	 * EPOLLIN|EPOLLRDNORM to normal read data.
21958c2ecf20Sopenharmony_ci	 */
21968c2ecf20Sopenharmony_ci	mask = 0;
21978c2ecf20Sopenharmony_ci	if (atomic_read(&file_data->srq_asserted))
21988c2ecf20Sopenharmony_ci		mask |= EPOLLPRI;
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	/* Note that the anchor submitted includes all urbs for BULK IN
22018c2ecf20Sopenharmony_ci	 * and OUT. So EPOLLOUT is signaled when BULK OUT is empty and
22028c2ecf20Sopenharmony_ci	 * all BULK IN urbs are completed and moved to in_anchor.
22038c2ecf20Sopenharmony_ci	 */
22048c2ecf20Sopenharmony_ci	if (usb_anchor_empty(&file_data->submitted))
22058c2ecf20Sopenharmony_ci		mask |= (EPOLLOUT | EPOLLWRNORM);
22068c2ecf20Sopenharmony_ci	if (!usb_anchor_empty(&file_data->in_anchor))
22078c2ecf20Sopenharmony_ci		mask |= (EPOLLIN | EPOLLRDNORM);
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	spin_lock_irq(&file_data->err_lock);
22108c2ecf20Sopenharmony_ci	if (file_data->in_status || file_data->out_status)
22118c2ecf20Sopenharmony_ci		mask |= EPOLLERR;
22128c2ecf20Sopenharmony_ci	spin_unlock_irq(&file_data->err_lock);
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	dev_dbg(&data->intf->dev, "poll mask = %x\n", mask);
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_cino_poll:
22178c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
22188c2ecf20Sopenharmony_ci	return mask;
22198c2ecf20Sopenharmony_ci}
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_cistatic const struct file_operations fops = {
22228c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
22238c2ecf20Sopenharmony_ci	.read		= usbtmc_read,
22248c2ecf20Sopenharmony_ci	.write		= usbtmc_write,
22258c2ecf20Sopenharmony_ci	.open		= usbtmc_open,
22268c2ecf20Sopenharmony_ci	.release	= usbtmc_release,
22278c2ecf20Sopenharmony_ci	.flush		= usbtmc_flush,
22288c2ecf20Sopenharmony_ci	.unlocked_ioctl	= usbtmc_ioctl,
22298c2ecf20Sopenharmony_ci	.compat_ioctl	= compat_ptr_ioctl,
22308c2ecf20Sopenharmony_ci	.fasync         = usbtmc_fasync,
22318c2ecf20Sopenharmony_ci	.poll           = usbtmc_poll,
22328c2ecf20Sopenharmony_ci	.llseek		= default_llseek,
22338c2ecf20Sopenharmony_ci};
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_cistatic struct usb_class_driver usbtmc_class = {
22368c2ecf20Sopenharmony_ci	.name =		"usbtmc%d",
22378c2ecf20Sopenharmony_ci	.fops =		&fops,
22388c2ecf20Sopenharmony_ci	.minor_base =	USBTMC_MINOR_BASE,
22398c2ecf20Sopenharmony_ci};
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_cistatic void usbtmc_interrupt(struct urb *urb)
22428c2ecf20Sopenharmony_ci{
22438c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = urb->context;
22448c2ecf20Sopenharmony_ci	struct device *dev = &data->intf->dev;
22458c2ecf20Sopenharmony_ci	int status = urb->status;
22468c2ecf20Sopenharmony_ci	int rv;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	dev_dbg(&data->intf->dev, "int status: %d len %d\n",
22498c2ecf20Sopenharmony_ci		status, urb->actual_length);
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	switch (status) {
22528c2ecf20Sopenharmony_ci	case 0: /* SUCCESS */
22538c2ecf20Sopenharmony_ci		/* check for valid STB notification */
22548c2ecf20Sopenharmony_ci		if (data->iin_buffer[0] > 0x81) {
22558c2ecf20Sopenharmony_ci			data->bNotify1 = data->iin_buffer[0];
22568c2ecf20Sopenharmony_ci			data->bNotify2 = data->iin_buffer[1];
22578c2ecf20Sopenharmony_ci			atomic_set(&data->iin_data_valid, 1);
22588c2ecf20Sopenharmony_ci			wake_up_interruptible(&data->waitq);
22598c2ecf20Sopenharmony_ci			goto exit;
22608c2ecf20Sopenharmony_ci		}
22618c2ecf20Sopenharmony_ci		/* check for SRQ notification */
22628c2ecf20Sopenharmony_ci		if (data->iin_buffer[0] == 0x81) {
22638c2ecf20Sopenharmony_ci			unsigned long flags;
22648c2ecf20Sopenharmony_ci			struct list_head *elem;
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci			if (data->fasync)
22678c2ecf20Sopenharmony_ci				kill_fasync(&data->fasync,
22688c2ecf20Sopenharmony_ci					SIGIO, POLL_PRI);
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci			spin_lock_irqsave(&data->dev_lock, flags);
22718c2ecf20Sopenharmony_ci			list_for_each(elem, &data->file_list) {
22728c2ecf20Sopenharmony_ci				struct usbtmc_file_data *file_data;
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci				file_data = list_entry(elem,
22758c2ecf20Sopenharmony_ci						       struct usbtmc_file_data,
22768c2ecf20Sopenharmony_ci						       file_elem);
22778c2ecf20Sopenharmony_ci				file_data->srq_byte = data->iin_buffer[1];
22788c2ecf20Sopenharmony_ci				atomic_set(&file_data->srq_asserted, 1);
22798c2ecf20Sopenharmony_ci			}
22808c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&data->dev_lock, flags);
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci			dev_dbg(dev, "srq received bTag %x stb %x\n",
22838c2ecf20Sopenharmony_ci				(unsigned int)data->iin_buffer[0],
22848c2ecf20Sopenharmony_ci				(unsigned int)data->iin_buffer[1]);
22858c2ecf20Sopenharmony_ci			wake_up_interruptible_all(&data->waitq);
22868c2ecf20Sopenharmony_ci			goto exit;
22878c2ecf20Sopenharmony_ci		}
22888c2ecf20Sopenharmony_ci		dev_warn(dev, "invalid notification: %x\n",
22898c2ecf20Sopenharmony_ci			 data->iin_buffer[0]);
22908c2ecf20Sopenharmony_ci		break;
22918c2ecf20Sopenharmony_ci	case -EOVERFLOW:
22928c2ecf20Sopenharmony_ci		dev_err(dev, "overflow with length %d, actual length is %d\n",
22938c2ecf20Sopenharmony_ci			data->iin_wMaxPacketSize, urb->actual_length);
22948c2ecf20Sopenharmony_ci		fallthrough;
22958c2ecf20Sopenharmony_ci	default:
22968c2ecf20Sopenharmony_ci		/* urb terminated, clean up */
22978c2ecf20Sopenharmony_ci		dev_dbg(dev, "urb terminated, status: %d\n", status);
22988c2ecf20Sopenharmony_ci		return;
22998c2ecf20Sopenharmony_ci	}
23008c2ecf20Sopenharmony_ciexit:
23018c2ecf20Sopenharmony_ci	rv = usb_submit_urb(urb, GFP_ATOMIC);
23028c2ecf20Sopenharmony_ci	if (rv)
23038c2ecf20Sopenharmony_ci		dev_err(dev, "usb_submit_urb failed: %d\n", rv);
23048c2ecf20Sopenharmony_ci}
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_cistatic void usbtmc_free_int(struct usbtmc_device_data *data)
23078c2ecf20Sopenharmony_ci{
23088c2ecf20Sopenharmony_ci	if (!data->iin_ep_present || !data->iin_urb)
23098c2ecf20Sopenharmony_ci		return;
23108c2ecf20Sopenharmony_ci	usb_kill_urb(data->iin_urb);
23118c2ecf20Sopenharmony_ci	kfree(data->iin_buffer);
23128c2ecf20Sopenharmony_ci	data->iin_buffer = NULL;
23138c2ecf20Sopenharmony_ci	usb_free_urb(data->iin_urb);
23148c2ecf20Sopenharmony_ci	data->iin_urb = NULL;
23158c2ecf20Sopenharmony_ci	kref_put(&data->kref, usbtmc_delete);
23168c2ecf20Sopenharmony_ci}
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_cistatic int usbtmc_probe(struct usb_interface *intf,
23198c2ecf20Sopenharmony_ci			const struct usb_device_id *id)
23208c2ecf20Sopenharmony_ci{
23218c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data;
23228c2ecf20Sopenharmony_ci	struct usb_host_interface *iface_desc;
23238c2ecf20Sopenharmony_ci	struct usb_endpoint_descriptor *bulk_in, *bulk_out, *int_in;
23248c2ecf20Sopenharmony_ci	int retcode;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	dev_dbg(&intf->dev, "%s called\n", __func__);
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	data = kzalloc(sizeof(*data), GFP_KERNEL);
23298c2ecf20Sopenharmony_ci	if (!data)
23308c2ecf20Sopenharmony_ci		return -ENOMEM;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	data->intf = intf;
23338c2ecf20Sopenharmony_ci	data->id = id;
23348c2ecf20Sopenharmony_ci	data->usb_dev = usb_get_dev(interface_to_usbdev(intf));
23358c2ecf20Sopenharmony_ci	usb_set_intfdata(intf, data);
23368c2ecf20Sopenharmony_ci	kref_init(&data->kref);
23378c2ecf20Sopenharmony_ci	mutex_init(&data->io_mutex);
23388c2ecf20Sopenharmony_ci	init_waitqueue_head(&data->waitq);
23398c2ecf20Sopenharmony_ci	atomic_set(&data->iin_data_valid, 0);
23408c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&data->file_list);
23418c2ecf20Sopenharmony_ci	spin_lock_init(&data->dev_lock);
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci	data->zombie = 0;
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	/* Initialize USBTMC bTag and other fields */
23468c2ecf20Sopenharmony_ci	data->bTag	= 1;
23478c2ecf20Sopenharmony_ci	/*  2 <= bTag <= 127   USBTMC-USB488 subclass specification 4.3.1 */
23488c2ecf20Sopenharmony_ci	data->iin_bTag = 2;
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_ci	/* USBTMC devices have only one setting, so use that */
23518c2ecf20Sopenharmony_ci	iface_desc = data->intf->cur_altsetting;
23528c2ecf20Sopenharmony_ci	data->ifnum = iface_desc->desc.bInterfaceNumber;
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	/* Find bulk endpoints */
23558c2ecf20Sopenharmony_ci	retcode = usb_find_common_endpoints(iface_desc,
23568c2ecf20Sopenharmony_ci			&bulk_in, &bulk_out, NULL, NULL);
23578c2ecf20Sopenharmony_ci	if (retcode) {
23588c2ecf20Sopenharmony_ci		dev_err(&intf->dev, "bulk endpoints not found\n");
23598c2ecf20Sopenharmony_ci		goto err_put;
23608c2ecf20Sopenharmony_ci	}
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_ci	retcode = -EINVAL;
23638c2ecf20Sopenharmony_ci	data->bulk_in = bulk_in->bEndpointAddress;
23648c2ecf20Sopenharmony_ci	data->wMaxPacketSize = usb_endpoint_maxp(bulk_in);
23658c2ecf20Sopenharmony_ci	if (!data->wMaxPacketSize)
23668c2ecf20Sopenharmony_ci		goto err_put;
23678c2ecf20Sopenharmony_ci	dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in);
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	data->bulk_out = bulk_out->bEndpointAddress;
23708c2ecf20Sopenharmony_ci	dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", data->bulk_out);
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	/* Find int endpoint */
23738c2ecf20Sopenharmony_ci	retcode = usb_find_int_in_endpoint(iface_desc, &int_in);
23748c2ecf20Sopenharmony_ci	if (!retcode) {
23758c2ecf20Sopenharmony_ci		data->iin_ep_present = 1;
23768c2ecf20Sopenharmony_ci		data->iin_ep = int_in->bEndpointAddress;
23778c2ecf20Sopenharmony_ci		data->iin_wMaxPacketSize = usb_endpoint_maxp(int_in);
23788c2ecf20Sopenharmony_ci		data->iin_interval = int_in->bInterval;
23798c2ecf20Sopenharmony_ci		dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
23808c2ecf20Sopenharmony_ci				data->iin_ep);
23818c2ecf20Sopenharmony_ci	}
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	retcode = get_capabilities(data);
23848c2ecf20Sopenharmony_ci	if (retcode)
23858c2ecf20Sopenharmony_ci		dev_err(&intf->dev, "can't read capabilities\n");
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci	if (data->iin_ep_present) {
23888c2ecf20Sopenharmony_ci		/* allocate int urb */
23898c2ecf20Sopenharmony_ci		data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
23908c2ecf20Sopenharmony_ci		if (!data->iin_urb) {
23918c2ecf20Sopenharmony_ci			retcode = -ENOMEM;
23928c2ecf20Sopenharmony_ci			goto error_register;
23938c2ecf20Sopenharmony_ci		}
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci		/* Protect interrupt in endpoint data until iin_urb is freed */
23968c2ecf20Sopenharmony_ci		kref_get(&data->kref);
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci		/* allocate buffer for interrupt in */
23998c2ecf20Sopenharmony_ci		data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
24008c2ecf20Sopenharmony_ci					GFP_KERNEL);
24018c2ecf20Sopenharmony_ci		if (!data->iin_buffer) {
24028c2ecf20Sopenharmony_ci			retcode = -ENOMEM;
24038c2ecf20Sopenharmony_ci			goto error_register;
24048c2ecf20Sopenharmony_ci		}
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci		/* fill interrupt urb */
24078c2ecf20Sopenharmony_ci		usb_fill_int_urb(data->iin_urb, data->usb_dev,
24088c2ecf20Sopenharmony_ci				usb_rcvintpipe(data->usb_dev, data->iin_ep),
24098c2ecf20Sopenharmony_ci				data->iin_buffer, data->iin_wMaxPacketSize,
24108c2ecf20Sopenharmony_ci				usbtmc_interrupt,
24118c2ecf20Sopenharmony_ci				data, data->iin_interval);
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci		retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
24148c2ecf20Sopenharmony_ci		if (retcode) {
24158c2ecf20Sopenharmony_ci			dev_err(&intf->dev, "Failed to submit iin_urb\n");
24168c2ecf20Sopenharmony_ci			goto error_register;
24178c2ecf20Sopenharmony_ci		}
24188c2ecf20Sopenharmony_ci	}
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	retcode = usb_register_dev(intf, &usbtmc_class);
24218c2ecf20Sopenharmony_ci	if (retcode) {
24228c2ecf20Sopenharmony_ci		dev_err(&intf->dev, "Not able to get a minor (base %u, slice default): %d\n",
24238c2ecf20Sopenharmony_ci			USBTMC_MINOR_BASE,
24248c2ecf20Sopenharmony_ci			retcode);
24258c2ecf20Sopenharmony_ci		goto error_register;
24268c2ecf20Sopenharmony_ci	}
24278c2ecf20Sopenharmony_ci	dev_dbg(&intf->dev, "Using minor number %d\n", intf->minor);
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	return 0;
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_cierror_register:
24328c2ecf20Sopenharmony_ci	usbtmc_free_int(data);
24338c2ecf20Sopenharmony_cierr_put:
24348c2ecf20Sopenharmony_ci	kref_put(&data->kref, usbtmc_delete);
24358c2ecf20Sopenharmony_ci	return retcode;
24368c2ecf20Sopenharmony_ci}
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_cistatic void usbtmc_disconnect(struct usb_interface *intf)
24398c2ecf20Sopenharmony_ci{
24408c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data  = usb_get_intfdata(intf);
24418c2ecf20Sopenharmony_ci	struct list_head *elem;
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	usb_deregister_dev(intf, &usbtmc_class);
24448c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
24458c2ecf20Sopenharmony_ci	data->zombie = 1;
24468c2ecf20Sopenharmony_ci	wake_up_interruptible_all(&data->waitq);
24478c2ecf20Sopenharmony_ci	list_for_each(elem, &data->file_list) {
24488c2ecf20Sopenharmony_ci		struct usbtmc_file_data *file_data;
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci		file_data = list_entry(elem,
24518c2ecf20Sopenharmony_ci				       struct usbtmc_file_data,
24528c2ecf20Sopenharmony_ci				       file_elem);
24538c2ecf20Sopenharmony_ci		usb_kill_anchored_urbs(&file_data->submitted);
24548c2ecf20Sopenharmony_ci		usb_scuttle_anchored_urbs(&file_data->in_anchor);
24558c2ecf20Sopenharmony_ci	}
24568c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
24578c2ecf20Sopenharmony_ci	usbtmc_free_int(data);
24588c2ecf20Sopenharmony_ci	kref_put(&data->kref, usbtmc_delete);
24598c2ecf20Sopenharmony_ci}
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_cistatic void usbtmc_draw_down(struct usbtmc_file_data *file_data)
24628c2ecf20Sopenharmony_ci{
24638c2ecf20Sopenharmony_ci	int time;
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	time = usb_wait_anchor_empty_timeout(&file_data->submitted, 1000);
24668c2ecf20Sopenharmony_ci	if (!time)
24678c2ecf20Sopenharmony_ci		usb_kill_anchored_urbs(&file_data->submitted);
24688c2ecf20Sopenharmony_ci	usb_scuttle_anchored_urbs(&file_data->in_anchor);
24698c2ecf20Sopenharmony_ci}
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_cistatic int usbtmc_suspend(struct usb_interface *intf, pm_message_t message)
24728c2ecf20Sopenharmony_ci{
24738c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = usb_get_intfdata(intf);
24748c2ecf20Sopenharmony_ci	struct list_head *elem;
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	if (!data)
24778c2ecf20Sopenharmony_ci		return 0;
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
24808c2ecf20Sopenharmony_ci	list_for_each(elem, &data->file_list) {
24818c2ecf20Sopenharmony_ci		struct usbtmc_file_data *file_data;
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci		file_data = list_entry(elem,
24848c2ecf20Sopenharmony_ci				       struct usbtmc_file_data,
24858c2ecf20Sopenharmony_ci				       file_elem);
24868c2ecf20Sopenharmony_ci		usbtmc_draw_down(file_data);
24878c2ecf20Sopenharmony_ci	}
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	if (data->iin_ep_present && data->iin_urb)
24908c2ecf20Sopenharmony_ci		usb_kill_urb(data->iin_urb);
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
24938c2ecf20Sopenharmony_ci	return 0;
24948c2ecf20Sopenharmony_ci}
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_cistatic int usbtmc_resume(struct usb_interface *intf)
24978c2ecf20Sopenharmony_ci{
24988c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data = usb_get_intfdata(intf);
24998c2ecf20Sopenharmony_ci	int retcode = 0;
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_ci	if (data->iin_ep_present && data->iin_urb)
25028c2ecf20Sopenharmony_ci		retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
25038c2ecf20Sopenharmony_ci	if (retcode)
25048c2ecf20Sopenharmony_ci		dev_err(&intf->dev, "Failed to submit iin_urb\n");
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci	return retcode;
25078c2ecf20Sopenharmony_ci}
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_cistatic int usbtmc_pre_reset(struct usb_interface *intf)
25108c2ecf20Sopenharmony_ci{
25118c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data  = usb_get_intfdata(intf);
25128c2ecf20Sopenharmony_ci	struct list_head *elem;
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci	if (!data)
25158c2ecf20Sopenharmony_ci		return 0;
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci	mutex_lock(&data->io_mutex);
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	list_for_each(elem, &data->file_list) {
25208c2ecf20Sopenharmony_ci		struct usbtmc_file_data *file_data;
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci		file_data = list_entry(elem,
25238c2ecf20Sopenharmony_ci				       struct usbtmc_file_data,
25248c2ecf20Sopenharmony_ci				       file_elem);
25258c2ecf20Sopenharmony_ci		usbtmc_ioctl_cancel_io(file_data);
25268c2ecf20Sopenharmony_ci	}
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	return 0;
25298c2ecf20Sopenharmony_ci}
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_cistatic int usbtmc_post_reset(struct usb_interface *intf)
25328c2ecf20Sopenharmony_ci{
25338c2ecf20Sopenharmony_ci	struct usbtmc_device_data *data  = usb_get_intfdata(intf);
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci	mutex_unlock(&data->io_mutex);
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci	return 0;
25388c2ecf20Sopenharmony_ci}
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_cistatic struct usb_driver usbtmc_driver = {
25418c2ecf20Sopenharmony_ci	.name		= "usbtmc",
25428c2ecf20Sopenharmony_ci	.id_table	= usbtmc_devices,
25438c2ecf20Sopenharmony_ci	.probe		= usbtmc_probe,
25448c2ecf20Sopenharmony_ci	.disconnect	= usbtmc_disconnect,
25458c2ecf20Sopenharmony_ci	.suspend	= usbtmc_suspend,
25468c2ecf20Sopenharmony_ci	.resume		= usbtmc_resume,
25478c2ecf20Sopenharmony_ci	.pre_reset	= usbtmc_pre_reset,
25488c2ecf20Sopenharmony_ci	.post_reset	= usbtmc_post_reset,
25498c2ecf20Sopenharmony_ci	.dev_groups	= usbtmc_groups,
25508c2ecf20Sopenharmony_ci};
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_cimodule_usb_driver(usbtmc_driver);
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2555