15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+ 25b775f67SGreg Kroah-Hartman /** 3af901ca1SAndré Goddard Rosa * drivers/usb/class/usbtmc.c - USB Test & Measurement class driver 45b775f67SGreg Kroah-Hartman * 55b775f67SGreg Kroah-Hartman * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany 65b775f67SGreg Kroah-Hartman * Copyright (C) 2008 Novell, Inc. 75b775f67SGreg Kroah-Hartman * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> 8658f24f4SGuido Kiener * Copyright (C) 2018 IVI Foundation, Inc. 95b775f67SGreg Kroah-Hartman */ 105b775f67SGreg Kroah-Hartman 11f4d844cbSAndy Shevchenko #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12f4d844cbSAndy Shevchenko 135b775f67SGreg Kroah-Hartman #include <linux/module.h> 14857cc4dfSIlpo Järvinen #include <linux/kernel.h> 155b775f67SGreg Kroah-Hartman #include <linux/fs.h> 165b775f67SGreg Kroah-Hartman #include <linux/uaccess.h> 175b775f67SGreg Kroah-Hartman #include <linux/kref.h> 185a0e3ad6STejun Heo #include <linux/slab.h> 19eb6b92ecSDave Penkler #include <linux/poll.h> 205b775f67SGreg Kroah-Hartman #include <linux/mutex.h> 215b775f67SGreg Kroah-Hartman #include <linux/usb.h> 2260207c8eSGuido Kiener #include <linux/compat.h> 235b775f67SGreg Kroah-Hartman #include <linux/usb/tmc.h> 245b775f67SGreg Kroah-Hartman 255b775f67SGreg Kroah-Hartman 268402db5dSAlexandre Peixoto Ferreira #define USBTMC_HEADER_SIZE 12 275b775f67SGreg Kroah-Hartman #define USBTMC_MINOR_BASE 176 285b775f67SGreg Kroah-Hartman 295b775f67SGreg Kroah-Hartman /* 305b775f67SGreg Kroah-Hartman * Size of driver internal IO buffer. Must be multiple of 4 and at least as 315b775f67SGreg Kroah-Hartman * large as wMaxPacketSize (which is usually 512 bytes). 325b775f67SGreg Kroah-Hartman */ 335b775f67SGreg Kroah-Hartman #define USBTMC_SIZE_IOBUFFER 2048 345b775f67SGreg Kroah-Hartman 35048c6d88SGuido Kiener /* Minimum USB timeout (in milliseconds) */ 36048c6d88SGuido Kiener #define USBTMC_MIN_TIMEOUT 100 375b775f67SGreg Kroah-Hartman /* Default USB timeout (in milliseconds) */ 3835f76e89SGergely Imreh #define USBTMC_TIMEOUT 5000 395b775f67SGreg Kroah-Hartman 404ddc645fSGuido Kiener /* Max number of urbs used in write transfers */ 414ddc645fSGuido Kiener #define MAX_URBS_IN_FLIGHT 16 42658f24f4SGuido Kiener /* I/O buffer size used in generic read/write functions */ 43658f24f4SGuido Kiener #define USBTMC_BUFSIZE (4096) 44658f24f4SGuido Kiener 455b775f67SGreg Kroah-Hartman /* 465b775f67SGreg Kroah-Hartman * Maximum number of read cycles to empty bulk in endpoint during CLEAR and 475b775f67SGreg Kroah-Hartman * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short 485b775f67SGreg Kroah-Hartman * packet is never read. 495b775f67SGreg Kroah-Hartman */ 505b775f67SGreg Kroah-Hartman #define USBTMC_MAX_READS_TO_CLEAR_BULK_IN 100 515b775f67SGreg Kroah-Hartman 526ef4852bSNémeth Márton static const struct usb_device_id usbtmc_devices[] = { 535b775f67SGreg Kroah-Hartman { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), }, 54228dd05dSGreg Kroah-Hartman { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), }, 555b775f67SGreg Kroah-Hartman { 0, } /* terminating entry */ 565b775f67SGreg Kroah-Hartman }; 575413aa46SGreg Kroah-Hartman MODULE_DEVICE_TABLE(usb, usbtmc_devices); 585b775f67SGreg Kroah-Hartman 595b775f67SGreg Kroah-Hartman /* 605b775f67SGreg Kroah-Hartman * This structure is the capabilities for the device 61d0a38365SGergely Imreh * See section 4.2.1.8 of the USBTMC specification, 62d0a38365SGergely Imreh * and section 4.2.2 of the USBTMC usb488 subclass 63d0a38365SGergely Imreh * specification for details. 645b775f67SGreg Kroah-Hartman */ 655b775f67SGreg Kroah-Hartman struct usbtmc_dev_capabilities { 665b775f67SGreg Kroah-Hartman __u8 interface_capabilities; 675b775f67SGreg Kroah-Hartman __u8 device_capabilities; 685b775f67SGreg Kroah-Hartman __u8 usb488_interface_capabilities; 695b775f67SGreg Kroah-Hartman __u8 usb488_device_capabilities; 705b775f67SGreg Kroah-Hartman }; 715b775f67SGreg Kroah-Hartman 725b775f67SGreg Kroah-Hartman /* This structure holds private data for each USBTMC device. One copy is 735b775f67SGreg Kroah-Hartman * allocated for each USBTMC device in the driver's probe function. 745b775f67SGreg Kroah-Hartman */ 755b775f67SGreg Kroah-Hartman struct usbtmc_device_data { 765b775f67SGreg Kroah-Hartman const struct usb_device_id *id; 775b775f67SGreg Kroah-Hartman struct usb_device *usb_dev; 785b775f67SGreg Kroah-Hartman struct usb_interface *intf; 794f3c8d6eSGuido Kiener struct list_head file_list; 805b775f67SGreg Kroah-Hartman 815b775f67SGreg Kroah-Hartman unsigned int bulk_in; 825b775f67SGreg Kroah-Hartman unsigned int bulk_out; 835b775f67SGreg Kroah-Hartman 845b775f67SGreg Kroah-Hartman u8 bTag; 855b775f67SGreg Kroah-Hartman u8 bTag_last_write; /* needed for abort */ 865b775f67SGreg Kroah-Hartman u8 bTag_last_read; /* needed for abort */ 875b775f67SGreg Kroah-Hartman 88bb99794aSGuido Kiener /* packet size of IN bulk */ 89bb99794aSGuido Kiener u16 wMaxPacketSize; 90bb99794aSGuido Kiener 91dbf3e7f6SDave Penkler /* data for interrupt in endpoint handling */ 92dbf3e7f6SDave Penkler u8 bNotify1; 93dbf3e7f6SDave Penkler u8 bNotify2; 94dbf3e7f6SDave Penkler u16 ifnum; 95dbf3e7f6SDave Penkler u8 iin_bTag; 96dbf3e7f6SDave Penkler u8 *iin_buffer; 97dbf3e7f6SDave Penkler atomic_t iin_data_valid; 98dbf3e7f6SDave Penkler unsigned int iin_ep; 99dbf3e7f6SDave Penkler int iin_ep_present; 100dbf3e7f6SDave Penkler int iin_interval; 101dbf3e7f6SDave Penkler struct urb *iin_urb; 102dbf3e7f6SDave Penkler u16 iin_wMaxPacketSize; 103dbf3e7f6SDave Penkler 10429779d89SDave Penkler /* coalesced usb488_caps from usbtmc_dev_capabilities */ 10529779d89SDave Penkler __u8 usb488_caps; 10629779d89SDave Penkler 1075b775f67SGreg Kroah-Hartman /* attributes from the USB TMC spec for this device */ 1085b775f67SGreg Kroah-Hartman u8 TermChar; 1095b775f67SGreg Kroah-Hartman bool TermCharEnabled; 1105b775f67SGreg Kroah-Hartman bool auto_abort; 1115b775f67SGreg Kroah-Hartman 11286286883SOliver Neukum bool zombie; /* fd of disconnected device */ 11386286883SOliver Neukum 1145b775f67SGreg Kroah-Hartman struct usbtmc_dev_capabilities capabilities; 1155b775f67SGreg Kroah-Hartman struct kref kref; 1165b775f67SGreg Kroah-Hartman struct mutex io_mutex; /* only one i/o function running at a time */ 117dbf3e7f6SDave Penkler wait_queue_head_t waitq; 11882ed3381SDave Penkler struct fasync_struct *fasync; 1194f3c8d6eSGuido Kiener spinlock_t dev_lock; /* lock for file_list */ 1205b775f67SGreg Kroah-Hartman }; 1215b775f67SGreg Kroah-Hartman #define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref) 1225b775f67SGreg Kroah-Hartman 1234f3c8d6eSGuido Kiener /* 1244f3c8d6eSGuido Kiener * This structure holds private data for each USBTMC file handle. 1254f3c8d6eSGuido Kiener */ 1264f3c8d6eSGuido Kiener struct usbtmc_file_data { 1274f3c8d6eSGuido Kiener struct usbtmc_device_data *data; 1284f3c8d6eSGuido Kiener struct list_head file_elem; 1294f3c8d6eSGuido Kiener 130048c6d88SGuido Kiener u32 timeout; 1314f3c8d6eSGuido Kiener u8 srq_byte; 1324f3c8d6eSGuido Kiener atomic_t srq_asserted; 133739240a9SGuido Kiener atomic_t closing; 1348409e96fSGuido Kiener u8 bmTransferAttributes; /* member of DEV_DEP_MSG_IN */ 1354ddc645fSGuido Kiener 136fbd83971SGuido Kiener u8 eom_val; 13712dcaeb7SGuido Kiener u8 term_char; 13812dcaeb7SGuido Kiener bool term_char_enabled; 139ec34d08eSGuido Kiener bool auto_abort; 1404ddc645fSGuido Kiener 1414ddc645fSGuido Kiener spinlock_t err_lock; /* lock for errors */ 1424ddc645fSGuido Kiener 1434ddc645fSGuido Kiener struct usb_anchor submitted; 1444ddc645fSGuido Kiener 1454ddc645fSGuido Kiener /* data for generic_write */ 1464ddc645fSGuido Kiener struct semaphore limit_write_sem; 1474ddc645fSGuido Kiener u32 out_transfer_size; 1484ddc645fSGuido Kiener int out_status; 149bb99794aSGuido Kiener 150bb99794aSGuido Kiener /* data for generic_read */ 151bb99794aSGuido Kiener u32 in_transfer_size; 152bb99794aSGuido Kiener int in_status; 153bb99794aSGuido Kiener int in_urbs_used; 154bb99794aSGuido Kiener struct usb_anchor in_anchor; 155bb99794aSGuido Kiener wait_queue_head_t wait_bulk_in; 1564f3c8d6eSGuido Kiener }; 1574f3c8d6eSGuido Kiener 1585b775f67SGreg Kroah-Hartman /* Forward declarations */ 1595b775f67SGreg Kroah-Hartman static struct usb_driver usbtmc_driver; 1604ddc645fSGuido Kiener static void usbtmc_draw_down(struct usbtmc_file_data *file_data); 1615b775f67SGreg Kroah-Hartman 1625b775f67SGreg Kroah-Hartman static void usbtmc_delete(struct kref *kref) 1635b775f67SGreg Kroah-Hartman { 1645b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = to_usbtmc_data(kref); 1655b775f67SGreg Kroah-Hartman 1665b775f67SGreg Kroah-Hartman usb_put_dev(data->usb_dev); 167ab21b63eSGreg Kroah-Hartman kfree(data); 1685b775f67SGreg Kroah-Hartman } 1695b775f67SGreg Kroah-Hartman 1705b775f67SGreg Kroah-Hartman static int usbtmc_open(struct inode *inode, struct file *filp) 1715b775f67SGreg Kroah-Hartman { 1725b775f67SGreg Kroah-Hartman struct usb_interface *intf; 1735b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 1744f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data; 1755b775f67SGreg Kroah-Hartman 1765b775f67SGreg Kroah-Hartman intf = usb_find_interface(&usbtmc_driver, iminor(inode)); 1775b775f67SGreg Kroah-Hartman if (!intf) { 178f4d844cbSAndy Shevchenko pr_err("can not find device for minor %d", iminor(inode)); 179f4d844cbSAndy Shevchenko return -ENODEV; 1805b775f67SGreg Kroah-Hartman } 1815b775f67SGreg Kroah-Hartman 1824f3c8d6eSGuido Kiener file_data = kzalloc(sizeof(*file_data), GFP_KERNEL); 1834f3c8d6eSGuido Kiener if (!file_data) 1844f3c8d6eSGuido Kiener return -ENOMEM; 1854f3c8d6eSGuido Kiener 1864ddc645fSGuido Kiener spin_lock_init(&file_data->err_lock); 1874ddc645fSGuido Kiener sema_init(&file_data->limit_write_sem, MAX_URBS_IN_FLIGHT); 1884ddc645fSGuido Kiener init_usb_anchor(&file_data->submitted); 189bb99794aSGuido Kiener init_usb_anchor(&file_data->in_anchor); 190bb99794aSGuido Kiener init_waitqueue_head(&file_data->wait_bulk_in); 1914ddc645fSGuido Kiener 1925b775f67SGreg Kroah-Hartman data = usb_get_intfdata(intf); 19388aecde4SDave Penkler /* Protect reference to data from file structure until release */ 1945b775f67SGreg Kroah-Hartman kref_get(&data->kref); 1955b775f67SGreg Kroah-Hartman 1964f3c8d6eSGuido Kiener mutex_lock(&data->io_mutex); 1974f3c8d6eSGuido Kiener file_data->data = data; 1985b775f67SGreg Kroah-Hartman 199739240a9SGuido Kiener atomic_set(&file_data->closing, 0); 200739240a9SGuido Kiener 20112dcaeb7SGuido Kiener /* copy default values from device settings */ 202048c6d88SGuido Kiener file_data->timeout = USBTMC_TIMEOUT; 20312dcaeb7SGuido Kiener file_data->term_char = data->TermChar; 20412dcaeb7SGuido Kiener file_data->term_char_enabled = data->TermCharEnabled; 205ec34d08eSGuido Kiener file_data->auto_abort = data->auto_abort; 206fbd83971SGuido Kiener file_data->eom_val = 1; 207048c6d88SGuido Kiener 2084f3c8d6eSGuido Kiener INIT_LIST_HEAD(&file_data->file_elem); 2094f3c8d6eSGuido Kiener spin_lock_irq(&data->dev_lock); 2104f3c8d6eSGuido Kiener list_add_tail(&file_data->file_elem, &data->file_list); 2114f3c8d6eSGuido Kiener spin_unlock_irq(&data->dev_lock); 2124f3c8d6eSGuido Kiener mutex_unlock(&data->io_mutex); 2134f3c8d6eSGuido Kiener 2144f3c8d6eSGuido Kiener /* Store pointer in file structure's private data field */ 2154f3c8d6eSGuido Kiener filp->private_data = file_data; 2164f3c8d6eSGuido Kiener 2174f3c8d6eSGuido Kiener return 0; 2185b775f67SGreg Kroah-Hartman } 2195b775f67SGreg Kroah-Hartman 2204ddc645fSGuido Kiener /* 2214ddc645fSGuido Kiener * usbtmc_flush - called before file handle is closed 2224ddc645fSGuido Kiener */ 2234ddc645fSGuido Kiener static int usbtmc_flush(struct file *file, fl_owner_t id) 2244ddc645fSGuido Kiener { 2254ddc645fSGuido Kiener struct usbtmc_file_data *file_data; 2264ddc645fSGuido Kiener struct usbtmc_device_data *data; 2274ddc645fSGuido Kiener 2284ddc645fSGuido Kiener file_data = file->private_data; 2294ddc645fSGuido Kiener if (file_data == NULL) 2304ddc645fSGuido Kiener return -ENODEV; 2314ddc645fSGuido Kiener 232739240a9SGuido Kiener atomic_set(&file_data->closing, 1); 2334ddc645fSGuido Kiener data = file_data->data; 2344ddc645fSGuido Kiener 2354ddc645fSGuido Kiener /* wait for io to stop */ 2364ddc645fSGuido Kiener mutex_lock(&data->io_mutex); 2374ddc645fSGuido Kiener 2384ddc645fSGuido Kiener usbtmc_draw_down(file_data); 2394ddc645fSGuido Kiener 2404ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 241bb99794aSGuido Kiener file_data->in_status = 0; 242bb99794aSGuido Kiener file_data->in_transfer_size = 0; 243bb99794aSGuido Kiener file_data->in_urbs_used = 0; 2444ddc645fSGuido Kiener file_data->out_status = 0; 2454ddc645fSGuido Kiener file_data->out_transfer_size = 0; 2464ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 2474ddc645fSGuido Kiener 2484ddc645fSGuido Kiener wake_up_interruptible_all(&data->waitq); 2494ddc645fSGuido Kiener mutex_unlock(&data->io_mutex); 2504ddc645fSGuido Kiener 2514ddc645fSGuido Kiener return 0; 2524ddc645fSGuido Kiener } 2534ddc645fSGuido Kiener 2545b775f67SGreg Kroah-Hartman static int usbtmc_release(struct inode *inode, struct file *file) 2555b775f67SGreg Kroah-Hartman { 2564f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data = file->private_data; 2575b775f67SGreg Kroah-Hartman 2584f3c8d6eSGuido Kiener /* prevent IO _AND_ usbtmc_interrupt */ 2594f3c8d6eSGuido Kiener mutex_lock(&file_data->data->io_mutex); 2604f3c8d6eSGuido Kiener spin_lock_irq(&file_data->data->dev_lock); 2614f3c8d6eSGuido Kiener 2624f3c8d6eSGuido Kiener list_del(&file_data->file_elem); 2634f3c8d6eSGuido Kiener 2644f3c8d6eSGuido Kiener spin_unlock_irq(&file_data->data->dev_lock); 2654f3c8d6eSGuido Kiener mutex_unlock(&file_data->data->io_mutex); 2664f3c8d6eSGuido Kiener 2674f3c8d6eSGuido Kiener kref_put(&file_data->data->kref, usbtmc_delete); 2684f3c8d6eSGuido Kiener file_data->data = NULL; 2694f3c8d6eSGuido Kiener kfree(file_data); 2705b775f67SGreg Kroah-Hartman return 0; 2715b775f67SGreg Kroah-Hartman } 2725b775f67SGreg Kroah-Hartman 273cbe743f1SGuido Kiener static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data, 274cbe743f1SGuido Kiener u8 tag) 2755b775f67SGreg Kroah-Hartman { 276b361a6e3SChris Malley u8 *buffer; 2775b775f67SGreg Kroah-Hartman struct device *dev; 2785b775f67SGreg Kroah-Hartman int rv; 2795b775f67SGreg Kroah-Hartman int n; 2805b775f67SGreg Kroah-Hartman int actual; 2815b775f67SGreg Kroah-Hartman 2825b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 283cbe743f1SGuido Kiener buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL); 2845b775f67SGreg Kroah-Hartman if (!buffer) 2855b775f67SGreg Kroah-Hartman return -ENOMEM; 2865b775f67SGreg Kroah-Hartman 2875b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 2885b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 2895b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, 2905b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 291cbe743f1SGuido Kiener tag, data->bulk_in, 292cbe743f1SGuido Kiener buffer, 2, USB_CTRL_GET_TIMEOUT); 2935b775f67SGreg Kroah-Hartman 2945b775f67SGreg Kroah-Hartman if (rv < 0) { 2955b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 2965b775f67SGreg Kroah-Hartman goto exit; 2975b775f67SGreg Kroah-Hartman } 2985b775f67SGreg Kroah-Hartman 299cbe743f1SGuido Kiener dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n", 300cbe743f1SGuido Kiener buffer[0], buffer[1]); 3015b775f67SGreg Kroah-Hartman 3025b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_FAILED) { 303cbe743f1SGuido Kiener /* No transfer in progress and the Bulk-OUT FIFO is empty. */ 3045b775f67SGreg Kroah-Hartman rv = 0; 3055b775f67SGreg Kroah-Hartman goto exit; 3065b775f67SGreg Kroah-Hartman } 3075b775f67SGreg Kroah-Hartman 308cbe743f1SGuido Kiener if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) { 309cbe743f1SGuido Kiener /* The device returns this status if either: 310cbe743f1SGuido Kiener * - There is a transfer in progress, but the specified bTag 311cbe743f1SGuido Kiener * does not match. 312cbe743f1SGuido Kiener * - There is no transfer in progress, but the Bulk-OUT FIFO 313cbe743f1SGuido Kiener * is not empty. 314cbe743f1SGuido Kiener */ 315cbe743f1SGuido Kiener rv = -ENOMSG; 316cbe743f1SGuido Kiener goto exit; 317cbe743f1SGuido Kiener } 318cbe743f1SGuido Kiener 3195b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 3205b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", 3215b775f67SGreg Kroah-Hartman buffer[0]); 3225b775f67SGreg Kroah-Hartman rv = -EPERM; 3235b775f67SGreg Kroah-Hartman goto exit; 3245b775f67SGreg Kroah-Hartman } 3255b775f67SGreg Kroah-Hartman 3265b775f67SGreg Kroah-Hartman n = 0; 3275b775f67SGreg Kroah-Hartman 328cbe743f1SGuido Kiener usbtmc_abort_bulk_in_status: 3295b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 3305b775f67SGreg Kroah-Hartman 331cbe743f1SGuido Kiener /* Data must be present. So use low timeout 300 ms */ 3325b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 3335b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 3345b775f67SGreg Kroah-Hartman data->bulk_in), 335cbe743f1SGuido Kiener buffer, USBTMC_BUFSIZE, 336cbe743f1SGuido Kiener &actual, 300); 337cbe743f1SGuido Kiener 338cbe743f1SGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1, 339cbe743f1SGuido Kiener buffer, actual, true); 3405b775f67SGreg Kroah-Hartman 3415b775f67SGreg Kroah-Hartman n++; 3425b775f67SGreg Kroah-Hartman 3435b775f67SGreg Kroah-Hartman if (rv < 0) { 3445b775f67SGreg Kroah-Hartman dev_err(dev, "usb_bulk_msg returned %d\n", rv); 345cbe743f1SGuido Kiener if (rv != -ETIMEDOUT) 3465b775f67SGreg Kroah-Hartman goto exit; 3475b775f67SGreg Kroah-Hartman } 3485b775f67SGreg Kroah-Hartman 349cbe743f1SGuido Kiener if (actual == USBTMC_BUFSIZE) 350cbe743f1SGuido Kiener goto usbtmc_abort_bulk_in_status; 351cbe743f1SGuido Kiener 352cbe743f1SGuido Kiener if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) { 3535b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 3545b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 3555b775f67SGreg Kroah-Hartman rv = -EPERM; 3565b775f67SGreg Kroah-Hartman goto exit; 3575b775f67SGreg Kroah-Hartman } 3585b775f67SGreg Kroah-Hartman 3595b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 3605b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 3615b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, 3625b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 3635b775f67SGreg Kroah-Hartman 0, data->bulk_in, buffer, 0x08, 364cbe743f1SGuido Kiener USB_CTRL_GET_TIMEOUT); 3655b775f67SGreg Kroah-Hartman 3665b775f67SGreg Kroah-Hartman if (rv < 0) { 3675b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 3685b775f67SGreg Kroah-Hartman goto exit; 3695b775f67SGreg Kroah-Hartman } 3705b775f67SGreg Kroah-Hartman 371cbe743f1SGuido Kiener dev_dbg(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); 3725b775f67SGreg Kroah-Hartman 3735b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) { 3745b775f67SGreg Kroah-Hartman rv = 0; 3755b775f67SGreg Kroah-Hartman goto exit; 3765b775f67SGreg Kroah-Hartman } 3775b775f67SGreg Kroah-Hartman 3785b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_PENDING) { 379cbe743f1SGuido Kiener dev_err(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); 3805b775f67SGreg Kroah-Hartman rv = -EPERM; 3815b775f67SGreg Kroah-Hartman goto exit; 3825b775f67SGreg Kroah-Hartman } 3835b775f67SGreg Kroah-Hartman 384cbe743f1SGuido Kiener if ((buffer[1] & 1) > 0) { 385cbe743f1SGuido Kiener /* The device has 1 or more queued packets the Host can read */ 3865b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_in_status; 387cbe743f1SGuido Kiener } 3885b775f67SGreg Kroah-Hartman 389cbe743f1SGuido Kiener /* The Host must send CHECK_ABORT_BULK_IN_STATUS at a later time. */ 390cbe743f1SGuido Kiener rv = -EAGAIN; 3915b775f67SGreg Kroah-Hartman exit: 3925b775f67SGreg Kroah-Hartman kfree(buffer); 3935b775f67SGreg Kroah-Hartman return rv; 394cbe743f1SGuido Kiener } 3955b775f67SGreg Kroah-Hartman 396cbe743f1SGuido Kiener static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) 397cbe743f1SGuido Kiener { 398cbe743f1SGuido Kiener return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read); 3995b775f67SGreg Kroah-Hartman } 4005b775f67SGreg Kroah-Hartman 401*0e59088eSGuido Kiener static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data, 402*0e59088eSGuido Kiener u8 tag) 4035b775f67SGreg Kroah-Hartman { 4045b775f67SGreg Kroah-Hartman struct device *dev; 4055b775f67SGreg Kroah-Hartman u8 *buffer; 4065b775f67SGreg Kroah-Hartman int rv; 4075b775f67SGreg Kroah-Hartman int n; 4085b775f67SGreg Kroah-Hartman 4095b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 4105b775f67SGreg Kroah-Hartman 4115b775f67SGreg Kroah-Hartman buffer = kmalloc(8, GFP_KERNEL); 4125b775f67SGreg Kroah-Hartman if (!buffer) 4135b775f67SGreg Kroah-Hartman return -ENOMEM; 4145b775f67SGreg Kroah-Hartman 4155b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 4165b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 4175b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, 4185b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 419*0e59088eSGuido Kiener tag, data->bulk_out, 420*0e59088eSGuido Kiener buffer, 2, USB_CTRL_GET_TIMEOUT); 4215b775f67SGreg Kroah-Hartman 4225b775f67SGreg Kroah-Hartman if (rv < 0) { 4235b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 4245b775f67SGreg Kroah-Hartman goto exit; 4255b775f67SGreg Kroah-Hartman } 4265b775f67SGreg Kroah-Hartman 4275b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", buffer[0]); 4285b775f67SGreg Kroah-Hartman 4295b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 4305b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", 4315b775f67SGreg Kroah-Hartman buffer[0]); 4325b775f67SGreg Kroah-Hartman rv = -EPERM; 4335b775f67SGreg Kroah-Hartman goto exit; 4345b775f67SGreg Kroah-Hartman } 4355b775f67SGreg Kroah-Hartman 4365b775f67SGreg Kroah-Hartman n = 0; 4375b775f67SGreg Kroah-Hartman 4385b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_check_status: 439*0e59088eSGuido Kiener /* do not stress device with subsequent requests */ 440*0e59088eSGuido Kiener msleep(50); 4415b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 4425b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 4435b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, 4445b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 4455b775f67SGreg Kroah-Hartman 0, data->bulk_out, buffer, 0x08, 446*0e59088eSGuido Kiener USB_CTRL_GET_TIMEOUT); 4475b775f67SGreg Kroah-Hartman n++; 4485b775f67SGreg Kroah-Hartman if (rv < 0) { 4495b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 4505b775f67SGreg Kroah-Hartman goto exit; 4515b775f67SGreg Kroah-Hartman } 4525b775f67SGreg Kroah-Hartman 4535b775f67SGreg Kroah-Hartman dev_dbg(dev, "CHECK_ABORT_BULK_OUT returned %x\n", buffer[0]); 4545b775f67SGreg Kroah-Hartman 4555b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) 4565b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_out_clear_halt; 4575b775f67SGreg Kroah-Hartman 4585b775f67SGreg Kroah-Hartman if ((buffer[0] == USBTMC_STATUS_PENDING) && 4595b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)) 4605b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_out_check_status; 4615b775f67SGreg Kroah-Hartman 4625b775f67SGreg Kroah-Hartman rv = -EPERM; 4635b775f67SGreg Kroah-Hartman goto exit; 4645b775f67SGreg Kroah-Hartman 4655b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_clear_halt: 4663342ecdaSSarah Sharp rv = usb_clear_halt(data->usb_dev, 4673342ecdaSSarah Sharp usb_sndbulkpipe(data->usb_dev, data->bulk_out)); 4685b775f67SGreg Kroah-Hartman 4695b775f67SGreg Kroah-Hartman if (rv < 0) { 4705b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 4715b775f67SGreg Kroah-Hartman goto exit; 4725b775f67SGreg Kroah-Hartman } 4735b775f67SGreg Kroah-Hartman rv = 0; 4745b775f67SGreg Kroah-Hartman 4755b775f67SGreg Kroah-Hartman exit: 4765b775f67SGreg Kroah-Hartman kfree(buffer); 4775b775f67SGreg Kroah-Hartman return rv; 4785b775f67SGreg Kroah-Hartman } 4795b775f67SGreg Kroah-Hartman 480*0e59088eSGuido Kiener static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) 481*0e59088eSGuido Kiener { 482*0e59088eSGuido Kiener return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write); 483*0e59088eSGuido Kiener } 484*0e59088eSGuido Kiener 4854f3c8d6eSGuido Kiener static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, 486dbf3e7f6SDave Penkler void __user *arg) 487dbf3e7f6SDave Penkler { 4884f3c8d6eSGuido Kiener struct usbtmc_device_data *data = file_data->data; 489dbf3e7f6SDave Penkler struct device *dev = &data->intf->dev; 4904f3c8d6eSGuido Kiener int srq_asserted = 0; 491dbf3e7f6SDave Penkler u8 *buffer; 492dbf3e7f6SDave Penkler u8 tag; 493dbf3e7f6SDave Penkler __u8 stb; 494dbf3e7f6SDave Penkler int rv; 495dbf3e7f6SDave Penkler 496dbf3e7f6SDave Penkler dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n", 497dbf3e7f6SDave Penkler data->iin_ep_present); 498dbf3e7f6SDave Penkler 4994f3c8d6eSGuido Kiener spin_lock_irq(&data->dev_lock); 5004f3c8d6eSGuido Kiener srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted); 5014f3c8d6eSGuido Kiener if (srq_asserted) { 5024f3c8d6eSGuido Kiener /* a STB with SRQ is already received */ 5034f3c8d6eSGuido Kiener stb = file_data->srq_byte; 5044f3c8d6eSGuido Kiener spin_unlock_irq(&data->dev_lock); 5054f3c8d6eSGuido Kiener rv = put_user(stb, (__u8 __user *)arg); 5064f3c8d6eSGuido Kiener dev_dbg(dev, "stb:0x%02x with srq received %d\n", 5074f3c8d6eSGuido Kiener (unsigned int)stb, rv); 5084f3c8d6eSGuido Kiener return rv; 5094f3c8d6eSGuido Kiener } 5104f3c8d6eSGuido Kiener spin_unlock_irq(&data->dev_lock); 5114f3c8d6eSGuido Kiener 512dbf3e7f6SDave Penkler buffer = kmalloc(8, GFP_KERNEL); 513dbf3e7f6SDave Penkler if (!buffer) 514dbf3e7f6SDave Penkler return -ENOMEM; 515dbf3e7f6SDave Penkler 516dbf3e7f6SDave Penkler atomic_set(&data->iin_data_valid, 0); 517dbf3e7f6SDave Penkler 518dbf3e7f6SDave Penkler rv = usb_control_msg(data->usb_dev, 519dbf3e7f6SDave Penkler usb_rcvctrlpipe(data->usb_dev, 0), 520dbf3e7f6SDave Penkler USBTMC488_REQUEST_READ_STATUS_BYTE, 521dbf3e7f6SDave Penkler USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 522dbf3e7f6SDave Penkler data->iin_bTag, 523dbf3e7f6SDave Penkler data->ifnum, 524dbf3e7f6SDave Penkler buffer, 0x03, USBTMC_TIMEOUT); 525dbf3e7f6SDave Penkler if (rv < 0) { 526dbf3e7f6SDave Penkler dev_err(dev, "stb usb_control_msg returned %d\n", rv); 527dbf3e7f6SDave Penkler goto exit; 528dbf3e7f6SDave Penkler } 529dbf3e7f6SDave Penkler 530dbf3e7f6SDave Penkler if (buffer[0] != USBTMC_STATUS_SUCCESS) { 531dbf3e7f6SDave Penkler dev_err(dev, "control status returned %x\n", buffer[0]); 532dbf3e7f6SDave Penkler rv = -EIO; 533dbf3e7f6SDave Penkler goto exit; 534dbf3e7f6SDave Penkler } 535dbf3e7f6SDave Penkler 536dbf3e7f6SDave Penkler if (data->iin_ep_present) { 537dbf3e7f6SDave Penkler rv = wait_event_interruptible_timeout( 538dbf3e7f6SDave Penkler data->waitq, 539dbf3e7f6SDave Penkler atomic_read(&data->iin_data_valid) != 0, 540048c6d88SGuido Kiener file_data->timeout); 541dbf3e7f6SDave Penkler if (rv < 0) { 542dbf3e7f6SDave Penkler dev_dbg(dev, "wait interrupted %d\n", rv); 543dbf3e7f6SDave Penkler goto exit; 544dbf3e7f6SDave Penkler } 545dbf3e7f6SDave Penkler 546dbf3e7f6SDave Penkler if (rv == 0) { 547dbf3e7f6SDave Penkler dev_dbg(dev, "wait timed out\n"); 54819e6c57eSGuido Kiener rv = -ETIMEDOUT; 549dbf3e7f6SDave Penkler goto exit; 550dbf3e7f6SDave Penkler } 551dbf3e7f6SDave Penkler 552dbf3e7f6SDave Penkler tag = data->bNotify1 & 0x7f; 553dbf3e7f6SDave Penkler if (tag != data->iin_bTag) { 554dbf3e7f6SDave Penkler dev_err(dev, "expected bTag %x got %x\n", 555dbf3e7f6SDave Penkler data->iin_bTag, tag); 556dbf3e7f6SDave Penkler } 557dbf3e7f6SDave Penkler 558dbf3e7f6SDave Penkler stb = data->bNotify2; 559dbf3e7f6SDave Penkler } else { 560dbf3e7f6SDave Penkler stb = buffer[2]; 561dbf3e7f6SDave Penkler } 562dbf3e7f6SDave Penkler 5634f3c8d6eSGuido Kiener rv = put_user(stb, (__u8 __user *)arg); 5644f3c8d6eSGuido Kiener dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)stb, rv); 565dbf3e7f6SDave Penkler 566dbf3e7f6SDave Penkler exit: 567dbf3e7f6SDave Penkler /* bump interrupt bTag */ 568dbf3e7f6SDave Penkler data->iin_bTag += 1; 569dbf3e7f6SDave Penkler if (data->iin_bTag > 127) 570dbf3e7f6SDave Penkler /* 1 is for SRQ see USBTMC-USB488 subclass spec section 4.3.1 */ 571dbf3e7f6SDave Penkler data->iin_bTag = 2; 572dbf3e7f6SDave Penkler 573dbf3e7f6SDave Penkler kfree(buffer); 574dbf3e7f6SDave Penkler return rv; 575dbf3e7f6SDave Penkler } 576dbf3e7f6SDave Penkler 577739240a9SGuido Kiener static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, 578739240a9SGuido Kiener __u32 __user *arg) 579739240a9SGuido Kiener { 580739240a9SGuido Kiener struct usbtmc_device_data *data = file_data->data; 581739240a9SGuido Kiener struct device *dev = &data->intf->dev; 582739240a9SGuido Kiener int rv; 583739240a9SGuido Kiener u32 timeout; 584739240a9SGuido Kiener unsigned long expire; 585739240a9SGuido Kiener 586739240a9SGuido Kiener if (!data->iin_ep_present) { 587739240a9SGuido Kiener dev_dbg(dev, "no interrupt endpoint present\n"); 588739240a9SGuido Kiener return -EFAULT; 589739240a9SGuido Kiener } 590739240a9SGuido Kiener 591739240a9SGuido Kiener if (get_user(timeout, arg)) 592739240a9SGuido Kiener return -EFAULT; 593739240a9SGuido Kiener 594739240a9SGuido Kiener expire = msecs_to_jiffies(timeout); 595739240a9SGuido Kiener 596739240a9SGuido Kiener mutex_unlock(&data->io_mutex); 597739240a9SGuido Kiener 598739240a9SGuido Kiener rv = wait_event_interruptible_timeout( 599739240a9SGuido Kiener data->waitq, 600739240a9SGuido Kiener atomic_read(&file_data->srq_asserted) != 0 || 601739240a9SGuido Kiener atomic_read(&file_data->closing), 602739240a9SGuido Kiener expire); 603739240a9SGuido Kiener 604739240a9SGuido Kiener mutex_lock(&data->io_mutex); 605739240a9SGuido Kiener 606739240a9SGuido Kiener /* Note! disconnect or close could be called in the meantime */ 607739240a9SGuido Kiener if (atomic_read(&file_data->closing) || data->zombie) 608739240a9SGuido Kiener rv = -ENODEV; 609739240a9SGuido Kiener 610739240a9SGuido Kiener if (rv < 0) { 611739240a9SGuido Kiener /* dev can be invalid now! */ 612739240a9SGuido Kiener pr_debug("%s - wait interrupted %d\n", __func__, rv); 613739240a9SGuido Kiener return rv; 614739240a9SGuido Kiener } 615739240a9SGuido Kiener 616739240a9SGuido Kiener if (rv == 0) { 617739240a9SGuido Kiener dev_dbg(dev, "%s - wait timed out\n", __func__); 618739240a9SGuido Kiener return -ETIMEDOUT; 619739240a9SGuido Kiener } 620739240a9SGuido Kiener 621739240a9SGuido Kiener dev_dbg(dev, "%s - srq asserted\n", __func__); 622739240a9SGuido Kiener return 0; 623739240a9SGuido Kiener } 624739240a9SGuido Kiener 625379d3d33SDave Penkler static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data, 626379d3d33SDave Penkler void __user *arg, unsigned int cmd) 627379d3d33SDave Penkler { 628379d3d33SDave Penkler struct device *dev = &data->intf->dev; 629379d3d33SDave Penkler __u8 val; 630379d3d33SDave Penkler u8 *buffer; 631379d3d33SDave Penkler u16 wValue; 632379d3d33SDave Penkler int rv; 633379d3d33SDave Penkler 634379d3d33SDave Penkler if (!(data->usb488_caps & USBTMC488_CAPABILITY_SIMPLE)) 635379d3d33SDave Penkler return -EINVAL; 636379d3d33SDave Penkler 637379d3d33SDave Penkler buffer = kmalloc(8, GFP_KERNEL); 638379d3d33SDave Penkler if (!buffer) 639379d3d33SDave Penkler return -ENOMEM; 640379d3d33SDave Penkler 641379d3d33SDave Penkler if (cmd == USBTMC488_REQUEST_REN_CONTROL) { 642379d3d33SDave Penkler rv = copy_from_user(&val, arg, sizeof(val)); 643379d3d33SDave Penkler if (rv) { 644379d3d33SDave Penkler rv = -EFAULT; 645379d3d33SDave Penkler goto exit; 646379d3d33SDave Penkler } 647379d3d33SDave Penkler wValue = val ? 1 : 0; 648379d3d33SDave Penkler } else { 649379d3d33SDave Penkler wValue = 0; 650379d3d33SDave Penkler } 651379d3d33SDave Penkler 652379d3d33SDave Penkler rv = usb_control_msg(data->usb_dev, 653379d3d33SDave Penkler usb_rcvctrlpipe(data->usb_dev, 0), 654379d3d33SDave Penkler cmd, 655379d3d33SDave Penkler USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 656379d3d33SDave Penkler wValue, 657379d3d33SDave Penkler data->ifnum, 658379d3d33SDave Penkler buffer, 0x01, USBTMC_TIMEOUT); 659379d3d33SDave Penkler if (rv < 0) { 660379d3d33SDave Penkler dev_err(dev, "simple usb_control_msg failed %d\n", rv); 661379d3d33SDave Penkler goto exit; 662379d3d33SDave Penkler } else if (rv != 1) { 663379d3d33SDave Penkler dev_warn(dev, "simple usb_control_msg returned %d\n", rv); 664379d3d33SDave Penkler rv = -EIO; 665379d3d33SDave Penkler goto exit; 666379d3d33SDave Penkler } 667379d3d33SDave Penkler 668379d3d33SDave Penkler if (buffer[0] != USBTMC_STATUS_SUCCESS) { 669379d3d33SDave Penkler dev_err(dev, "simple control status returned %x\n", buffer[0]); 670379d3d33SDave Penkler rv = -EIO; 671379d3d33SDave Penkler goto exit; 672379d3d33SDave Penkler } 673379d3d33SDave Penkler rv = 0; 674379d3d33SDave Penkler 675379d3d33SDave Penkler exit: 676379d3d33SDave Penkler kfree(buffer); 677379d3d33SDave Penkler return rv; 678379d3d33SDave Penkler } 679379d3d33SDave Penkler 68088d9b2b3SAlexandre Peixoto Ferreira /* 681fe78a7c6SGuido Kiener * Sends a TRIGGER Bulk-OUT command message 682fe78a7c6SGuido Kiener * See the USBTMC-USB488 specification, Table 2. 683fe78a7c6SGuido Kiener * 684fe78a7c6SGuido Kiener * Also updates bTag_last_write. 685fe78a7c6SGuido Kiener */ 686fe78a7c6SGuido Kiener static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data) 687fe78a7c6SGuido Kiener { 688fe78a7c6SGuido Kiener struct usbtmc_device_data *data = file_data->data; 689fe78a7c6SGuido Kiener int retval; 690fe78a7c6SGuido Kiener u8 *buffer; 691fe78a7c6SGuido Kiener int actual; 692fe78a7c6SGuido Kiener 693fe78a7c6SGuido Kiener buffer = kzalloc(USBTMC_HEADER_SIZE, GFP_KERNEL); 694fe78a7c6SGuido Kiener if (!buffer) 695fe78a7c6SGuido Kiener return -ENOMEM; 696fe78a7c6SGuido Kiener 697fe78a7c6SGuido Kiener buffer[0] = 128; 698fe78a7c6SGuido Kiener buffer[1] = data->bTag; 699fe78a7c6SGuido Kiener buffer[2] = ~data->bTag; 700fe78a7c6SGuido Kiener 701fe78a7c6SGuido Kiener retval = usb_bulk_msg(data->usb_dev, 702fe78a7c6SGuido Kiener usb_sndbulkpipe(data->usb_dev, 703fe78a7c6SGuido Kiener data->bulk_out), 704fe78a7c6SGuido Kiener buffer, USBTMC_HEADER_SIZE, 705fe78a7c6SGuido Kiener &actual, file_data->timeout); 706fe78a7c6SGuido Kiener 707fe78a7c6SGuido Kiener /* Store bTag (in case we need to abort) */ 708fe78a7c6SGuido Kiener data->bTag_last_write = data->bTag; 709fe78a7c6SGuido Kiener 710fe78a7c6SGuido Kiener /* Increment bTag -- and increment again if zero */ 711fe78a7c6SGuido Kiener data->bTag++; 712fe78a7c6SGuido Kiener if (!data->bTag) 713fe78a7c6SGuido Kiener data->bTag++; 714fe78a7c6SGuido Kiener 715fe78a7c6SGuido Kiener kfree(buffer); 716fe78a7c6SGuido Kiener if (retval < 0) { 717fe78a7c6SGuido Kiener dev_err(&data->intf->dev, "%s returned %d\n", 718fe78a7c6SGuido Kiener __func__, retval); 719fe78a7c6SGuido Kiener return retval; 720fe78a7c6SGuido Kiener } 721fe78a7c6SGuido Kiener 722fe78a7c6SGuido Kiener return 0; 723fe78a7c6SGuido Kiener } 724fe78a7c6SGuido Kiener 7254ddc645fSGuido Kiener static struct urb *usbtmc_create_urb(void) 7264ddc645fSGuido Kiener { 7274ddc645fSGuido Kiener const size_t bufsize = USBTMC_BUFSIZE; 7284ddc645fSGuido Kiener u8 *dmabuf = NULL; 7294ddc645fSGuido Kiener struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); 7304ddc645fSGuido Kiener 7314ddc645fSGuido Kiener if (!urb) 7324ddc645fSGuido Kiener return NULL; 7334ddc645fSGuido Kiener 7344ddc645fSGuido Kiener dmabuf = kmalloc(bufsize, GFP_KERNEL); 7354ddc645fSGuido Kiener if (!dmabuf) { 7364ddc645fSGuido Kiener usb_free_urb(urb); 7374ddc645fSGuido Kiener return NULL; 7384ddc645fSGuido Kiener } 7394ddc645fSGuido Kiener 7404ddc645fSGuido Kiener urb->transfer_buffer = dmabuf; 7414ddc645fSGuido Kiener urb->transfer_buffer_length = bufsize; 7424ddc645fSGuido Kiener urb->transfer_flags |= URB_FREE_BUFFER; 7434ddc645fSGuido Kiener return urb; 7444ddc645fSGuido Kiener } 7454ddc645fSGuido Kiener 746bb99794aSGuido Kiener static void usbtmc_read_bulk_cb(struct urb *urb) 747bb99794aSGuido Kiener { 748bb99794aSGuido Kiener struct usbtmc_file_data *file_data = urb->context; 749bb99794aSGuido Kiener int status = urb->status; 750bb99794aSGuido Kiener unsigned long flags; 751bb99794aSGuido Kiener 752bb99794aSGuido Kiener /* sync/async unlink faults aren't errors */ 753bb99794aSGuido Kiener if (status) { 754bb99794aSGuido Kiener if (!(/* status == -ENOENT || */ 755bb99794aSGuido Kiener status == -ECONNRESET || 756bb99794aSGuido Kiener status == -EREMOTEIO || /* Short packet */ 757bb99794aSGuido Kiener status == -ESHUTDOWN)) 758bb99794aSGuido Kiener dev_err(&file_data->data->intf->dev, 759bb99794aSGuido Kiener "%s - nonzero read bulk status received: %d\n", 760bb99794aSGuido Kiener __func__, status); 761bb99794aSGuido Kiener 762bb99794aSGuido Kiener spin_lock_irqsave(&file_data->err_lock, flags); 763bb99794aSGuido Kiener if (!file_data->in_status) 764bb99794aSGuido Kiener file_data->in_status = status; 765bb99794aSGuido Kiener spin_unlock_irqrestore(&file_data->err_lock, flags); 766bb99794aSGuido Kiener } 767bb99794aSGuido Kiener 768bb99794aSGuido Kiener spin_lock_irqsave(&file_data->err_lock, flags); 769bb99794aSGuido Kiener file_data->in_transfer_size += urb->actual_length; 770bb99794aSGuido Kiener dev_dbg(&file_data->data->intf->dev, 771bb99794aSGuido Kiener "%s - total size: %u current: %d status: %d\n", 772bb99794aSGuido Kiener __func__, file_data->in_transfer_size, 773bb99794aSGuido Kiener urb->actual_length, status); 774bb99794aSGuido Kiener spin_unlock_irqrestore(&file_data->err_lock, flags); 775bb99794aSGuido Kiener usb_anchor_urb(urb, &file_data->in_anchor); 776bb99794aSGuido Kiener 777bb99794aSGuido Kiener wake_up_interruptible(&file_data->wait_bulk_in); 778bb99794aSGuido Kiener wake_up_interruptible(&file_data->data->waitq); 779bb99794aSGuido Kiener } 780bb99794aSGuido Kiener 781bb99794aSGuido Kiener static inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data) 782bb99794aSGuido Kiener { 783bb99794aSGuido Kiener bool data_or_error; 784bb99794aSGuido Kiener 785bb99794aSGuido Kiener spin_lock_irq(&file_data->err_lock); 786bb99794aSGuido Kiener data_or_error = !usb_anchor_empty(&file_data->in_anchor) 787bb99794aSGuido Kiener || file_data->in_status; 788bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 789bb99794aSGuido Kiener dev_dbg(&file_data->data->intf->dev, "%s: returns %d\n", __func__, 790bb99794aSGuido Kiener data_or_error); 791bb99794aSGuido Kiener return data_or_error; 792bb99794aSGuido Kiener } 793bb99794aSGuido Kiener 794bb99794aSGuido Kiener static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, 795bb99794aSGuido Kiener void __user *user_buffer, 796bb99794aSGuido Kiener u32 transfer_size, 797bb99794aSGuido Kiener u32 *transferred, 798bb99794aSGuido Kiener u32 flags) 799bb99794aSGuido Kiener { 800bb99794aSGuido Kiener struct usbtmc_device_data *data = file_data->data; 801bb99794aSGuido Kiener struct device *dev = &data->intf->dev; 802bb99794aSGuido Kiener u32 done = 0; 803bb99794aSGuido Kiener u32 remaining; 804bb99794aSGuido Kiener const u32 bufsize = USBTMC_BUFSIZE; 805bb99794aSGuido Kiener int retval = 0; 806bb99794aSGuido Kiener u32 max_transfer_size; 807bb99794aSGuido Kiener unsigned long expire; 808bb99794aSGuido Kiener int bufcount = 1; 809bb99794aSGuido Kiener int again = 0; 810bb99794aSGuido Kiener 811bb99794aSGuido Kiener /* mutex already locked */ 812bb99794aSGuido Kiener 813bb99794aSGuido Kiener *transferred = done; 814bb99794aSGuido Kiener 815bb99794aSGuido Kiener max_transfer_size = transfer_size; 816bb99794aSGuido Kiener 817bb99794aSGuido Kiener if (flags & USBTMC_FLAG_IGNORE_TRAILER) { 818bb99794aSGuido Kiener /* The device may send extra alignment bytes (up to 819bb99794aSGuido Kiener * wMaxPacketSize – 1) to avoid sending a zero-length 820bb99794aSGuido Kiener * packet 821bb99794aSGuido Kiener */ 822bb99794aSGuido Kiener remaining = transfer_size; 823bb99794aSGuido Kiener if ((max_transfer_size % data->wMaxPacketSize) == 0) 824bb99794aSGuido Kiener max_transfer_size += (data->wMaxPacketSize - 1); 825bb99794aSGuido Kiener } else { 826bb99794aSGuido Kiener /* round down to bufsize to avoid truncated data left */ 827bb99794aSGuido Kiener if (max_transfer_size > bufsize) { 828bb99794aSGuido Kiener max_transfer_size = 829bb99794aSGuido Kiener roundup(max_transfer_size + 1 - bufsize, 830bb99794aSGuido Kiener bufsize); 831bb99794aSGuido Kiener } 832bb99794aSGuido Kiener remaining = max_transfer_size; 833bb99794aSGuido Kiener } 834bb99794aSGuido Kiener 835bb99794aSGuido Kiener spin_lock_irq(&file_data->err_lock); 836bb99794aSGuido Kiener 837bb99794aSGuido Kiener if (file_data->in_status) { 838bb99794aSGuido Kiener /* return the very first error */ 839bb99794aSGuido Kiener retval = file_data->in_status; 840bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 841bb99794aSGuido Kiener goto error; 842bb99794aSGuido Kiener } 843bb99794aSGuido Kiener 844bb99794aSGuido Kiener if (flags & USBTMC_FLAG_ASYNC) { 845bb99794aSGuido Kiener if (usb_anchor_empty(&file_data->in_anchor)) 846bb99794aSGuido Kiener again = 1; 847bb99794aSGuido Kiener 848bb99794aSGuido Kiener if (file_data->in_urbs_used == 0) { 849bb99794aSGuido Kiener file_data->in_transfer_size = 0; 850bb99794aSGuido Kiener file_data->in_status = 0; 851bb99794aSGuido Kiener } 852bb99794aSGuido Kiener } else { 853bb99794aSGuido Kiener file_data->in_transfer_size = 0; 854bb99794aSGuido Kiener file_data->in_status = 0; 855bb99794aSGuido Kiener } 856bb99794aSGuido Kiener 857bb99794aSGuido Kiener if (max_transfer_size == 0) { 858bb99794aSGuido Kiener bufcount = 0; 859bb99794aSGuido Kiener } else { 860bb99794aSGuido Kiener bufcount = roundup(max_transfer_size, bufsize) / bufsize; 861bb99794aSGuido Kiener if (bufcount > file_data->in_urbs_used) 862bb99794aSGuido Kiener bufcount -= file_data->in_urbs_used; 863bb99794aSGuido Kiener else 864bb99794aSGuido Kiener bufcount = 0; 865bb99794aSGuido Kiener 866bb99794aSGuido Kiener if (bufcount + file_data->in_urbs_used > MAX_URBS_IN_FLIGHT) { 867bb99794aSGuido Kiener bufcount = MAX_URBS_IN_FLIGHT - 868bb99794aSGuido Kiener file_data->in_urbs_used; 869bb99794aSGuido Kiener } 870bb99794aSGuido Kiener } 871bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 872bb99794aSGuido Kiener 873bb99794aSGuido Kiener dev_dbg(dev, "%s: requested=%u flags=0x%X size=%u bufs=%d used=%d\n", 874bb99794aSGuido Kiener __func__, transfer_size, flags, 875bb99794aSGuido Kiener max_transfer_size, bufcount, file_data->in_urbs_used); 876bb99794aSGuido Kiener 877bb99794aSGuido Kiener while (bufcount > 0) { 878bb99794aSGuido Kiener u8 *dmabuf = NULL; 879bb99794aSGuido Kiener struct urb *urb = usbtmc_create_urb(); 880bb99794aSGuido Kiener 881bb99794aSGuido Kiener if (!urb) { 882bb99794aSGuido Kiener retval = -ENOMEM; 883bb99794aSGuido Kiener goto error; 884bb99794aSGuido Kiener } 885bb99794aSGuido Kiener 886bb99794aSGuido Kiener dmabuf = urb->transfer_buffer; 887bb99794aSGuido Kiener 888bb99794aSGuido Kiener usb_fill_bulk_urb(urb, data->usb_dev, 889bb99794aSGuido Kiener usb_rcvbulkpipe(data->usb_dev, data->bulk_in), 890bb99794aSGuido Kiener dmabuf, bufsize, 891bb99794aSGuido Kiener usbtmc_read_bulk_cb, file_data); 892bb99794aSGuido Kiener 893bb99794aSGuido Kiener usb_anchor_urb(urb, &file_data->submitted); 894bb99794aSGuido Kiener retval = usb_submit_urb(urb, GFP_KERNEL); 895bb99794aSGuido Kiener /* urb is anchored. We can release our reference. */ 896bb99794aSGuido Kiener usb_free_urb(urb); 897bb99794aSGuido Kiener if (unlikely(retval)) { 898bb99794aSGuido Kiener usb_unanchor_urb(urb); 899bb99794aSGuido Kiener goto error; 900bb99794aSGuido Kiener } 901bb99794aSGuido Kiener file_data->in_urbs_used++; 902bb99794aSGuido Kiener bufcount--; 903bb99794aSGuido Kiener } 904bb99794aSGuido Kiener 905bb99794aSGuido Kiener if (again) { 906bb99794aSGuido Kiener dev_dbg(dev, "%s: ret=again\n", __func__); 907bb99794aSGuido Kiener return -EAGAIN; 908bb99794aSGuido Kiener } 909bb99794aSGuido Kiener 910bb99794aSGuido Kiener if (user_buffer == NULL) 911bb99794aSGuido Kiener return -EINVAL; 912bb99794aSGuido Kiener 913bb99794aSGuido Kiener expire = msecs_to_jiffies(file_data->timeout); 914bb99794aSGuido Kiener 915bb99794aSGuido Kiener while (max_transfer_size > 0) { 916bb99794aSGuido Kiener u32 this_part; 917bb99794aSGuido Kiener struct urb *urb = NULL; 918bb99794aSGuido Kiener 919bb99794aSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC)) { 920bb99794aSGuido Kiener dev_dbg(dev, "%s: before wait time %lu\n", 921bb99794aSGuido Kiener __func__, expire); 922bb99794aSGuido Kiener retval = wait_event_interruptible_timeout( 923bb99794aSGuido Kiener file_data->wait_bulk_in, 924bb99794aSGuido Kiener usbtmc_do_transfer(file_data), 925bb99794aSGuido Kiener expire); 926bb99794aSGuido Kiener 927bb99794aSGuido Kiener dev_dbg(dev, "%s: wait returned %d\n", 928bb99794aSGuido Kiener __func__, retval); 929bb99794aSGuido Kiener 930bb99794aSGuido Kiener if (retval <= 0) { 931bb99794aSGuido Kiener if (retval == 0) 932bb99794aSGuido Kiener retval = -ETIMEDOUT; 933bb99794aSGuido Kiener goto error; 934bb99794aSGuido Kiener } 935bb99794aSGuido Kiener } 936bb99794aSGuido Kiener 937bb99794aSGuido Kiener urb = usb_get_from_anchor(&file_data->in_anchor); 938bb99794aSGuido Kiener if (!urb) { 939bb99794aSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC)) { 940bb99794aSGuido Kiener /* synchronous case: must not happen */ 941bb99794aSGuido Kiener retval = -EFAULT; 942bb99794aSGuido Kiener goto error; 943bb99794aSGuido Kiener } 944bb99794aSGuido Kiener 945bb99794aSGuido Kiener /* asynchronous case: ready, do not block or wait */ 946bb99794aSGuido Kiener *transferred = done; 947bb99794aSGuido Kiener dev_dbg(dev, "%s: (async) done=%u ret=0\n", 948bb99794aSGuido Kiener __func__, done); 949bb99794aSGuido Kiener return 0; 950bb99794aSGuido Kiener } 951bb99794aSGuido Kiener 952bb99794aSGuido Kiener file_data->in_urbs_used--; 953bb99794aSGuido Kiener 954bb99794aSGuido Kiener if (max_transfer_size > urb->actual_length) 955bb99794aSGuido Kiener max_transfer_size -= urb->actual_length; 956bb99794aSGuido Kiener else 957bb99794aSGuido Kiener max_transfer_size = 0; 958bb99794aSGuido Kiener 959bb99794aSGuido Kiener if (remaining > urb->actual_length) 960bb99794aSGuido Kiener this_part = urb->actual_length; 961bb99794aSGuido Kiener else 962bb99794aSGuido Kiener this_part = remaining; 963bb99794aSGuido Kiener 964bb99794aSGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1, 965bb99794aSGuido Kiener urb->transfer_buffer, urb->actual_length, true); 966bb99794aSGuido Kiener 967bb99794aSGuido Kiener if (copy_to_user(user_buffer + done, 968bb99794aSGuido Kiener urb->transfer_buffer, this_part)) { 969bb99794aSGuido Kiener usb_free_urb(urb); 970bb99794aSGuido Kiener retval = -EFAULT; 971bb99794aSGuido Kiener goto error; 972bb99794aSGuido Kiener } 973bb99794aSGuido Kiener 974bb99794aSGuido Kiener remaining -= this_part; 975bb99794aSGuido Kiener done += this_part; 976bb99794aSGuido Kiener 977bb99794aSGuido Kiener spin_lock_irq(&file_data->err_lock); 978bb99794aSGuido Kiener if (urb->status) { 979bb99794aSGuido Kiener /* return the very first error */ 980bb99794aSGuido Kiener retval = file_data->in_status; 981bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 982bb99794aSGuido Kiener usb_free_urb(urb); 983bb99794aSGuido Kiener goto error; 984bb99794aSGuido Kiener } 985bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 986bb99794aSGuido Kiener 987bb99794aSGuido Kiener if (urb->actual_length < bufsize) { 988bb99794aSGuido Kiener /* short packet or ZLP received => ready */ 989bb99794aSGuido Kiener usb_free_urb(urb); 990bb99794aSGuido Kiener retval = 1; 991bb99794aSGuido Kiener break; 992bb99794aSGuido Kiener } 993bb99794aSGuido Kiener 994bb99794aSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC) && 995bb99794aSGuido Kiener max_transfer_size > (bufsize * file_data->in_urbs_used)) { 996bb99794aSGuido Kiener /* resubmit, since other buffers still not enough */ 997bb99794aSGuido Kiener usb_anchor_urb(urb, &file_data->submitted); 998bb99794aSGuido Kiener retval = usb_submit_urb(urb, GFP_KERNEL); 999bb99794aSGuido Kiener if (unlikely(retval)) { 1000bb99794aSGuido Kiener usb_unanchor_urb(urb); 1001bb99794aSGuido Kiener usb_free_urb(urb); 1002bb99794aSGuido Kiener goto error; 1003bb99794aSGuido Kiener } 1004bb99794aSGuido Kiener file_data->in_urbs_used++; 1005bb99794aSGuido Kiener } 1006bb99794aSGuido Kiener usb_free_urb(urb); 1007bb99794aSGuido Kiener retval = 0; 1008bb99794aSGuido Kiener } 1009bb99794aSGuido Kiener 1010bb99794aSGuido Kiener error: 1011bb99794aSGuido Kiener *transferred = done; 1012bb99794aSGuido Kiener 1013bb99794aSGuido Kiener dev_dbg(dev, "%s: before kill\n", __func__); 1014bb99794aSGuido Kiener /* Attention: killing urbs can take long time (2 ms) */ 1015bb99794aSGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 1016bb99794aSGuido Kiener dev_dbg(dev, "%s: after kill\n", __func__); 1017bb99794aSGuido Kiener usb_scuttle_anchored_urbs(&file_data->in_anchor); 1018bb99794aSGuido Kiener file_data->in_urbs_used = 0; 1019bb99794aSGuido Kiener file_data->in_status = 0; /* no spinlock needed here */ 1020bb99794aSGuido Kiener dev_dbg(dev, "%s: done=%u ret=%d\n", __func__, done, retval); 1021bb99794aSGuido Kiener 1022bb99794aSGuido Kiener return retval; 1023bb99794aSGuido Kiener } 1024bb99794aSGuido Kiener 1025bb99794aSGuido Kiener static ssize_t usbtmc_ioctl_generic_read(struct usbtmc_file_data *file_data, 1026bb99794aSGuido Kiener void __user *arg) 1027bb99794aSGuido Kiener { 1028bb99794aSGuido Kiener struct usbtmc_message msg; 1029bb99794aSGuido Kiener ssize_t retval = 0; 1030bb99794aSGuido Kiener 1031bb99794aSGuido Kiener /* mutex already locked */ 1032bb99794aSGuido Kiener 1033bb99794aSGuido Kiener if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message))) 1034bb99794aSGuido Kiener return -EFAULT; 1035bb99794aSGuido Kiener 1036bb99794aSGuido Kiener retval = usbtmc_generic_read(file_data, msg.message, 1037bb99794aSGuido Kiener msg.transfer_size, &msg.transferred, 1038bb99794aSGuido Kiener msg.flags); 1039bb99794aSGuido Kiener 1040bb99794aSGuido Kiener if (put_user(msg.transferred, 1041bb99794aSGuido Kiener &((struct usbtmc_message __user *)arg)->transferred)) 1042bb99794aSGuido Kiener return -EFAULT; 1043bb99794aSGuido Kiener 1044bb99794aSGuido Kiener return retval; 1045bb99794aSGuido Kiener } 1046bb99794aSGuido Kiener 10474ddc645fSGuido Kiener static void usbtmc_write_bulk_cb(struct urb *urb) 10484ddc645fSGuido Kiener { 10494ddc645fSGuido Kiener struct usbtmc_file_data *file_data = urb->context; 10504ddc645fSGuido Kiener int wakeup = 0; 10514ddc645fSGuido Kiener unsigned long flags; 10524ddc645fSGuido Kiener 10534ddc645fSGuido Kiener spin_lock_irqsave(&file_data->err_lock, flags); 10544ddc645fSGuido Kiener file_data->out_transfer_size += urb->actual_length; 10554ddc645fSGuido Kiener 10564ddc645fSGuido Kiener /* sync/async unlink faults aren't errors */ 10574ddc645fSGuido Kiener if (urb->status) { 10584ddc645fSGuido Kiener if (!(urb->status == -ENOENT || 10594ddc645fSGuido Kiener urb->status == -ECONNRESET || 10604ddc645fSGuido Kiener urb->status == -ESHUTDOWN)) 10614ddc645fSGuido Kiener dev_err(&file_data->data->intf->dev, 10624ddc645fSGuido Kiener "%s - nonzero write bulk status received: %d\n", 10634ddc645fSGuido Kiener __func__, urb->status); 10644ddc645fSGuido Kiener 10654ddc645fSGuido Kiener if (!file_data->out_status) { 10664ddc645fSGuido Kiener file_data->out_status = urb->status; 10674ddc645fSGuido Kiener wakeup = 1; 10684ddc645fSGuido Kiener } 10694ddc645fSGuido Kiener } 10704ddc645fSGuido Kiener spin_unlock_irqrestore(&file_data->err_lock, flags); 10714ddc645fSGuido Kiener 10724ddc645fSGuido Kiener dev_dbg(&file_data->data->intf->dev, 10734ddc645fSGuido Kiener "%s - write bulk total size: %u\n", 10744ddc645fSGuido Kiener __func__, file_data->out_transfer_size); 10754ddc645fSGuido Kiener 10764ddc645fSGuido Kiener up(&file_data->limit_write_sem); 10774ddc645fSGuido Kiener if (usb_anchor_empty(&file_data->submitted) || wakeup) 10784ddc645fSGuido Kiener wake_up_interruptible(&file_data->data->waitq); 10794ddc645fSGuido Kiener } 10804ddc645fSGuido Kiener 10814ddc645fSGuido Kiener static ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data, 10824ddc645fSGuido Kiener const void __user *user_buffer, 10834ddc645fSGuido Kiener u32 transfer_size, 10844ddc645fSGuido Kiener u32 *transferred, 10854ddc645fSGuido Kiener u32 flags) 10864ddc645fSGuido Kiener { 10874ddc645fSGuido Kiener struct usbtmc_device_data *data = file_data->data; 10884ddc645fSGuido Kiener struct device *dev; 10894ddc645fSGuido Kiener u32 done = 0; 10904ddc645fSGuido Kiener u32 remaining; 10914ddc645fSGuido Kiener unsigned long expire; 10924ddc645fSGuido Kiener const u32 bufsize = USBTMC_BUFSIZE; 10934ddc645fSGuido Kiener struct urb *urb = NULL; 10944ddc645fSGuido Kiener int retval = 0; 10954ddc645fSGuido Kiener u32 timeout; 10964ddc645fSGuido Kiener 10974ddc645fSGuido Kiener *transferred = 0; 10984ddc645fSGuido Kiener 10994ddc645fSGuido Kiener /* Get pointer to private data structure */ 11004ddc645fSGuido Kiener dev = &data->intf->dev; 11014ddc645fSGuido Kiener 11024ddc645fSGuido Kiener dev_dbg(dev, "%s: size=%u flags=0x%X sema=%u\n", 11034ddc645fSGuido Kiener __func__, transfer_size, flags, 11044ddc645fSGuido Kiener file_data->limit_write_sem.count); 11054ddc645fSGuido Kiener 11064ddc645fSGuido Kiener if (flags & USBTMC_FLAG_APPEND) { 11074ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 11084ddc645fSGuido Kiener retval = file_data->out_status; 11094ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 11104ddc645fSGuido Kiener if (retval < 0) 11114ddc645fSGuido Kiener return retval; 11124ddc645fSGuido Kiener } else { 11134ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 11144ddc645fSGuido Kiener file_data->out_transfer_size = 0; 11154ddc645fSGuido Kiener file_data->out_status = 0; 11164ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 11174ddc645fSGuido Kiener } 11184ddc645fSGuido Kiener 11194ddc645fSGuido Kiener remaining = transfer_size; 11204ddc645fSGuido Kiener if (remaining > INT_MAX) 11214ddc645fSGuido Kiener remaining = INT_MAX; 11224ddc645fSGuido Kiener 11234ddc645fSGuido Kiener timeout = file_data->timeout; 11244ddc645fSGuido Kiener expire = msecs_to_jiffies(timeout); 11254ddc645fSGuido Kiener 11264ddc645fSGuido Kiener while (remaining > 0) { 11274ddc645fSGuido Kiener u32 this_part, aligned; 11284ddc645fSGuido Kiener u8 *buffer = NULL; 11294ddc645fSGuido Kiener 11304ddc645fSGuido Kiener if (flags & USBTMC_FLAG_ASYNC) { 11314ddc645fSGuido Kiener if (down_trylock(&file_data->limit_write_sem)) { 11324ddc645fSGuido Kiener retval = (done)?(0):(-EAGAIN); 11334ddc645fSGuido Kiener goto exit; 11344ddc645fSGuido Kiener } 11354ddc645fSGuido Kiener } else { 11364ddc645fSGuido Kiener retval = down_timeout(&file_data->limit_write_sem, 11374ddc645fSGuido Kiener expire); 11384ddc645fSGuido Kiener if (retval < 0) { 11394ddc645fSGuido Kiener retval = -ETIMEDOUT; 11404ddc645fSGuido Kiener goto error; 11414ddc645fSGuido Kiener } 11424ddc645fSGuido Kiener } 11434ddc645fSGuido Kiener 11444ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 11454ddc645fSGuido Kiener retval = file_data->out_status; 11464ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 11474ddc645fSGuido Kiener if (retval < 0) { 11484ddc645fSGuido Kiener up(&file_data->limit_write_sem); 11494ddc645fSGuido Kiener goto error; 11504ddc645fSGuido Kiener } 11514ddc645fSGuido Kiener 11524ddc645fSGuido Kiener /* prepare next urb to send */ 11534ddc645fSGuido Kiener urb = usbtmc_create_urb(); 11544ddc645fSGuido Kiener if (!urb) { 11554ddc645fSGuido Kiener retval = -ENOMEM; 11564ddc645fSGuido Kiener up(&file_data->limit_write_sem); 11574ddc645fSGuido Kiener goto error; 11584ddc645fSGuido Kiener } 11594ddc645fSGuido Kiener buffer = urb->transfer_buffer; 11604ddc645fSGuido Kiener 11614ddc645fSGuido Kiener if (remaining > bufsize) 11624ddc645fSGuido Kiener this_part = bufsize; 11634ddc645fSGuido Kiener else 11644ddc645fSGuido Kiener this_part = remaining; 11654ddc645fSGuido Kiener 11664ddc645fSGuido Kiener if (copy_from_user(buffer, user_buffer + done, this_part)) { 11674ddc645fSGuido Kiener retval = -EFAULT; 11684ddc645fSGuido Kiener up(&file_data->limit_write_sem); 11694ddc645fSGuido Kiener goto error; 11704ddc645fSGuido Kiener } 11714ddc645fSGuido Kiener 11724ddc645fSGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 11734ddc645fSGuido Kiener 16, 1, buffer, this_part, true); 11744ddc645fSGuido Kiener 11754ddc645fSGuido Kiener /* fill bulk with 32 bit alignment to meet USBTMC specification 11764ddc645fSGuido Kiener * (size + 3 & ~3) rounds up and simplifies user code 11774ddc645fSGuido Kiener */ 11784ddc645fSGuido Kiener aligned = (this_part + 3) & ~3; 11794ddc645fSGuido Kiener dev_dbg(dev, "write(size:%u align:%u done:%u)\n", 11804ddc645fSGuido Kiener (unsigned int)this_part, 11814ddc645fSGuido Kiener (unsigned int)aligned, 11824ddc645fSGuido Kiener (unsigned int)done); 11834ddc645fSGuido Kiener 11844ddc645fSGuido Kiener usb_fill_bulk_urb(urb, data->usb_dev, 11854ddc645fSGuido Kiener usb_sndbulkpipe(data->usb_dev, data->bulk_out), 11864ddc645fSGuido Kiener urb->transfer_buffer, aligned, 11874ddc645fSGuido Kiener usbtmc_write_bulk_cb, file_data); 11884ddc645fSGuido Kiener 11894ddc645fSGuido Kiener usb_anchor_urb(urb, &file_data->submitted); 11904ddc645fSGuido Kiener retval = usb_submit_urb(urb, GFP_KERNEL); 11914ddc645fSGuido Kiener if (unlikely(retval)) { 11924ddc645fSGuido Kiener usb_unanchor_urb(urb); 11934ddc645fSGuido Kiener up(&file_data->limit_write_sem); 11944ddc645fSGuido Kiener goto error; 11954ddc645fSGuido Kiener } 11964ddc645fSGuido Kiener 11974ddc645fSGuido Kiener usb_free_urb(urb); 11984ddc645fSGuido Kiener urb = NULL; /* urb will be finally released by usb driver */ 11994ddc645fSGuido Kiener 12004ddc645fSGuido Kiener remaining -= this_part; 12014ddc645fSGuido Kiener done += this_part; 12024ddc645fSGuido Kiener } 12034ddc645fSGuido Kiener 12044ddc645fSGuido Kiener /* All urbs are on the fly */ 12054ddc645fSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC)) { 12064ddc645fSGuido Kiener if (!usb_wait_anchor_empty_timeout(&file_data->submitted, 12074ddc645fSGuido Kiener timeout)) { 12084ddc645fSGuido Kiener retval = -ETIMEDOUT; 12094ddc645fSGuido Kiener goto error; 12104ddc645fSGuido Kiener } 12114ddc645fSGuido Kiener } 12124ddc645fSGuido Kiener 12134ddc645fSGuido Kiener retval = 0; 12144ddc645fSGuido Kiener goto exit; 12154ddc645fSGuido Kiener 12164ddc645fSGuido Kiener error: 12174ddc645fSGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 12184ddc645fSGuido Kiener exit: 12194ddc645fSGuido Kiener usb_free_urb(urb); 12204ddc645fSGuido Kiener 12214ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 12224ddc645fSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC)) 12234ddc645fSGuido Kiener done = file_data->out_transfer_size; 12244ddc645fSGuido Kiener if (!retval && file_data->out_status) 12254ddc645fSGuido Kiener retval = file_data->out_status; 12264ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 12274ddc645fSGuido Kiener 12284ddc645fSGuido Kiener *transferred = done; 12294ddc645fSGuido Kiener 12304ddc645fSGuido Kiener dev_dbg(dev, "%s: done=%u, retval=%d, urbstat=%d\n", 12314ddc645fSGuido Kiener __func__, done, retval, file_data->out_status); 12324ddc645fSGuido Kiener 12334ddc645fSGuido Kiener return retval; 12344ddc645fSGuido Kiener } 12354ddc645fSGuido Kiener 12364ddc645fSGuido Kiener static ssize_t usbtmc_ioctl_generic_write(struct usbtmc_file_data *file_data, 12374ddc645fSGuido Kiener void __user *arg) 12384ddc645fSGuido Kiener { 12394ddc645fSGuido Kiener struct usbtmc_message msg; 12404ddc645fSGuido Kiener ssize_t retval = 0; 12414ddc645fSGuido Kiener 12424ddc645fSGuido Kiener /* mutex already locked */ 12434ddc645fSGuido Kiener 12444ddc645fSGuido Kiener if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message))) 12454ddc645fSGuido Kiener return -EFAULT; 12464ddc645fSGuido Kiener 12474ddc645fSGuido Kiener retval = usbtmc_generic_write(file_data, msg.message, 12484ddc645fSGuido Kiener msg.transfer_size, &msg.transferred, 12494ddc645fSGuido Kiener msg.flags); 12504ddc645fSGuido Kiener 12514ddc645fSGuido Kiener if (put_user(msg.transferred, 12524ddc645fSGuido Kiener &((struct usbtmc_message __user *)arg)->transferred)) 12534ddc645fSGuido Kiener return -EFAULT; 12544ddc645fSGuido Kiener 12554ddc645fSGuido Kiener return retval; 12564ddc645fSGuido Kiener } 12574ddc645fSGuido Kiener 1258fe78a7c6SGuido Kiener /* 1259b1498451SGuido Kiener * Get the generic write result 1260b1498451SGuido Kiener */ 1261b1498451SGuido Kiener static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data, 1262b1498451SGuido Kiener void __user *arg) 1263b1498451SGuido Kiener { 1264b1498451SGuido Kiener u32 transferred; 1265b1498451SGuido Kiener int retval; 1266b1498451SGuido Kiener 1267b1498451SGuido Kiener spin_lock_irq(&file_data->err_lock); 1268b1498451SGuido Kiener transferred = file_data->out_transfer_size; 1269b1498451SGuido Kiener retval = file_data->out_status; 1270b1498451SGuido Kiener spin_unlock_irq(&file_data->err_lock); 1271b1498451SGuido Kiener 1272b1498451SGuido Kiener if (put_user(transferred, (__u32 __user *)arg)) 1273b1498451SGuido Kiener return -EFAULT; 1274b1498451SGuido Kiener 1275b1498451SGuido Kiener return retval; 1276b1498451SGuido Kiener } 1277b1498451SGuido Kiener 1278b1498451SGuido Kiener /* 127988aecde4SDave Penkler * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint. 128088d9b2b3SAlexandre Peixoto Ferreira * @transfer_size: number of bytes to request from the device. 128188d9b2b3SAlexandre Peixoto Ferreira * 128288d9b2b3SAlexandre Peixoto Ferreira * See the USBTMC specification, Table 4. 128388d9b2b3SAlexandre Peixoto Ferreira * 128488d9b2b3SAlexandre Peixoto Ferreira * Also updates bTag_last_write. 128588d9b2b3SAlexandre Peixoto Ferreira */ 1286048c6d88SGuido Kiener static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data, 1287d7604ff0SGuido Kiener u32 transfer_size) 128888d9b2b3SAlexandre Peixoto Ferreira { 1289048c6d88SGuido Kiener struct usbtmc_device_data *data = file_data->data; 129088d9b2b3SAlexandre Peixoto Ferreira int retval; 1291d846b765SOliver Neukum u8 *buffer; 129288d9b2b3SAlexandre Peixoto Ferreira int actual; 129388d9b2b3SAlexandre Peixoto Ferreira 1294d846b765SOliver Neukum buffer = kmalloc(USBTMC_HEADER_SIZE, GFP_KERNEL); 1295d846b765SOliver Neukum if (!buffer) 1296d846b765SOliver Neukum return -ENOMEM; 129788d9b2b3SAlexandre Peixoto Ferreira /* Setup IO buffer for REQUEST_DEV_DEP_MSG_IN message 129888d9b2b3SAlexandre Peixoto Ferreira * Refer to class specs for details 129988d9b2b3SAlexandre Peixoto Ferreira */ 130088d9b2b3SAlexandre Peixoto Ferreira buffer[0] = 2; 130188d9b2b3SAlexandre Peixoto Ferreira buffer[1] = data->bTag; 1302bbf4976eSAndy Shevchenko buffer[2] = ~data->bTag; 130388d9b2b3SAlexandre Peixoto Ferreira buffer[3] = 0; /* Reserved */ 1304bbf4976eSAndy Shevchenko buffer[4] = transfer_size >> 0; 1305bbf4976eSAndy Shevchenko buffer[5] = transfer_size >> 8; 1306bbf4976eSAndy Shevchenko buffer[6] = transfer_size >> 16; 1307bbf4976eSAndy Shevchenko buffer[7] = transfer_size >> 24; 130812dcaeb7SGuido Kiener buffer[8] = file_data->term_char_enabled * 2; 130988d9b2b3SAlexandre Peixoto Ferreira /* Use term character? */ 131012dcaeb7SGuido Kiener buffer[9] = file_data->term_char; 131188d9b2b3SAlexandre Peixoto Ferreira buffer[10] = 0; /* Reserved */ 131288d9b2b3SAlexandre Peixoto Ferreira buffer[11] = 0; /* Reserved */ 131388d9b2b3SAlexandre Peixoto Ferreira 131488d9b2b3SAlexandre Peixoto Ferreira /* Send bulk URB */ 131588d9b2b3SAlexandre Peixoto Ferreira retval = usb_bulk_msg(data->usb_dev, 131688d9b2b3SAlexandre Peixoto Ferreira usb_sndbulkpipe(data->usb_dev, 131788d9b2b3SAlexandre Peixoto Ferreira data->bulk_out), 1318048c6d88SGuido Kiener buffer, USBTMC_HEADER_SIZE, 1319048c6d88SGuido Kiener &actual, file_data->timeout); 132088d9b2b3SAlexandre Peixoto Ferreira 132188d9b2b3SAlexandre Peixoto Ferreira /* Store bTag (in case we need to abort) */ 132288d9b2b3SAlexandre Peixoto Ferreira data->bTag_last_write = data->bTag; 132388d9b2b3SAlexandre Peixoto Ferreira 132488d9b2b3SAlexandre Peixoto Ferreira /* Increment bTag -- and increment again if zero */ 132588d9b2b3SAlexandre Peixoto Ferreira data->bTag++; 132688d9b2b3SAlexandre Peixoto Ferreira if (!data->bTag) 1327bbf4976eSAndy Shevchenko data->bTag++; 132888d9b2b3SAlexandre Peixoto Ferreira 1329d846b765SOliver Neukum kfree(buffer); 1330d7604ff0SGuido Kiener if (retval < 0) 1331d7604ff0SGuido Kiener dev_err(&data->intf->dev, "%s returned %d\n", 1332d7604ff0SGuido Kiener __func__, retval); 133388d9b2b3SAlexandre Peixoto Ferreira 1334d7604ff0SGuido Kiener return retval; 133588d9b2b3SAlexandre Peixoto Ferreira } 133688d9b2b3SAlexandre Peixoto Ferreira 13375b775f67SGreg Kroah-Hartman static ssize_t usbtmc_read(struct file *filp, char __user *buf, 13385b775f67SGreg Kroah-Hartman size_t count, loff_t *f_pos) 13395b775f67SGreg Kroah-Hartman { 13404f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data; 13415b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 13425b775f67SGreg Kroah-Hartman struct device *dev; 1343d7604ff0SGuido Kiener const u32 bufsize = USBTMC_BUFSIZE; 1344665d7662SGuus Sliepen u32 n_characters; 13455b775f67SGreg Kroah-Hartman u8 *buffer; 13465b775f67SGreg Kroah-Hartman int actual; 1347d7604ff0SGuido Kiener u32 done = 0; 1348d7604ff0SGuido Kiener u32 remaining; 13495b775f67SGreg Kroah-Hartman int retval; 13505b775f67SGreg Kroah-Hartman 13515b775f67SGreg Kroah-Hartman /* Get pointer to private data structure */ 13524f3c8d6eSGuido Kiener file_data = filp->private_data; 13534f3c8d6eSGuido Kiener data = file_data->data; 13545b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 13555b775f67SGreg Kroah-Hartman 1356d7604ff0SGuido Kiener buffer = kmalloc(bufsize, GFP_KERNEL); 13575b775f67SGreg Kroah-Hartman if (!buffer) 13585b775f67SGreg Kroah-Hartman return -ENOMEM; 13595b775f67SGreg Kroah-Hartman 13605b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 136186286883SOliver Neukum if (data->zombie) { 136286286883SOliver Neukum retval = -ENODEV; 136386286883SOliver Neukum goto exit; 136486286883SOliver Neukum } 13655b775f67SGreg Kroah-Hartman 1366d7604ff0SGuido Kiener if (count > INT_MAX) 1367d7604ff0SGuido Kiener count = INT_MAX; 1368d7604ff0SGuido Kiener 1369d7604ff0SGuido Kiener dev_dbg(dev, "%s(count:%zu)\n", __func__, count); 1370d2ddce37SAlexandre Peixoto Ferreira 1371048c6d88SGuido Kiener retval = send_request_dev_dep_msg_in(file_data, count); 1372d2ddce37SAlexandre Peixoto Ferreira 1373d2ddce37SAlexandre Peixoto Ferreira if (retval < 0) { 1374ec34d08eSGuido Kiener if (file_data->auto_abort) 1375d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_out(data); 1376d2ddce37SAlexandre Peixoto Ferreira goto exit; 1377d2ddce37SAlexandre Peixoto Ferreira } 1378d2ddce37SAlexandre Peixoto Ferreira 1379d2ddce37SAlexandre Peixoto Ferreira /* Loop until we have fetched everything we requested */ 13805b775f67SGreg Kroah-Hartman remaining = count; 13815b775f67SGreg Kroah-Hartman 13825b775f67SGreg Kroah-Hartman /* Send bulk URB */ 13835b775f67SGreg Kroah-Hartman retval = usb_bulk_msg(data->usb_dev, 13845b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 13855b775f67SGreg Kroah-Hartman data->bulk_in), 1386d7604ff0SGuido Kiener buffer, bufsize, &actual, 1387048c6d88SGuido Kiener file_data->timeout); 13885b775f67SGreg Kroah-Hartman 1389d7604ff0SGuido Kiener dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n", 1390d7604ff0SGuido Kiener __func__, retval, actual); 1391d2ddce37SAlexandre Peixoto Ferreira 13925b775f67SGreg Kroah-Hartman /* Store bTag (in case we need to abort) */ 13935b775f67SGreg Kroah-Hartman data->bTag_last_read = data->bTag; 13945b775f67SGreg Kroah-Hartman 13955b775f67SGreg Kroah-Hartman if (retval < 0) { 1396ec34d08eSGuido Kiener if (file_data->auto_abort) 1397d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_in(data); 1398d2ddce37SAlexandre Peixoto Ferreira goto exit; 1399d2ddce37SAlexandre Peixoto Ferreira } 1400d2ddce37SAlexandre Peixoto Ferreira 1401d2ddce37SAlexandre Peixoto Ferreira /* Sanity checks for the header */ 1402d2ddce37SAlexandre Peixoto Ferreira if (actual < USBTMC_HEADER_SIZE) { 1403d7604ff0SGuido Kiener dev_err(dev, "Device sent too small first packet: %u < %u\n", 1404d7604ff0SGuido Kiener actual, USBTMC_HEADER_SIZE); 1405ec34d08eSGuido Kiener if (file_data->auto_abort) 1406d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_in(data); 1407d2ddce37SAlexandre Peixoto Ferreira goto exit; 1408d2ddce37SAlexandre Peixoto Ferreira } 1409d2ddce37SAlexandre Peixoto Ferreira 1410d2ddce37SAlexandre Peixoto Ferreira if (buffer[0] != 2) { 1411d7604ff0SGuido Kiener dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", 1412d7604ff0SGuido Kiener buffer[0]); 1413ec34d08eSGuido Kiener if (file_data->auto_abort) 1414d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_in(data); 1415d2ddce37SAlexandre Peixoto Ferreira goto exit; 1416d2ddce37SAlexandre Peixoto Ferreira } 1417d2ddce37SAlexandre Peixoto Ferreira 1418d2ddce37SAlexandre Peixoto Ferreira if (buffer[1] != data->bTag_last_write) { 1419d7604ff0SGuido Kiener dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", 1420d7604ff0SGuido Kiener buffer[1], data->bTag_last_write); 1421ec34d08eSGuido Kiener if (file_data->auto_abort) 14225b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_in(data); 14235b775f67SGreg Kroah-Hartman goto exit; 14245b775f67SGreg Kroah-Hartman } 14255b775f67SGreg Kroah-Hartman 14265b775f67SGreg Kroah-Hartman /* How many characters did the instrument send? */ 14275b775f67SGreg Kroah-Hartman n_characters = buffer[4] + 14285b775f67SGreg Kroah-Hartman (buffer[5] << 8) + 14295b775f67SGreg Kroah-Hartman (buffer[6] << 16) + 14305b775f67SGreg Kroah-Hartman (buffer[7] << 24); 14315b775f67SGreg Kroah-Hartman 14328409e96fSGuido Kiener file_data->bmTransferAttributes = buffer[8]; 14338409e96fSGuido Kiener 1434d7604ff0SGuido Kiener dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", 1435d7604ff0SGuido Kiener n_characters, buffer[8]); 1436d7604ff0SGuido Kiener 1437d7604ff0SGuido Kiener if (n_characters > remaining) { 1438d7604ff0SGuido Kiener dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", 1439d7604ff0SGuido Kiener n_characters, count); 1440ec34d08eSGuido Kiener if (file_data->auto_abort) 1441d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_in(data); 1442d2ddce37SAlexandre Peixoto Ferreira goto exit; 1443665d7662SGuus Sliepen } 1444665d7662SGuus Sliepen 1445d7604ff0SGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 1446d7604ff0SGuido Kiener 16, 1, buffer, actual, true); 1447d7604ff0SGuido Kiener 1448d7604ff0SGuido Kiener remaining = n_characters; 1449d7604ff0SGuido Kiener 1450d2ddce37SAlexandre Peixoto Ferreira /* Remove the USBTMC header */ 1451d2ddce37SAlexandre Peixoto Ferreira actual -= USBTMC_HEADER_SIZE; 1452d2ddce37SAlexandre Peixoto Ferreira 1453d2ddce37SAlexandre Peixoto Ferreira /* Remove padding if it exists */ 1454d2ddce37SAlexandre Peixoto Ferreira if (actual > remaining) 1455d2ddce37SAlexandre Peixoto Ferreira actual = remaining; 1456d2ddce37SAlexandre Peixoto Ferreira 1457d2ddce37SAlexandre Peixoto Ferreira remaining -= actual; 1458d2ddce37SAlexandre Peixoto Ferreira 14595b775f67SGreg Kroah-Hartman /* Copy buffer to user space */ 1460d7604ff0SGuido Kiener if (copy_to_user(buf, &buffer[USBTMC_HEADER_SIZE], actual)) { 14615b775f67SGreg Kroah-Hartman /* There must have been an addressing problem */ 14625b775f67SGreg Kroah-Hartman retval = -EFAULT; 14635b775f67SGreg Kroah-Hartman goto exit; 14645b775f67SGreg Kroah-Hartman } 14655b775f67SGreg Kroah-Hartman 1466d7604ff0SGuido Kiener if ((actual + USBTMC_HEADER_SIZE) == bufsize) { 1467d7604ff0SGuido Kiener retval = usbtmc_generic_read(file_data, buf + actual, 1468d7604ff0SGuido Kiener remaining, 1469d7604ff0SGuido Kiener &done, 1470d7604ff0SGuido Kiener USBTMC_FLAG_IGNORE_TRAILER); 1471d7604ff0SGuido Kiener if (retval < 0) 1472d2ddce37SAlexandre Peixoto Ferreira goto exit; 1473d2ddce37SAlexandre Peixoto Ferreira } 1474d2ddce37SAlexandre Peixoto Ferreira done += actual; 14755b775f67SGreg Kroah-Hartman 14765b775f67SGreg Kroah-Hartman /* Update file position value */ 14775b775f67SGreg Kroah-Hartman *f_pos = *f_pos + done; 14785b775f67SGreg Kroah-Hartman retval = done; 14795b775f67SGreg Kroah-Hartman 14805b775f67SGreg Kroah-Hartman exit: 14815b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 14825b775f67SGreg Kroah-Hartman kfree(buffer); 14835b775f67SGreg Kroah-Hartman return retval; 14845b775f67SGreg Kroah-Hartman } 14855b775f67SGreg Kroah-Hartman 14865b775f67SGreg Kroah-Hartman static ssize_t usbtmc_write(struct file *filp, const char __user *buf, 14875b775f67SGreg Kroah-Hartman size_t count, loff_t *f_pos) 14885b775f67SGreg Kroah-Hartman { 14894f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data; 14905b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 14914d5e18d9SGuido Kiener struct urb *urb = NULL; 14924d5e18d9SGuido Kiener ssize_t retval = 0; 14935b775f67SGreg Kroah-Hartman u8 *buffer; 14944d5e18d9SGuido Kiener u32 remaining, done; 14954d5e18d9SGuido Kiener u32 transfersize, aligned, buflen; 14965b775f67SGreg Kroah-Hartman 14974f3c8d6eSGuido Kiener file_data = filp->private_data; 14984f3c8d6eSGuido Kiener data = file_data->data; 14995b775f67SGreg Kroah-Hartman 15005b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 15014d5e18d9SGuido Kiener 150286286883SOliver Neukum if (data->zombie) { 150386286883SOliver Neukum retval = -ENODEV; 150486286883SOliver Neukum goto exit; 150586286883SOliver Neukum } 15065b775f67SGreg Kroah-Hartman 15075b775f67SGreg Kroah-Hartman done = 0; 15085b775f67SGreg Kroah-Hartman 15094d5e18d9SGuido Kiener spin_lock_irq(&file_data->err_lock); 15104d5e18d9SGuido Kiener file_data->out_transfer_size = 0; 15114d5e18d9SGuido Kiener file_data->out_status = 0; 15124d5e18d9SGuido Kiener spin_unlock_irq(&file_data->err_lock); 15134d5e18d9SGuido Kiener 15144d5e18d9SGuido Kiener if (!count) 15154d5e18d9SGuido Kiener goto exit; 15164d5e18d9SGuido Kiener 15174d5e18d9SGuido Kiener if (down_trylock(&file_data->limit_write_sem)) { 15184d5e18d9SGuido Kiener /* previous calls were async */ 15194d5e18d9SGuido Kiener retval = -EBUSY; 15204d5e18d9SGuido Kiener goto exit; 15214d5e18d9SGuido Kiener } 15224d5e18d9SGuido Kiener 15234d5e18d9SGuido Kiener urb = usbtmc_create_urb(); 15244d5e18d9SGuido Kiener if (!urb) { 15254d5e18d9SGuido Kiener retval = -ENOMEM; 15264d5e18d9SGuido Kiener up(&file_data->limit_write_sem); 15274d5e18d9SGuido Kiener goto exit; 15284d5e18d9SGuido Kiener } 15294d5e18d9SGuido Kiener 15304d5e18d9SGuido Kiener buffer = urb->transfer_buffer; 15314d5e18d9SGuido Kiener buflen = urb->transfer_buffer_length; 15324d5e18d9SGuido Kiener 15334d5e18d9SGuido Kiener if (count > INT_MAX) { 15344d5e18d9SGuido Kiener transfersize = INT_MAX; 15355b775f67SGreg Kroah-Hartman buffer[8] = 0; 15365b775f67SGreg Kroah-Hartman } else { 15374d5e18d9SGuido Kiener transfersize = count; 1538fbd83971SGuido Kiener buffer[8] = file_data->eom_val; 15395b775f67SGreg Kroah-Hartman } 15405b775f67SGreg Kroah-Hartman 15415b775f67SGreg Kroah-Hartman /* Setup IO buffer for DEV_DEP_MSG_OUT message */ 15425b775f67SGreg Kroah-Hartman buffer[0] = 1; 15435b775f67SGreg Kroah-Hartman buffer[1] = data->bTag; 1544bbf4976eSAndy Shevchenko buffer[2] = ~data->bTag; 15455b775f67SGreg Kroah-Hartman buffer[3] = 0; /* Reserved */ 15464d5e18d9SGuido Kiener buffer[4] = transfersize >> 0; 15474d5e18d9SGuido Kiener buffer[5] = transfersize >> 8; 15484d5e18d9SGuido Kiener buffer[6] = transfersize >> 16; 15494d5e18d9SGuido Kiener buffer[7] = transfersize >> 24; 15505b775f67SGreg Kroah-Hartman /* buffer[8] is set above... */ 15515b775f67SGreg Kroah-Hartman buffer[9] = 0; /* Reserved */ 15525b775f67SGreg Kroah-Hartman buffer[10] = 0; /* Reserved */ 15535b775f67SGreg Kroah-Hartman buffer[11] = 0; /* Reserved */ 15545b775f67SGreg Kroah-Hartman 15554d5e18d9SGuido Kiener remaining = transfersize; 15564d5e18d9SGuido Kiener 15574d5e18d9SGuido Kiener if (transfersize + USBTMC_HEADER_SIZE > buflen) { 15584d5e18d9SGuido Kiener transfersize = buflen - USBTMC_HEADER_SIZE; 15594d5e18d9SGuido Kiener aligned = buflen; 15604d5e18d9SGuido Kiener } else { 15614d5e18d9SGuido Kiener aligned = (transfersize + (USBTMC_HEADER_SIZE + 3)) & ~3; 15624d5e18d9SGuido Kiener } 15634d5e18d9SGuido Kiener 15644d5e18d9SGuido Kiener if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf, transfersize)) { 15655b775f67SGreg Kroah-Hartman retval = -EFAULT; 15664d5e18d9SGuido Kiener up(&file_data->limit_write_sem); 15675b775f67SGreg Kroah-Hartman goto exit; 15685b775f67SGreg Kroah-Hartman } 15695b775f67SGreg Kroah-Hartman 15704d5e18d9SGuido Kiener dev_dbg(&data->intf->dev, "%s(size:%u align:%u)\n", __func__, 15714d5e18d9SGuido Kiener (unsigned int)transfersize, (unsigned int)aligned); 15725b775f67SGreg Kroah-Hartman 15734d5e18d9SGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 15744d5e18d9SGuido Kiener 16, 1, buffer, aligned, true); 15754d5e18d9SGuido Kiener 15764d5e18d9SGuido Kiener usb_fill_bulk_urb(urb, data->usb_dev, 15774d5e18d9SGuido Kiener usb_sndbulkpipe(data->usb_dev, data->bulk_out), 15784d5e18d9SGuido Kiener urb->transfer_buffer, aligned, 15794d5e18d9SGuido Kiener usbtmc_write_bulk_cb, file_data); 15804d5e18d9SGuido Kiener 15814d5e18d9SGuido Kiener usb_anchor_urb(urb, &file_data->submitted); 15824d5e18d9SGuido Kiener retval = usb_submit_urb(urb, GFP_KERNEL); 15834d5e18d9SGuido Kiener if (unlikely(retval)) { 15844d5e18d9SGuido Kiener usb_unanchor_urb(urb); 15854d5e18d9SGuido Kiener up(&file_data->limit_write_sem); 15864d5e18d9SGuido Kiener goto exit; 15874d5e18d9SGuido Kiener } 15884d5e18d9SGuido Kiener 15894d5e18d9SGuido Kiener remaining -= transfersize; 15905b775f67SGreg Kroah-Hartman 15915b775f67SGreg Kroah-Hartman data->bTag_last_write = data->bTag; 15925b775f67SGreg Kroah-Hartman data->bTag++; 15935b775f67SGreg Kroah-Hartman 15945b775f67SGreg Kroah-Hartman if (!data->bTag) 15955b775f67SGreg Kroah-Hartman data->bTag++; 15965b775f67SGreg Kroah-Hartman 15974d5e18d9SGuido Kiener /* call generic_write even when remaining = 0 */ 15984d5e18d9SGuido Kiener retval = usbtmc_generic_write(file_data, buf + transfersize, remaining, 15994d5e18d9SGuido Kiener &done, USBTMC_FLAG_APPEND); 16004d5e18d9SGuido Kiener /* truncate alignment bytes */ 16014d5e18d9SGuido Kiener if (done > remaining) 16024d5e18d9SGuido Kiener done = remaining; 16034d5e18d9SGuido Kiener 16044d5e18d9SGuido Kiener /*add size of first urb*/ 16054d5e18d9SGuido Kiener done += transfersize; 16064d5e18d9SGuido Kiener 16075b775f67SGreg Kroah-Hartman if (retval < 0) { 16084d5e18d9SGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 16094d5e18d9SGuido Kiener 16105b775f67SGreg Kroah-Hartman dev_err(&data->intf->dev, 16114d5e18d9SGuido Kiener "Unable to send data, error %d\n", (int)retval); 1612ec34d08eSGuido Kiener if (file_data->auto_abort) 16135b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_out(data); 16145b775f67SGreg Kroah-Hartman goto exit; 16155b775f67SGreg Kroah-Hartman } 16165b775f67SGreg Kroah-Hartman 16174d5e18d9SGuido Kiener retval = done; 16185b775f67SGreg Kroah-Hartman exit: 16194d5e18d9SGuido Kiener usb_free_urb(urb); 16205b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 16215b775f67SGreg Kroah-Hartman return retval; 16225b775f67SGreg Kroah-Hartman } 16235b775f67SGreg Kroah-Hartman 16245b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) 16255b775f67SGreg Kroah-Hartman { 16265b775f67SGreg Kroah-Hartman struct device *dev; 16275b775f67SGreg Kroah-Hartman u8 *buffer; 16285b775f67SGreg Kroah-Hartman int rv; 16295b775f67SGreg Kroah-Hartman int n; 1630ab53eb97SRickard Strandqvist int actual = 0; 16315b775f67SGreg Kroah-Hartman 16325b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 16335b775f67SGreg Kroah-Hartman 16345b775f67SGreg Kroah-Hartman dev_dbg(dev, "Sending INITIATE_CLEAR request\n"); 16355b775f67SGreg Kroah-Hartman 1636dfee02acSGuido Kiener buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL); 16375b775f67SGreg Kroah-Hartman if (!buffer) 16385b775f67SGreg Kroah-Hartman return -ENOMEM; 16395b775f67SGreg Kroah-Hartman 16405b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 16415b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 16425b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_CLEAR, 16435b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 1644dfee02acSGuido Kiener 0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT); 16455b775f67SGreg Kroah-Hartman if (rv < 0) { 16465b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 16475b775f67SGreg Kroah-Hartman goto exit; 16485b775f67SGreg Kroah-Hartman } 16495b775f67SGreg Kroah-Hartman 16505b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); 16515b775f67SGreg Kroah-Hartman 16525b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 16535b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); 16545b775f67SGreg Kroah-Hartman rv = -EPERM; 16555b775f67SGreg Kroah-Hartman goto exit; 16565b775f67SGreg Kroah-Hartman } 16575b775f67SGreg Kroah-Hartman 16585b775f67SGreg Kroah-Hartman n = 0; 16595b775f67SGreg Kroah-Hartman 16605b775f67SGreg Kroah-Hartman usbtmc_clear_check_status: 16615b775f67SGreg Kroah-Hartman 16625b775f67SGreg Kroah-Hartman dev_dbg(dev, "Sending CHECK_CLEAR_STATUS request\n"); 16635b775f67SGreg Kroah-Hartman 16645b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 16655b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 16665b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_CLEAR_STATUS, 16675b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 1668dfee02acSGuido Kiener 0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT); 16695b775f67SGreg Kroah-Hartman if (rv < 0) { 16705b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 16715b775f67SGreg Kroah-Hartman goto exit; 16725b775f67SGreg Kroah-Hartman } 16735b775f67SGreg Kroah-Hartman 16745b775f67SGreg Kroah-Hartman dev_dbg(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); 16755b775f67SGreg Kroah-Hartman 16765b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) 16775b775f67SGreg Kroah-Hartman goto usbtmc_clear_bulk_out_halt; 16785b775f67SGreg Kroah-Hartman 16795b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_PENDING) { 16805b775f67SGreg Kroah-Hartman dev_err(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); 16815b775f67SGreg Kroah-Hartman rv = -EPERM; 16825b775f67SGreg Kroah-Hartman goto exit; 16835b775f67SGreg Kroah-Hartman } 16845b775f67SGreg Kroah-Hartman 1685dfee02acSGuido Kiener if ((buffer[1] & 1) != 0) { 16865b775f67SGreg Kroah-Hartman do { 16875b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 16885b775f67SGreg Kroah-Hartman 16895b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 16905b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 16915b775f67SGreg Kroah-Hartman data->bulk_in), 1692dfee02acSGuido Kiener buffer, USBTMC_BUFSIZE, 1693dfee02acSGuido Kiener &actual, USB_CTRL_GET_TIMEOUT); 1694dfee02acSGuido Kiener 1695dfee02acSGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 1696dfee02acSGuido Kiener 16, 1, buffer, actual, true); 1697dfee02acSGuido Kiener 16985b775f67SGreg Kroah-Hartman n++; 16995b775f67SGreg Kroah-Hartman 17005b775f67SGreg Kroah-Hartman if (rv < 0) { 17015b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", 17025b775f67SGreg Kroah-Hartman rv); 17035b775f67SGreg Kroah-Hartman goto exit; 17045b775f67SGreg Kroah-Hartman } 1705dfee02acSGuido Kiener } while ((actual == USBTMC_BUFSIZE) && 17065b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); 1707dfee02acSGuido Kiener } else { 1708dfee02acSGuido Kiener /* do not stress device with subsequent requests */ 1709dfee02acSGuido Kiener msleep(50); 1710dfee02acSGuido Kiener n++; 1711dfee02acSGuido Kiener } 17125b775f67SGreg Kroah-Hartman 1713dfee02acSGuido Kiener if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) { 17145b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 17155b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 17165b775f67SGreg Kroah-Hartman rv = -EPERM; 17175b775f67SGreg Kroah-Hartman goto exit; 17185b775f67SGreg Kroah-Hartman } 17195b775f67SGreg Kroah-Hartman 17205b775f67SGreg Kroah-Hartman goto usbtmc_clear_check_status; 17215b775f67SGreg Kroah-Hartman 17225b775f67SGreg Kroah-Hartman usbtmc_clear_bulk_out_halt: 17235b775f67SGreg Kroah-Hartman 17243342ecdaSSarah Sharp rv = usb_clear_halt(data->usb_dev, 17253342ecdaSSarah Sharp usb_sndbulkpipe(data->usb_dev, data->bulk_out)); 17265b775f67SGreg Kroah-Hartman if (rv < 0) { 1727dfee02acSGuido Kiener dev_err(dev, "usb_clear_halt returned %d\n", rv); 17285b775f67SGreg Kroah-Hartman goto exit; 17295b775f67SGreg Kroah-Hartman } 17305b775f67SGreg Kroah-Hartman rv = 0; 17315b775f67SGreg Kroah-Hartman 17325b775f67SGreg Kroah-Hartman exit: 17335b775f67SGreg Kroah-Hartman kfree(buffer); 17345b775f67SGreg Kroah-Hartman return rv; 17355b775f67SGreg Kroah-Hartman } 17365b775f67SGreg Kroah-Hartman 17375b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data) 17385b775f67SGreg Kroah-Hartman { 17395b775f67SGreg Kroah-Hartman int rv; 17405b775f67SGreg Kroah-Hartman 17413342ecdaSSarah Sharp rv = usb_clear_halt(data->usb_dev, 17423342ecdaSSarah Sharp usb_sndbulkpipe(data->usb_dev, data->bulk_out)); 17435b775f67SGreg Kroah-Hartman 17445b775f67SGreg Kroah-Hartman if (rv < 0) { 17455b775f67SGreg Kroah-Hartman dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", 17465b775f67SGreg Kroah-Hartman rv); 17475b775f67SGreg Kroah-Hartman return rv; 17485b775f67SGreg Kroah-Hartman } 1749ac9e59caSMing Lei return 0; 1750ac9e59caSMing Lei } 17515b775f67SGreg Kroah-Hartman 17525b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) 17535b775f67SGreg Kroah-Hartman { 17545b775f67SGreg Kroah-Hartman int rv; 17555b775f67SGreg Kroah-Hartman 17563342ecdaSSarah Sharp rv = usb_clear_halt(data->usb_dev, 17573342ecdaSSarah Sharp usb_rcvbulkpipe(data->usb_dev, data->bulk_in)); 17585b775f67SGreg Kroah-Hartman 17595b775f67SGreg Kroah-Hartman if (rv < 0) { 17605b775f67SGreg Kroah-Hartman dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", 17615b775f67SGreg Kroah-Hartman rv); 17625b775f67SGreg Kroah-Hartman return rv; 17635b775f67SGreg Kroah-Hartman } 1764ac9e59caSMing Lei return 0; 1765ac9e59caSMing Lei } 17665b775f67SGreg Kroah-Hartman 17674ddc645fSGuido Kiener static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data) 17684ddc645fSGuido Kiener { 17694ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 1770bb99794aSGuido Kiener file_data->in_status = -ECANCELED; 17714ddc645fSGuido Kiener file_data->out_status = -ECANCELED; 17724ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 17734ddc645fSGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 17744ddc645fSGuido Kiener return 0; 17754ddc645fSGuido Kiener } 17764ddc645fSGuido Kiener 1777987b8199SGuido Kiener static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data) 1778987b8199SGuido Kiener { 1779987b8199SGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 1780987b8199SGuido Kiener usb_scuttle_anchored_urbs(&file_data->in_anchor); 1781987b8199SGuido Kiener spin_lock_irq(&file_data->err_lock); 1782987b8199SGuido Kiener file_data->in_status = 0; 1783987b8199SGuido Kiener file_data->in_transfer_size = 0; 1784987b8199SGuido Kiener file_data->out_status = 0; 1785987b8199SGuido Kiener file_data->out_transfer_size = 0; 1786987b8199SGuido Kiener spin_unlock_irq(&file_data->err_lock); 1787987b8199SGuido Kiener 1788987b8199SGuido Kiener file_data->in_urbs_used = 0; 1789987b8199SGuido Kiener return 0; 1790987b8199SGuido Kiener } 1791987b8199SGuido Kiener 17925b775f67SGreg Kroah-Hartman static int get_capabilities(struct usbtmc_device_data *data) 17935b775f67SGreg Kroah-Hartman { 17945b775f67SGreg Kroah-Hartman struct device *dev = &data->usb_dev->dev; 17955b775f67SGreg Kroah-Hartman char *buffer; 1796ca157c4aSOliver Neukum int rv = 0; 17975b775f67SGreg Kroah-Hartman 17985b775f67SGreg Kroah-Hartman buffer = kmalloc(0x18, GFP_KERNEL); 17995b775f67SGreg Kroah-Hartman if (!buffer) 18005b775f67SGreg Kroah-Hartman return -ENOMEM; 18015b775f67SGreg Kroah-Hartman 18025b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), 18035b775f67SGreg Kroah-Hartman USBTMC_REQUEST_GET_CAPABILITIES, 18045b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 18055b775f67SGreg Kroah-Hartman 0, 0, buffer, 0x18, USBTMC_TIMEOUT); 18065b775f67SGreg Kroah-Hartman if (rv < 0) { 18075b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 1808ca157c4aSOliver Neukum goto err_out; 18095b775f67SGreg Kroah-Hartman } 18105b775f67SGreg Kroah-Hartman 18115b775f67SGreg Kroah-Hartman dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); 18125b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 18135b775f67SGreg Kroah-Hartman dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); 1814ca157c4aSOliver Neukum rv = -EPERM; 1815ca157c4aSOliver Neukum goto err_out; 18165b775f67SGreg Kroah-Hartman } 1817d0a38365SGergely Imreh dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]); 1818d0a38365SGergely Imreh dev_dbg(dev, "Device capabilities are %x\n", buffer[5]); 1819d0a38365SGergely Imreh dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]); 1820d0a38365SGergely Imreh dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]); 18215b775f67SGreg Kroah-Hartman 18225b775f67SGreg Kroah-Hartman data->capabilities.interface_capabilities = buffer[4]; 18235b775f67SGreg Kroah-Hartman data->capabilities.device_capabilities = buffer[5]; 18245b775f67SGreg Kroah-Hartman data->capabilities.usb488_interface_capabilities = buffer[14]; 18255b775f67SGreg Kroah-Hartman data->capabilities.usb488_device_capabilities = buffer[15]; 182629779d89SDave Penkler data->usb488_caps = (buffer[14] & 0x07) | ((buffer[15] & 0x0f) << 4); 1827d0a38365SGergely Imreh rv = 0; 18285b775f67SGreg Kroah-Hartman 1829ca157c4aSOliver Neukum err_out: 18305b775f67SGreg Kroah-Hartman kfree(buffer); 1831ca157c4aSOliver Neukum return rv; 18325b775f67SGreg Kroah-Hartman } 18335b775f67SGreg Kroah-Hartman 18345b775f67SGreg Kroah-Hartman #define capability_attribute(name) \ 18352a6eb8acSGreg Kroah-Hartman static ssize_t name##_show(struct device *dev, \ 18365b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 18375b775f67SGreg Kroah-Hartman { \ 18385b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 18395b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 18405b775f67SGreg Kroah-Hartman \ 18415b775f67SGreg Kroah-Hartman return sprintf(buf, "%d\n", data->capabilities.name); \ 18425b775f67SGreg Kroah-Hartman } \ 18432a6eb8acSGreg Kroah-Hartman static DEVICE_ATTR_RO(name) 18445b775f67SGreg Kroah-Hartman 18455b775f67SGreg Kroah-Hartman capability_attribute(interface_capabilities); 18465b775f67SGreg Kroah-Hartman capability_attribute(device_capabilities); 18475b775f67SGreg Kroah-Hartman capability_attribute(usb488_interface_capabilities); 18485b775f67SGreg Kroah-Hartman capability_attribute(usb488_device_capabilities); 18495b775f67SGreg Kroah-Hartman 18505b775f67SGreg Kroah-Hartman static struct attribute *capability_attrs[] = { 18515b775f67SGreg Kroah-Hartman &dev_attr_interface_capabilities.attr, 18525b775f67SGreg Kroah-Hartman &dev_attr_device_capabilities.attr, 18535b775f67SGreg Kroah-Hartman &dev_attr_usb488_interface_capabilities.attr, 18545b775f67SGreg Kroah-Hartman &dev_attr_usb488_device_capabilities.attr, 18555b775f67SGreg Kroah-Hartman NULL, 18565b775f67SGreg Kroah-Hartman }; 18575b775f67SGreg Kroah-Hartman 1858a70df964SArvind Yadav static const struct attribute_group capability_attr_grp = { 18595b775f67SGreg Kroah-Hartman .attrs = capability_attrs, 18605b775f67SGreg Kroah-Hartman }; 18615b775f67SGreg Kroah-Hartman 18622a6eb8acSGreg Kroah-Hartman static ssize_t TermChar_show(struct device *dev, 18635b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 18645b775f67SGreg Kroah-Hartman { 18655b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); 18665b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); 18675b775f67SGreg Kroah-Hartman 18685b775f67SGreg Kroah-Hartman return sprintf(buf, "%c\n", data->TermChar); 18695b775f67SGreg Kroah-Hartman } 18705b775f67SGreg Kroah-Hartman 18712a6eb8acSGreg Kroah-Hartman static ssize_t TermChar_store(struct device *dev, 18725b775f67SGreg Kroah-Hartman struct device_attribute *attr, 18735b775f67SGreg Kroah-Hartman const char *buf, size_t count) 18745b775f67SGreg Kroah-Hartman { 18755b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); 18765b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); 18775b775f67SGreg Kroah-Hartman 18785b775f67SGreg Kroah-Hartman if (count < 1) 18795b775f67SGreg Kroah-Hartman return -EINVAL; 18805b775f67SGreg Kroah-Hartman data->TermChar = buf[0]; 18815b775f67SGreg Kroah-Hartman return count; 18825b775f67SGreg Kroah-Hartman } 18832a6eb8acSGreg Kroah-Hartman static DEVICE_ATTR_RW(TermChar); 18845b775f67SGreg Kroah-Hartman 18855b775f67SGreg Kroah-Hartman #define data_attribute(name) \ 18862a6eb8acSGreg Kroah-Hartman static ssize_t name##_show(struct device *dev, \ 18875b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 18885b775f67SGreg Kroah-Hartman { \ 18895b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 18905b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 18915b775f67SGreg Kroah-Hartman \ 18925b775f67SGreg Kroah-Hartman return sprintf(buf, "%d\n", data->name); \ 18935b775f67SGreg Kroah-Hartman } \ 18942a6eb8acSGreg Kroah-Hartman static ssize_t name##_store(struct device *dev, \ 18955b775f67SGreg Kroah-Hartman struct device_attribute *attr, \ 18965b775f67SGreg Kroah-Hartman const char *buf, size_t count) \ 18975b775f67SGreg Kroah-Hartman { \ 18985b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 18995b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 19005b775f67SGreg Kroah-Hartman ssize_t result; \ 19015b775f67SGreg Kroah-Hartman unsigned val; \ 19025b775f67SGreg Kroah-Hartman \ 19035b775f67SGreg Kroah-Hartman result = sscanf(buf, "%u\n", &val); \ 19045b775f67SGreg Kroah-Hartman if (result != 1) \ 19055b775f67SGreg Kroah-Hartman result = -EINVAL; \ 19065b775f67SGreg Kroah-Hartman data->name = val; \ 19075b775f67SGreg Kroah-Hartman if (result < 0) \ 19085b775f67SGreg Kroah-Hartman return result; \ 19095b775f67SGreg Kroah-Hartman else \ 19105b775f67SGreg Kroah-Hartman return count; \ 19115b775f67SGreg Kroah-Hartman } \ 19122a6eb8acSGreg Kroah-Hartman static DEVICE_ATTR_RW(name) 19135b775f67SGreg Kroah-Hartman 19145b775f67SGreg Kroah-Hartman data_attribute(TermCharEnabled); 19155b775f67SGreg Kroah-Hartman data_attribute(auto_abort); 19165b775f67SGreg Kroah-Hartman 19175b775f67SGreg Kroah-Hartman static struct attribute *data_attrs[] = { 19185b775f67SGreg Kroah-Hartman &dev_attr_TermChar.attr, 19195b775f67SGreg Kroah-Hartman &dev_attr_TermCharEnabled.attr, 19205b775f67SGreg Kroah-Hartman &dev_attr_auto_abort.attr, 19215b775f67SGreg Kroah-Hartman NULL, 19225b775f67SGreg Kroah-Hartman }; 19235b775f67SGreg Kroah-Hartman 1924a70df964SArvind Yadav static const struct attribute_group data_attr_grp = { 19255b775f67SGreg Kroah-Hartman .attrs = data_attrs, 19265b775f67SGreg Kroah-Hartman }; 19275b775f67SGreg Kroah-Hartman 19285b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) 19295b775f67SGreg Kroah-Hartman { 19305b775f67SGreg Kroah-Hartman struct device *dev; 19315b775f67SGreg Kroah-Hartman u8 *buffer; 19325b775f67SGreg Kroah-Hartman int rv; 19335b775f67SGreg Kroah-Hartman 19345b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 19355b775f67SGreg Kroah-Hartman 19365b775f67SGreg Kroah-Hartman buffer = kmalloc(2, GFP_KERNEL); 19375b775f67SGreg Kroah-Hartman if (!buffer) 19385b775f67SGreg Kroah-Hartman return -ENOMEM; 19395b775f67SGreg Kroah-Hartman 19405b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 19415b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 19425b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INDICATOR_PULSE, 19435b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 19445b775f67SGreg Kroah-Hartman 0, 0, buffer, 0x01, USBTMC_TIMEOUT); 19455b775f67SGreg Kroah-Hartman 19465b775f67SGreg Kroah-Hartman if (rv < 0) { 19475b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 19485b775f67SGreg Kroah-Hartman goto exit; 19495b775f67SGreg Kroah-Hartman } 19505b775f67SGreg Kroah-Hartman 19515b775f67SGreg Kroah-Hartman dev_dbg(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); 19525b775f67SGreg Kroah-Hartman 19535b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 19545b775f67SGreg Kroah-Hartman dev_err(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); 19555b775f67SGreg Kroah-Hartman rv = -EPERM; 19565b775f67SGreg Kroah-Hartman goto exit; 19575b775f67SGreg Kroah-Hartman } 19585b775f67SGreg Kroah-Hartman rv = 0; 19595b775f67SGreg Kroah-Hartman 19605b775f67SGreg Kroah-Hartman exit: 19615b775f67SGreg Kroah-Hartman kfree(buffer); 19625b775f67SGreg Kroah-Hartman return rv; 19635b775f67SGreg Kroah-Hartman } 19645b775f67SGreg Kroah-Hartman 1965658f24f4SGuido Kiener static int usbtmc_ioctl_request(struct usbtmc_device_data *data, 1966658f24f4SGuido Kiener void __user *arg) 1967658f24f4SGuido Kiener { 1968658f24f4SGuido Kiener struct device *dev = &data->intf->dev; 1969658f24f4SGuido Kiener struct usbtmc_ctrlrequest request; 1970658f24f4SGuido Kiener u8 *buffer = NULL; 1971658f24f4SGuido Kiener int rv; 1972658f24f4SGuido Kiener unsigned long res; 1973658f24f4SGuido Kiener 1974658f24f4SGuido Kiener res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest)); 1975658f24f4SGuido Kiener if (res) 1976658f24f4SGuido Kiener return -EFAULT; 1977658f24f4SGuido Kiener 1978658f24f4SGuido Kiener buffer = kmalloc(request.req.wLength, GFP_KERNEL); 1979658f24f4SGuido Kiener if (!buffer) 1980658f24f4SGuido Kiener return -ENOMEM; 1981658f24f4SGuido Kiener 1982658f24f4SGuido Kiener if (request.req.wLength > USBTMC_BUFSIZE) 1983658f24f4SGuido Kiener return -EMSGSIZE; 1984658f24f4SGuido Kiener 1985658f24f4SGuido Kiener if (request.req.wLength) { 1986658f24f4SGuido Kiener buffer = kmalloc(request.req.wLength, GFP_KERNEL); 1987658f24f4SGuido Kiener if (!buffer) 1988658f24f4SGuido Kiener return -ENOMEM; 1989658f24f4SGuido Kiener 1990658f24f4SGuido Kiener if ((request.req.bRequestType & USB_DIR_IN) == 0) { 1991658f24f4SGuido Kiener /* Send control data to device */ 1992658f24f4SGuido Kiener res = copy_from_user(buffer, request.data, 1993658f24f4SGuido Kiener request.req.wLength); 1994658f24f4SGuido Kiener if (res) { 1995658f24f4SGuido Kiener rv = -EFAULT; 1996658f24f4SGuido Kiener goto exit; 1997658f24f4SGuido Kiener } 1998658f24f4SGuido Kiener } 1999658f24f4SGuido Kiener } 2000658f24f4SGuido Kiener 2001658f24f4SGuido Kiener rv = usb_control_msg(data->usb_dev, 2002658f24f4SGuido Kiener usb_rcvctrlpipe(data->usb_dev, 0), 2003658f24f4SGuido Kiener request.req.bRequest, 2004658f24f4SGuido Kiener request.req.bRequestType, 2005658f24f4SGuido Kiener request.req.wValue, 2006658f24f4SGuido Kiener request.req.wIndex, 2007658f24f4SGuido Kiener buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT); 2008658f24f4SGuido Kiener 2009658f24f4SGuido Kiener if (rv < 0) { 2010658f24f4SGuido Kiener dev_err(dev, "%s failed %d\n", __func__, rv); 2011658f24f4SGuido Kiener goto exit; 2012658f24f4SGuido Kiener } 2013658f24f4SGuido Kiener 2014658f24f4SGuido Kiener if (rv && (request.req.bRequestType & USB_DIR_IN)) { 2015658f24f4SGuido Kiener /* Read control data from device */ 2016658f24f4SGuido Kiener res = copy_to_user(request.data, buffer, rv); 2017658f24f4SGuido Kiener if (res) 2018658f24f4SGuido Kiener rv = -EFAULT; 2019658f24f4SGuido Kiener } 2020658f24f4SGuido Kiener 2021658f24f4SGuido Kiener exit: 2022658f24f4SGuido Kiener kfree(buffer); 2023658f24f4SGuido Kiener return rv; 2024658f24f4SGuido Kiener } 2025658f24f4SGuido Kiener 2026048c6d88SGuido Kiener /* 2027048c6d88SGuido Kiener * Get the usb timeout value 2028048c6d88SGuido Kiener */ 2029048c6d88SGuido Kiener static int usbtmc_ioctl_get_timeout(struct usbtmc_file_data *file_data, 2030048c6d88SGuido Kiener void __user *arg) 2031048c6d88SGuido Kiener { 2032048c6d88SGuido Kiener u32 timeout; 2033048c6d88SGuido Kiener 2034048c6d88SGuido Kiener timeout = file_data->timeout; 2035048c6d88SGuido Kiener 2036048c6d88SGuido Kiener return put_user(timeout, (__u32 __user *)arg); 2037048c6d88SGuido Kiener } 2038048c6d88SGuido Kiener 2039048c6d88SGuido Kiener /* 2040048c6d88SGuido Kiener * Set the usb timeout value 2041048c6d88SGuido Kiener */ 2042048c6d88SGuido Kiener static int usbtmc_ioctl_set_timeout(struct usbtmc_file_data *file_data, 2043048c6d88SGuido Kiener void __user *arg) 2044048c6d88SGuido Kiener { 2045048c6d88SGuido Kiener u32 timeout; 2046048c6d88SGuido Kiener 2047048c6d88SGuido Kiener if (get_user(timeout, (__u32 __user *)arg)) 2048048c6d88SGuido Kiener return -EFAULT; 2049048c6d88SGuido Kiener 2050048c6d88SGuido Kiener /* Note that timeout = 0 means 2051048c6d88SGuido Kiener * MAX_SCHEDULE_TIMEOUT in usb_control_msg 2052048c6d88SGuido Kiener */ 2053048c6d88SGuido Kiener if (timeout < USBTMC_MIN_TIMEOUT) 2054048c6d88SGuido Kiener return -EINVAL; 2055048c6d88SGuido Kiener 2056048c6d88SGuido Kiener file_data->timeout = timeout; 2057048c6d88SGuido Kiener 2058048c6d88SGuido Kiener return 0; 2059048c6d88SGuido Kiener } 2060048c6d88SGuido Kiener 2061fbd83971SGuido Kiener /* 2062fbd83971SGuido Kiener * enables/disables sending EOM on write 2063fbd83971SGuido Kiener */ 2064fbd83971SGuido Kiener static int usbtmc_ioctl_eom_enable(struct usbtmc_file_data *file_data, 2065fbd83971SGuido Kiener void __user *arg) 2066fbd83971SGuido Kiener { 2067fbd83971SGuido Kiener u8 eom_enable; 2068fbd83971SGuido Kiener 2069fbd83971SGuido Kiener if (copy_from_user(&eom_enable, arg, sizeof(eom_enable))) 2070fbd83971SGuido Kiener return -EFAULT; 2071fbd83971SGuido Kiener 2072fbd83971SGuido Kiener if (eom_enable > 1) 2073fbd83971SGuido Kiener return -EINVAL; 2074fbd83971SGuido Kiener 2075fbd83971SGuido Kiener file_data->eom_val = eom_enable; 2076fbd83971SGuido Kiener 2077fbd83971SGuido Kiener return 0; 2078fbd83971SGuido Kiener } 2079fbd83971SGuido Kiener 208012dcaeb7SGuido Kiener /* 208112dcaeb7SGuido Kiener * Configure termination character for read() 208212dcaeb7SGuido Kiener */ 208312dcaeb7SGuido Kiener static int usbtmc_ioctl_config_termc(struct usbtmc_file_data *file_data, 208412dcaeb7SGuido Kiener void __user *arg) 208512dcaeb7SGuido Kiener { 208612dcaeb7SGuido Kiener struct usbtmc_termchar termc; 208712dcaeb7SGuido Kiener 208812dcaeb7SGuido Kiener if (copy_from_user(&termc, arg, sizeof(termc))) 208912dcaeb7SGuido Kiener return -EFAULT; 209012dcaeb7SGuido Kiener 209112dcaeb7SGuido Kiener if ((termc.term_char_enabled > 1) || 209212dcaeb7SGuido Kiener (termc.term_char_enabled && 209312dcaeb7SGuido Kiener !(file_data->data->capabilities.device_capabilities & 1))) 209412dcaeb7SGuido Kiener return -EINVAL; 209512dcaeb7SGuido Kiener 209612dcaeb7SGuido Kiener file_data->term_char = termc.term_char; 209712dcaeb7SGuido Kiener file_data->term_char_enabled = termc.term_char_enabled; 209812dcaeb7SGuido Kiener 209912dcaeb7SGuido Kiener return 0; 210012dcaeb7SGuido Kiener } 210112dcaeb7SGuido Kiener 21025b775f67SGreg Kroah-Hartman static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 21035b775f67SGreg Kroah-Hartman { 21044f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data; 21055b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 21065b775f67SGreg Kroah-Hartman int retval = -EBADRQC; 2107ec34d08eSGuido Kiener __u8 tmp_byte; 21085b775f67SGreg Kroah-Hartman 21094f3c8d6eSGuido Kiener file_data = file->private_data; 21104f3c8d6eSGuido Kiener data = file_data->data; 21114f3c8d6eSGuido Kiener 21125b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 211386286883SOliver Neukum if (data->zombie) { 211486286883SOliver Neukum retval = -ENODEV; 211586286883SOliver Neukum goto skip_io_on_zombie; 211686286883SOliver Neukum } 21175b775f67SGreg Kroah-Hartman 21185b775f67SGreg Kroah-Hartman switch (cmd) { 21195b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR_OUT_HALT: 21205b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear_out_halt(data); 2121a92b63e7SGreg Kroah-Hartman break; 21225b775f67SGreg Kroah-Hartman 21235b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR_IN_HALT: 21245b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear_in_halt(data); 2125a92b63e7SGreg Kroah-Hartman break; 21265b775f67SGreg Kroah-Hartman 21275b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_INDICATOR_PULSE: 21285b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_indicator_pulse(data); 2129a92b63e7SGreg Kroah-Hartman break; 21305b775f67SGreg Kroah-Hartman 21315b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR: 21325b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear(data); 2133a92b63e7SGreg Kroah-Hartman break; 21345b775f67SGreg Kroah-Hartman 21355b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_ABORT_BULK_OUT: 21365b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_abort_bulk_out(data); 2137a92b63e7SGreg Kroah-Hartman break; 21385b775f67SGreg Kroah-Hartman 21395b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_ABORT_BULK_IN: 21405b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_abort_bulk_in(data); 2141a92b63e7SGreg Kroah-Hartman break; 2142dbf3e7f6SDave Penkler 2143658f24f4SGuido Kiener case USBTMC_IOCTL_CTRL_REQUEST: 2144658f24f4SGuido Kiener retval = usbtmc_ioctl_request(data, (void __user *)arg); 2145658f24f4SGuido Kiener break; 2146658f24f4SGuido Kiener 2147048c6d88SGuido Kiener case USBTMC_IOCTL_GET_TIMEOUT: 2148048c6d88SGuido Kiener retval = usbtmc_ioctl_get_timeout(file_data, 2149048c6d88SGuido Kiener (void __user *)arg); 2150048c6d88SGuido Kiener break; 2151048c6d88SGuido Kiener 2152048c6d88SGuido Kiener case USBTMC_IOCTL_SET_TIMEOUT: 2153048c6d88SGuido Kiener retval = usbtmc_ioctl_set_timeout(file_data, 2154048c6d88SGuido Kiener (void __user *)arg); 2155048c6d88SGuido Kiener break; 2156048c6d88SGuido Kiener 2157fbd83971SGuido Kiener case USBTMC_IOCTL_EOM_ENABLE: 2158fbd83971SGuido Kiener retval = usbtmc_ioctl_eom_enable(file_data, 2159fbd83971SGuido Kiener (void __user *)arg); 2160fbd83971SGuido Kiener break; 2161fbd83971SGuido Kiener 216212dcaeb7SGuido Kiener case USBTMC_IOCTL_CONFIG_TERMCHAR: 216312dcaeb7SGuido Kiener retval = usbtmc_ioctl_config_termc(file_data, 216412dcaeb7SGuido Kiener (void __user *)arg); 216512dcaeb7SGuido Kiener break; 216612dcaeb7SGuido Kiener 21674ddc645fSGuido Kiener case USBTMC_IOCTL_WRITE: 21684ddc645fSGuido Kiener retval = usbtmc_ioctl_generic_write(file_data, 21694ddc645fSGuido Kiener (void __user *)arg); 21704ddc645fSGuido Kiener break; 21714ddc645fSGuido Kiener 2172bb99794aSGuido Kiener case USBTMC_IOCTL_READ: 2173bb99794aSGuido Kiener retval = usbtmc_ioctl_generic_read(file_data, 2174bb99794aSGuido Kiener (void __user *)arg); 2175bb99794aSGuido Kiener break; 2176bb99794aSGuido Kiener 2177b1498451SGuido Kiener case USBTMC_IOCTL_WRITE_RESULT: 2178b1498451SGuido Kiener retval = usbtmc_ioctl_write_result(file_data, 2179b1498451SGuido Kiener (void __user *)arg); 2180b1498451SGuido Kiener break; 2181b1498451SGuido Kiener 218229779d89SDave Penkler case USBTMC488_IOCTL_GET_CAPS: 218329779d89SDave Penkler retval = copy_to_user((void __user *)arg, 218429779d89SDave Penkler &data->usb488_caps, 218529779d89SDave Penkler sizeof(data->usb488_caps)); 218629779d89SDave Penkler if (retval) 218729779d89SDave Penkler retval = -EFAULT; 218829779d89SDave Penkler break; 218929779d89SDave Penkler 2190dbf3e7f6SDave Penkler case USBTMC488_IOCTL_READ_STB: 21914f3c8d6eSGuido Kiener retval = usbtmc488_ioctl_read_stb(file_data, 21924f3c8d6eSGuido Kiener (void __user *)arg); 2193dbf3e7f6SDave Penkler break; 2194379d3d33SDave Penkler 2195379d3d33SDave Penkler case USBTMC488_IOCTL_REN_CONTROL: 2196379d3d33SDave Penkler retval = usbtmc488_ioctl_simple(data, (void __user *)arg, 2197379d3d33SDave Penkler USBTMC488_REQUEST_REN_CONTROL); 2198379d3d33SDave Penkler break; 2199379d3d33SDave Penkler 2200379d3d33SDave Penkler case USBTMC488_IOCTL_GOTO_LOCAL: 2201379d3d33SDave Penkler retval = usbtmc488_ioctl_simple(data, (void __user *)arg, 2202379d3d33SDave Penkler USBTMC488_REQUEST_GOTO_LOCAL); 2203379d3d33SDave Penkler break; 2204379d3d33SDave Penkler 2205379d3d33SDave Penkler case USBTMC488_IOCTL_LOCAL_LOCKOUT: 2206379d3d33SDave Penkler retval = usbtmc488_ioctl_simple(data, (void __user *)arg, 2207379d3d33SDave Penkler USBTMC488_REQUEST_LOCAL_LOCKOUT); 2208379d3d33SDave Penkler break; 2209fe78a7c6SGuido Kiener 2210fe78a7c6SGuido Kiener case USBTMC488_IOCTL_TRIGGER: 2211fe78a7c6SGuido Kiener retval = usbtmc488_ioctl_trigger(file_data); 2212fe78a7c6SGuido Kiener break; 221346ecc9d5SGuido Kiener 2214739240a9SGuido Kiener case USBTMC488_IOCTL_WAIT_SRQ: 2215739240a9SGuido Kiener retval = usbtmc488_ioctl_wait_srq(file_data, 2216739240a9SGuido Kiener (__u32 __user *)arg); 2217739240a9SGuido Kiener break; 2218739240a9SGuido Kiener 22198409e96fSGuido Kiener case USBTMC_IOCTL_MSG_IN_ATTR: 22208409e96fSGuido Kiener retval = put_user(file_data->bmTransferAttributes, 22218409e96fSGuido Kiener (__u8 __user *)arg); 22228409e96fSGuido Kiener break; 22238409e96fSGuido Kiener 2224ec34d08eSGuido Kiener case USBTMC_IOCTL_AUTO_ABORT: 2225ec34d08eSGuido Kiener retval = get_user(tmp_byte, (unsigned char __user *)arg); 2226ec34d08eSGuido Kiener if (retval == 0) 2227ec34d08eSGuido Kiener file_data->auto_abort = !!tmp_byte; 2228ec34d08eSGuido Kiener break; 2229ec34d08eSGuido Kiener 223046ecc9d5SGuido Kiener case USBTMC_IOCTL_CANCEL_IO: 223146ecc9d5SGuido Kiener retval = usbtmc_ioctl_cancel_io(file_data); 223246ecc9d5SGuido Kiener break; 2233987b8199SGuido Kiener 2234987b8199SGuido Kiener case USBTMC_IOCTL_CLEANUP_IO: 2235987b8199SGuido Kiener retval = usbtmc_ioctl_cleanup_io(file_data); 2236987b8199SGuido Kiener break; 22375b775f67SGreg Kroah-Hartman } 22385b775f67SGreg Kroah-Hartman 223986286883SOliver Neukum skip_io_on_zombie: 22405b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 22415b775f67SGreg Kroah-Hartman return retval; 22425b775f67SGreg Kroah-Hartman } 22435b775f67SGreg Kroah-Hartman 224482ed3381SDave Penkler static int usbtmc_fasync(int fd, struct file *file, int on) 224582ed3381SDave Penkler { 22464f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data = file->private_data; 224782ed3381SDave Penkler 22484f3c8d6eSGuido Kiener return fasync_helper(fd, file, on, &file_data->data->fasync); 224982ed3381SDave Penkler } 225082ed3381SDave Penkler 2251afc9a42bSAl Viro static __poll_t usbtmc_poll(struct file *file, poll_table *wait) 2252eb6b92ecSDave Penkler { 22534f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data = file->private_data; 22544f3c8d6eSGuido Kiener struct usbtmc_device_data *data = file_data->data; 2255afc9a42bSAl Viro __poll_t mask; 2256eb6b92ecSDave Penkler 2257eb6b92ecSDave Penkler mutex_lock(&data->io_mutex); 2258eb6b92ecSDave Penkler 2259eb6b92ecSDave Penkler if (data->zombie) { 2260a9a08845SLinus Torvalds mask = EPOLLHUP | EPOLLERR; 2261eb6b92ecSDave Penkler goto no_poll; 2262eb6b92ecSDave Penkler } 2263eb6b92ecSDave Penkler 2264eb6b92ecSDave Penkler poll_wait(file, &data->waitq, wait); 2265eb6b92ecSDave Penkler 2266bb99794aSGuido Kiener /* Note that EPOLLPRI is now assigned to SRQ, and 2267bb99794aSGuido Kiener * EPOLLIN|EPOLLRDNORM to normal read data. 2268bb99794aSGuido Kiener */ 22694ddc645fSGuido Kiener mask = 0; 22704ddc645fSGuido Kiener if (atomic_read(&file_data->srq_asserted)) 22714ddc645fSGuido Kiener mask |= EPOLLPRI; 22724ddc645fSGuido Kiener 2273bb99794aSGuido Kiener /* Note that the anchor submitted includes all urbs for BULK IN 2274bb99794aSGuido Kiener * and OUT. So EPOLLOUT is signaled when BULK OUT is empty and 2275bb99794aSGuido Kiener * all BULK IN urbs are completed and moved to in_anchor. 2276bb99794aSGuido Kiener */ 22774ddc645fSGuido Kiener if (usb_anchor_empty(&file_data->submitted)) 22784ddc645fSGuido Kiener mask |= (EPOLLOUT | EPOLLWRNORM); 2279bb99794aSGuido Kiener if (!usb_anchor_empty(&file_data->in_anchor)) 2280bb99794aSGuido Kiener mask |= (EPOLLIN | EPOLLRDNORM); 22814ddc645fSGuido Kiener 22824ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 2283bb99794aSGuido Kiener if (file_data->in_status || file_data->out_status) 22844ddc645fSGuido Kiener mask |= EPOLLERR; 22854ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 22864ddc645fSGuido Kiener 22874ddc645fSGuido Kiener dev_dbg(&data->intf->dev, "poll mask = %x\n", mask); 2288eb6b92ecSDave Penkler 2289eb6b92ecSDave Penkler no_poll: 2290eb6b92ecSDave Penkler mutex_unlock(&data->io_mutex); 2291eb6b92ecSDave Penkler return mask; 2292eb6b92ecSDave Penkler } 2293eb6b92ecSDave Penkler 2294828c0950SAlexey Dobriyan static const struct file_operations fops = { 22955b775f67SGreg Kroah-Hartman .owner = THIS_MODULE, 22965b775f67SGreg Kroah-Hartman .read = usbtmc_read, 22975b775f67SGreg Kroah-Hartman .write = usbtmc_write, 22985b775f67SGreg Kroah-Hartman .open = usbtmc_open, 22995b775f67SGreg Kroah-Hartman .release = usbtmc_release, 23004ddc645fSGuido Kiener .flush = usbtmc_flush, 23015b775f67SGreg Kroah-Hartman .unlocked_ioctl = usbtmc_ioctl, 230260207c8eSGuido Kiener #ifdef CONFIG_COMPAT 230360207c8eSGuido Kiener .compat_ioctl = usbtmc_ioctl, 230460207c8eSGuido Kiener #endif 230582ed3381SDave Penkler .fasync = usbtmc_fasync, 2306eb6b92ecSDave Penkler .poll = usbtmc_poll, 23076038f373SArnd Bergmann .llseek = default_llseek, 23085b775f67SGreg Kroah-Hartman }; 23095b775f67SGreg Kroah-Hartman 23105b775f67SGreg Kroah-Hartman static struct usb_class_driver usbtmc_class = { 23115b775f67SGreg Kroah-Hartman .name = "usbtmc%d", 23125b775f67SGreg Kroah-Hartman .fops = &fops, 23135b775f67SGreg Kroah-Hartman .minor_base = USBTMC_MINOR_BASE, 23145b775f67SGreg Kroah-Hartman }; 23155b775f67SGreg Kroah-Hartman 2316dbf3e7f6SDave Penkler static void usbtmc_interrupt(struct urb *urb) 2317dbf3e7f6SDave Penkler { 2318dbf3e7f6SDave Penkler struct usbtmc_device_data *data = urb->context; 2319dbf3e7f6SDave Penkler struct device *dev = &data->intf->dev; 2320dbf3e7f6SDave Penkler int status = urb->status; 2321dbf3e7f6SDave Penkler int rv; 2322dbf3e7f6SDave Penkler 2323dbf3e7f6SDave Penkler dev_dbg(&data->intf->dev, "int status: %d len %d\n", 2324dbf3e7f6SDave Penkler status, urb->actual_length); 2325dbf3e7f6SDave Penkler 2326dbf3e7f6SDave Penkler switch (status) { 2327dbf3e7f6SDave Penkler case 0: /* SUCCESS */ 2328dbf3e7f6SDave Penkler /* check for valid STB notification */ 2329dbf3e7f6SDave Penkler if (data->iin_buffer[0] > 0x81) { 2330dbf3e7f6SDave Penkler data->bNotify1 = data->iin_buffer[0]; 2331dbf3e7f6SDave Penkler data->bNotify2 = data->iin_buffer[1]; 2332dbf3e7f6SDave Penkler atomic_set(&data->iin_data_valid, 1); 2333dbf3e7f6SDave Penkler wake_up_interruptible(&data->waitq); 2334dbf3e7f6SDave Penkler goto exit; 2335dbf3e7f6SDave Penkler } 233682ed3381SDave Penkler /* check for SRQ notification */ 233782ed3381SDave Penkler if (data->iin_buffer[0] == 0x81) { 23384f3c8d6eSGuido Kiener unsigned long flags; 23394f3c8d6eSGuido Kiener struct list_head *elem; 23404f3c8d6eSGuido Kiener 234182ed3381SDave Penkler if (data->fasync) 234282ed3381SDave Penkler kill_fasync(&data->fasync, 23434f3c8d6eSGuido Kiener SIGIO, POLL_PRI); 234482ed3381SDave Penkler 23454f3c8d6eSGuido Kiener spin_lock_irqsave(&data->dev_lock, flags); 23464f3c8d6eSGuido Kiener list_for_each(elem, &data->file_list) { 23474f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data; 23484f3c8d6eSGuido Kiener 23494f3c8d6eSGuido Kiener file_data = list_entry(elem, 23504f3c8d6eSGuido Kiener struct usbtmc_file_data, 23514f3c8d6eSGuido Kiener file_elem); 23524f3c8d6eSGuido Kiener file_data->srq_byte = data->iin_buffer[1]; 23534f3c8d6eSGuido Kiener atomic_set(&file_data->srq_asserted, 1); 23544f3c8d6eSGuido Kiener } 23554f3c8d6eSGuido Kiener spin_unlock_irqrestore(&data->dev_lock, flags); 23564f3c8d6eSGuido Kiener 23574f3c8d6eSGuido Kiener dev_dbg(dev, "srq received bTag %x stb %x\n", 23584f3c8d6eSGuido Kiener (unsigned int)data->iin_buffer[0], 23594f3c8d6eSGuido Kiener (unsigned int)data->iin_buffer[1]); 23604f3c8d6eSGuido Kiener wake_up_interruptible_all(&data->waitq); 236182ed3381SDave Penkler goto exit; 236282ed3381SDave Penkler } 23634f3c8d6eSGuido Kiener dev_warn(dev, "invalid notification: %x\n", 23644f3c8d6eSGuido Kiener data->iin_buffer[0]); 2365dbf3e7f6SDave Penkler break; 2366dbf3e7f6SDave Penkler case -EOVERFLOW: 2367dbf3e7f6SDave Penkler dev_err(dev, "overflow with length %d, actual length is %d\n", 2368dbf3e7f6SDave Penkler data->iin_wMaxPacketSize, urb->actual_length); 2369e4c6594dSGustavo A. R. Silva /* fall through */ 2370dbf3e7f6SDave Penkler case -ECONNRESET: 2371dbf3e7f6SDave Penkler case -ENOENT: 2372dbf3e7f6SDave Penkler case -ESHUTDOWN: 2373dbf3e7f6SDave Penkler case -EILSEQ: 2374dbf3e7f6SDave Penkler case -ETIME: 23754f3c8d6eSGuido Kiener case -EPIPE: 2376dbf3e7f6SDave Penkler /* urb terminated, clean up */ 2377dbf3e7f6SDave Penkler dev_dbg(dev, "urb terminated, status: %d\n", status); 2378dbf3e7f6SDave Penkler return; 2379dbf3e7f6SDave Penkler default: 2380dbf3e7f6SDave Penkler dev_err(dev, "unknown status received: %d\n", status); 2381dbf3e7f6SDave Penkler } 2382dbf3e7f6SDave Penkler exit: 2383dbf3e7f6SDave Penkler rv = usb_submit_urb(urb, GFP_ATOMIC); 2384dbf3e7f6SDave Penkler if (rv) 2385dbf3e7f6SDave Penkler dev_err(dev, "usb_submit_urb failed: %d\n", rv); 2386dbf3e7f6SDave Penkler } 2387dbf3e7f6SDave Penkler 2388dbf3e7f6SDave Penkler static void usbtmc_free_int(struct usbtmc_device_data *data) 2389dbf3e7f6SDave Penkler { 2390dbf3e7f6SDave Penkler if (!data->iin_ep_present || !data->iin_urb) 2391dbf3e7f6SDave Penkler return; 2392dbf3e7f6SDave Penkler usb_kill_urb(data->iin_urb); 2393dbf3e7f6SDave Penkler kfree(data->iin_buffer); 2394b19bbdc5SGuido Kiener data->iin_buffer = NULL; 2395dbf3e7f6SDave Penkler usb_free_urb(data->iin_urb); 2396b19bbdc5SGuido Kiener data->iin_urb = NULL; 2397dbf3e7f6SDave Penkler kref_put(&data->kref, usbtmc_delete); 2398dbf3e7f6SDave Penkler } 23995b775f67SGreg Kroah-Hartman 24005b775f67SGreg Kroah-Hartman static int usbtmc_probe(struct usb_interface *intf, 24015b775f67SGreg Kroah-Hartman const struct usb_device_id *id) 24025b775f67SGreg Kroah-Hartman { 24035b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 24045b775f67SGreg Kroah-Hartman struct usb_host_interface *iface_desc; 2405041370ccSJohan Hovold struct usb_endpoint_descriptor *bulk_in, *bulk_out, *int_in; 24065b775f67SGreg Kroah-Hartman int retcode; 24075b775f67SGreg Kroah-Hartman 24085b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "%s called\n", __func__); 24095b775f67SGreg Kroah-Hartman 2410687e0687SJohan Hovold data = kzalloc(sizeof(*data), GFP_KERNEL); 2411b8f2854bSPeter Chen if (!data) 24125b775f67SGreg Kroah-Hartman return -ENOMEM; 24135b775f67SGreg Kroah-Hartman 24145b775f67SGreg Kroah-Hartman data->intf = intf; 24155b775f67SGreg Kroah-Hartman data->id = id; 24165b775f67SGreg Kroah-Hartman data->usb_dev = usb_get_dev(interface_to_usbdev(intf)); 24175b775f67SGreg Kroah-Hartman usb_set_intfdata(intf, data); 24185b775f67SGreg Kroah-Hartman kref_init(&data->kref); 24195b775f67SGreg Kroah-Hartman mutex_init(&data->io_mutex); 2420dbf3e7f6SDave Penkler init_waitqueue_head(&data->waitq); 2421dbf3e7f6SDave Penkler atomic_set(&data->iin_data_valid, 0); 24224f3c8d6eSGuido Kiener INIT_LIST_HEAD(&data->file_list); 24234f3c8d6eSGuido Kiener spin_lock_init(&data->dev_lock); 24244f3c8d6eSGuido Kiener 242586286883SOliver Neukum data->zombie = 0; 24265b775f67SGreg Kroah-Hartman 24275b775f67SGreg Kroah-Hartman /* Initialize USBTMC bTag and other fields */ 24285b775f67SGreg Kroah-Hartman data->bTag = 1; 24295b775f67SGreg Kroah-Hartman data->TermCharEnabled = 0; 24305b775f67SGreg Kroah-Hartman data->TermChar = '\n'; 2431dbf3e7f6SDave Penkler /* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */ 2432dbf3e7f6SDave Penkler data->iin_bTag = 2; 24335b775f67SGreg Kroah-Hartman 24345b775f67SGreg Kroah-Hartman /* USBTMC devices have only one setting, so use that */ 24355b775f67SGreg Kroah-Hartman iface_desc = data->intf->cur_altsetting; 2436dbf3e7f6SDave Penkler data->ifnum = iface_desc->desc.bInterfaceNumber; 24375b775f67SGreg Kroah-Hartman 2438041370ccSJohan Hovold /* Find bulk endpoints */ 2439041370ccSJohan Hovold retcode = usb_find_common_endpoints(iface_desc, 2440041370ccSJohan Hovold &bulk_in, &bulk_out, NULL, NULL); 2441041370ccSJohan Hovold if (retcode) { 2442687e0687SJohan Hovold dev_err(&intf->dev, "bulk endpoints not found\n"); 2443687e0687SJohan Hovold goto err_put; 2444687e0687SJohan Hovold } 2445687e0687SJohan Hovold 2446041370ccSJohan Hovold data->bulk_in = bulk_in->bEndpointAddress; 2447bb99794aSGuido Kiener data->wMaxPacketSize = usb_endpoint_maxp(bulk_in); 2448041370ccSJohan Hovold dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in); 2449dbf3e7f6SDave Penkler 2450041370ccSJohan Hovold data->bulk_out = bulk_out->bEndpointAddress; 2451041370ccSJohan Hovold dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", data->bulk_out); 2452041370ccSJohan Hovold 2453041370ccSJohan Hovold /* Find int endpoint */ 2454041370ccSJohan Hovold retcode = usb_find_int_in_endpoint(iface_desc, &int_in); 2455041370ccSJohan Hovold if (!retcode) { 2456dbf3e7f6SDave Penkler data->iin_ep_present = 1; 2457041370ccSJohan Hovold data->iin_ep = int_in->bEndpointAddress; 2458041370ccSJohan Hovold data->iin_wMaxPacketSize = usb_endpoint_maxp(int_in); 2459041370ccSJohan Hovold data->iin_interval = int_in->bInterval; 2460dbf3e7f6SDave Penkler dev_dbg(&intf->dev, "Found Int in endpoint at %u\n", 2461dbf3e7f6SDave Penkler data->iin_ep); 2462dbf3e7f6SDave Penkler } 24635b775f67SGreg Kroah-Hartman 24645b775f67SGreg Kroah-Hartman retcode = get_capabilities(data); 24655b775f67SGreg Kroah-Hartman if (retcode) 24665b775f67SGreg Kroah-Hartman dev_err(&intf->dev, "can't read capabilities\n"); 24675b775f67SGreg Kroah-Hartman else 24685b775f67SGreg Kroah-Hartman retcode = sysfs_create_group(&intf->dev.kobj, 24695b775f67SGreg Kroah-Hartman &capability_attr_grp); 24705b775f67SGreg Kroah-Hartman 2471dbf3e7f6SDave Penkler if (data->iin_ep_present) { 2472dbf3e7f6SDave Penkler /* allocate int urb */ 2473dbf3e7f6SDave Penkler data->iin_urb = usb_alloc_urb(0, GFP_KERNEL); 24742e47c535SJohan Hovold if (!data->iin_urb) { 24752e47c535SJohan Hovold retcode = -ENOMEM; 2476dbf3e7f6SDave Penkler goto error_register; 24772e47c535SJohan Hovold } 2478dbf3e7f6SDave Penkler 247988aecde4SDave Penkler /* Protect interrupt in endpoint data until iin_urb is freed */ 2480dbf3e7f6SDave Penkler kref_get(&data->kref); 2481dbf3e7f6SDave Penkler 2482dbf3e7f6SDave Penkler /* allocate buffer for interrupt in */ 2483dbf3e7f6SDave Penkler data->iin_buffer = kmalloc(data->iin_wMaxPacketSize, 2484dbf3e7f6SDave Penkler GFP_KERNEL); 24852e47c535SJohan Hovold if (!data->iin_buffer) { 24862e47c535SJohan Hovold retcode = -ENOMEM; 2487dbf3e7f6SDave Penkler goto error_register; 24882e47c535SJohan Hovold } 2489dbf3e7f6SDave Penkler 2490dbf3e7f6SDave Penkler /* fill interrupt urb */ 2491dbf3e7f6SDave Penkler usb_fill_int_urb(data->iin_urb, data->usb_dev, 2492dbf3e7f6SDave Penkler usb_rcvintpipe(data->usb_dev, data->iin_ep), 2493dbf3e7f6SDave Penkler data->iin_buffer, data->iin_wMaxPacketSize, 2494dbf3e7f6SDave Penkler usbtmc_interrupt, 2495dbf3e7f6SDave Penkler data, data->iin_interval); 2496dbf3e7f6SDave Penkler 2497dbf3e7f6SDave Penkler retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL); 2498dbf3e7f6SDave Penkler if (retcode) { 2499dbf3e7f6SDave Penkler dev_err(&intf->dev, "Failed to submit iin_urb\n"); 2500dbf3e7f6SDave Penkler goto error_register; 2501dbf3e7f6SDave Penkler } 2502dbf3e7f6SDave Penkler } 2503dbf3e7f6SDave Penkler 25045b775f67SGreg Kroah-Hartman retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp); 25055b775f67SGreg Kroah-Hartman 25065b775f67SGreg Kroah-Hartman retcode = usb_register_dev(intf, &usbtmc_class); 25075b775f67SGreg Kroah-Hartman if (retcode) { 25085b775f67SGreg Kroah-Hartman dev_err(&intf->dev, "Not able to get a minor" 25095b775f67SGreg Kroah-Hartman " (base %u, slice default): %d\n", USBTMC_MINOR_BASE, 25105b775f67SGreg Kroah-Hartman retcode); 25115b775f67SGreg Kroah-Hartman goto error_register; 25125b775f67SGreg Kroah-Hartman } 25135b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "Using minor number %d\n", intf->minor); 25145b775f67SGreg Kroah-Hartman 25155b775f67SGreg Kroah-Hartman return 0; 25165b775f67SGreg Kroah-Hartman 25175b775f67SGreg Kroah-Hartman error_register: 25185b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); 25195b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); 2520dbf3e7f6SDave Penkler usbtmc_free_int(data); 2521687e0687SJohan Hovold err_put: 25225b775f67SGreg Kroah-Hartman kref_put(&data->kref, usbtmc_delete); 25235b775f67SGreg Kroah-Hartman return retcode; 25245b775f67SGreg Kroah-Hartman } 25255b775f67SGreg Kroah-Hartman 25265b775f67SGreg Kroah-Hartman static void usbtmc_disconnect(struct usb_interface *intf) 25275b775f67SGreg Kroah-Hartman { 25284f3c8d6eSGuido Kiener struct usbtmc_device_data *data = usb_get_intfdata(intf); 25294ddc645fSGuido Kiener struct list_head *elem; 25305b775f67SGreg Kroah-Hartman 25315b775f67SGreg Kroah-Hartman usb_deregister_dev(intf, &usbtmc_class); 25325b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); 25335b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); 253486286883SOliver Neukum mutex_lock(&data->io_mutex); 253586286883SOliver Neukum data->zombie = 1; 25364f3c8d6eSGuido Kiener wake_up_interruptible_all(&data->waitq); 25374ddc645fSGuido Kiener list_for_each(elem, &data->file_list) { 25384ddc645fSGuido Kiener struct usbtmc_file_data *file_data; 25394ddc645fSGuido Kiener 25404ddc645fSGuido Kiener file_data = list_entry(elem, 25414ddc645fSGuido Kiener struct usbtmc_file_data, 25424ddc645fSGuido Kiener file_elem); 25434ddc645fSGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 2544bb99794aSGuido Kiener usb_scuttle_anchored_urbs(&file_data->in_anchor); 25454ddc645fSGuido Kiener } 254686286883SOliver Neukum mutex_unlock(&data->io_mutex); 2547f9cfabceSDave Penkler usbtmc_free_int(data); 25485b775f67SGreg Kroah-Hartman kref_put(&data->kref, usbtmc_delete); 25495b775f67SGreg Kroah-Hartman } 25505b775f67SGreg Kroah-Hartman 25514ddc645fSGuido Kiener static void usbtmc_draw_down(struct usbtmc_file_data *file_data) 25524ddc645fSGuido Kiener { 25534ddc645fSGuido Kiener int time; 25544ddc645fSGuido Kiener 25554ddc645fSGuido Kiener time = usb_wait_anchor_empty_timeout(&file_data->submitted, 1000); 25564ddc645fSGuido Kiener if (!time) 25574ddc645fSGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 2558bb99794aSGuido Kiener usb_scuttle_anchored_urbs(&file_data->in_anchor); 25594ddc645fSGuido Kiener } 25604ddc645fSGuido Kiener 2561a4708103SOliver Neukum static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message) 2562a4708103SOliver Neukum { 25634ddc645fSGuido Kiener struct usbtmc_device_data *data = usb_get_intfdata(intf); 25644ddc645fSGuido Kiener struct list_head *elem; 25654ddc645fSGuido Kiener 25664ddc645fSGuido Kiener if (!data) 25674ddc645fSGuido Kiener return 0; 25684ddc645fSGuido Kiener 25694ddc645fSGuido Kiener mutex_lock(&data->io_mutex); 25704ddc645fSGuido Kiener list_for_each(elem, &data->file_list) { 25714ddc645fSGuido Kiener struct usbtmc_file_data *file_data; 25724ddc645fSGuido Kiener 25734ddc645fSGuido Kiener file_data = list_entry(elem, 25744ddc645fSGuido Kiener struct usbtmc_file_data, 25754ddc645fSGuido Kiener file_elem); 25764ddc645fSGuido Kiener usbtmc_draw_down(file_data); 25774ddc645fSGuido Kiener } 2578b19bbdc5SGuido Kiener 2579b19bbdc5SGuido Kiener if (data->iin_ep_present && data->iin_urb) 2580b19bbdc5SGuido Kiener usb_kill_urb(data->iin_urb); 2581b19bbdc5SGuido Kiener 25824ddc645fSGuido Kiener mutex_unlock(&data->io_mutex); 2583a4708103SOliver Neukum return 0; 2584a4708103SOliver Neukum } 2585a4708103SOliver Neukum 2586a4708103SOliver Neukum static int usbtmc_resume(struct usb_interface *intf) 2587a4708103SOliver Neukum { 2588b19bbdc5SGuido Kiener struct usbtmc_device_data *data = usb_get_intfdata(intf); 2589b19bbdc5SGuido Kiener int retcode = 0; 2590b19bbdc5SGuido Kiener 2591b19bbdc5SGuido Kiener if (data->iin_ep_present && data->iin_urb) 2592b19bbdc5SGuido Kiener retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL); 2593b19bbdc5SGuido Kiener if (retcode) 2594b19bbdc5SGuido Kiener dev_err(&intf->dev, "Failed to submit iin_urb\n"); 2595b19bbdc5SGuido Kiener 2596b19bbdc5SGuido Kiener return retcode; 2597a4708103SOliver Neukum } 2598a4708103SOliver Neukum 25994ddc645fSGuido Kiener static int usbtmc_pre_reset(struct usb_interface *intf) 26004ddc645fSGuido Kiener { 26014ddc645fSGuido Kiener struct usbtmc_device_data *data = usb_get_intfdata(intf); 26024ddc645fSGuido Kiener struct list_head *elem; 26034ddc645fSGuido Kiener 26044ddc645fSGuido Kiener if (!data) 26054ddc645fSGuido Kiener return 0; 26064ddc645fSGuido Kiener 26074ddc645fSGuido Kiener mutex_lock(&data->io_mutex); 26084ddc645fSGuido Kiener 26094ddc645fSGuido Kiener list_for_each(elem, &data->file_list) { 26104ddc645fSGuido Kiener struct usbtmc_file_data *file_data; 26114ddc645fSGuido Kiener 26124ddc645fSGuido Kiener file_data = list_entry(elem, 26134ddc645fSGuido Kiener struct usbtmc_file_data, 26144ddc645fSGuido Kiener file_elem); 26154ddc645fSGuido Kiener usbtmc_ioctl_cancel_io(file_data); 26164ddc645fSGuido Kiener } 26174ddc645fSGuido Kiener 26184ddc645fSGuido Kiener return 0; 26194ddc645fSGuido Kiener } 26204ddc645fSGuido Kiener 26214ddc645fSGuido Kiener static int usbtmc_post_reset(struct usb_interface *intf) 26224ddc645fSGuido Kiener { 26234ddc645fSGuido Kiener struct usbtmc_device_data *data = usb_get_intfdata(intf); 26244ddc645fSGuido Kiener 26254ddc645fSGuido Kiener mutex_unlock(&data->io_mutex); 26264ddc645fSGuido Kiener 26274ddc645fSGuido Kiener return 0; 26284ddc645fSGuido Kiener } 26294ddc645fSGuido Kiener 26305b775f67SGreg Kroah-Hartman static struct usb_driver usbtmc_driver = { 26315b775f67SGreg Kroah-Hartman .name = "usbtmc", 26325b775f67SGreg Kroah-Hartman .id_table = usbtmc_devices, 26335b775f67SGreg Kroah-Hartman .probe = usbtmc_probe, 2634a4708103SOliver Neukum .disconnect = usbtmc_disconnect, 2635a4708103SOliver Neukum .suspend = usbtmc_suspend, 2636a4708103SOliver Neukum .resume = usbtmc_resume, 26374ddc645fSGuido Kiener .pre_reset = usbtmc_pre_reset, 26384ddc645fSGuido Kiener .post_reset = usbtmc_post_reset, 26395b775f67SGreg Kroah-Hartman }; 26405b775f67SGreg Kroah-Hartman 264165db4305SGreg Kroah-Hartman module_usb_driver(usbtmc_driver); 26425b775f67SGreg Kroah-Hartman 26435b775f67SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 2644