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