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 25e013477bSGuido Kiener /* Increment API VERSION when changing tmc.h with new flags or ioctls 26e013477bSGuido Kiener * or when changing a significant behavior of the driver. 27e013477bSGuido Kiener */ 28e013477bSGuido Kiener #define USBTMC_API_VERSION (2) 295b775f67SGreg Kroah-Hartman 308402db5dSAlexandre Peixoto Ferreira #define USBTMC_HEADER_SIZE 12 315b775f67SGreg Kroah-Hartman #define USBTMC_MINOR_BASE 176 325b775f67SGreg Kroah-Hartman 335b775f67SGreg Kroah-Hartman /* 345b775f67SGreg Kroah-Hartman * Size of driver internal IO buffer. Must be multiple of 4 and at least as 355b775f67SGreg Kroah-Hartman * large as wMaxPacketSize (which is usually 512 bytes). 365b775f67SGreg Kroah-Hartman */ 375b775f67SGreg Kroah-Hartman #define USBTMC_SIZE_IOBUFFER 2048 385b775f67SGreg Kroah-Hartman 39048c6d88SGuido Kiener /* Minimum USB timeout (in milliseconds) */ 40048c6d88SGuido Kiener #define USBTMC_MIN_TIMEOUT 100 415b775f67SGreg Kroah-Hartman /* Default USB timeout (in milliseconds) */ 4235f76e89SGergely Imreh #define USBTMC_TIMEOUT 5000 435b775f67SGreg Kroah-Hartman 444ddc645fSGuido Kiener /* Max number of urbs used in write transfers */ 454ddc645fSGuido Kiener #define MAX_URBS_IN_FLIGHT 16 46658f24f4SGuido Kiener /* I/O buffer size used in generic read/write functions */ 47658f24f4SGuido Kiener #define USBTMC_BUFSIZE (4096) 48658f24f4SGuido Kiener 495b775f67SGreg Kroah-Hartman /* 505b775f67SGreg Kroah-Hartman * Maximum number of read cycles to empty bulk in endpoint during CLEAR and 515b775f67SGreg Kroah-Hartman * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short 525b775f67SGreg Kroah-Hartman * packet is never read. 535b775f67SGreg Kroah-Hartman */ 545b775f67SGreg Kroah-Hartman #define USBTMC_MAX_READS_TO_CLEAR_BULK_IN 100 555b775f67SGreg Kroah-Hartman 566ef4852bSNémeth Márton static const struct usb_device_id usbtmc_devices[] = { 575b775f67SGreg Kroah-Hartman { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), }, 58228dd05dSGreg Kroah-Hartman { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), }, 595b775f67SGreg Kroah-Hartman { 0, } /* terminating entry */ 605b775f67SGreg Kroah-Hartman }; 615413aa46SGreg Kroah-Hartman MODULE_DEVICE_TABLE(usb, usbtmc_devices); 625b775f67SGreg Kroah-Hartman 635b775f67SGreg Kroah-Hartman /* 645b775f67SGreg Kroah-Hartman * This structure is the capabilities for the device 65d0a38365SGergely Imreh * See section 4.2.1.8 of the USBTMC specification, 66d0a38365SGergely Imreh * and section 4.2.2 of the USBTMC usb488 subclass 67d0a38365SGergely Imreh * specification for details. 685b775f67SGreg Kroah-Hartman */ 695b775f67SGreg Kroah-Hartman struct usbtmc_dev_capabilities { 705b775f67SGreg Kroah-Hartman __u8 interface_capabilities; 715b775f67SGreg Kroah-Hartman __u8 device_capabilities; 725b775f67SGreg Kroah-Hartman __u8 usb488_interface_capabilities; 735b775f67SGreg Kroah-Hartman __u8 usb488_device_capabilities; 745b775f67SGreg Kroah-Hartman }; 755b775f67SGreg Kroah-Hartman 765b775f67SGreg Kroah-Hartman /* This structure holds private data for each USBTMC device. One copy is 775b775f67SGreg Kroah-Hartman * allocated for each USBTMC device in the driver's probe function. 785b775f67SGreg Kroah-Hartman */ 795b775f67SGreg Kroah-Hartman struct usbtmc_device_data { 805b775f67SGreg Kroah-Hartman const struct usb_device_id *id; 815b775f67SGreg Kroah-Hartman struct usb_device *usb_dev; 825b775f67SGreg Kroah-Hartman struct usb_interface *intf; 834f3c8d6eSGuido Kiener struct list_head file_list; 845b775f67SGreg Kroah-Hartman 855b775f67SGreg Kroah-Hartman unsigned int bulk_in; 865b775f67SGreg Kroah-Hartman unsigned int bulk_out; 875b775f67SGreg Kroah-Hartman 885b775f67SGreg Kroah-Hartman u8 bTag; 895b775f67SGreg Kroah-Hartman u8 bTag_last_write; /* needed for abort */ 905b775f67SGreg Kroah-Hartman u8 bTag_last_read; /* needed for abort */ 915b775f67SGreg Kroah-Hartman 92bb99794aSGuido Kiener /* packet size of IN bulk */ 93bb99794aSGuido Kiener u16 wMaxPacketSize; 94bb99794aSGuido Kiener 95dbf3e7f6SDave Penkler /* data for interrupt in endpoint handling */ 96dbf3e7f6SDave Penkler u8 bNotify1; 97dbf3e7f6SDave Penkler u8 bNotify2; 98dbf3e7f6SDave Penkler u16 ifnum; 99dbf3e7f6SDave Penkler u8 iin_bTag; 100dbf3e7f6SDave Penkler u8 *iin_buffer; 101dbf3e7f6SDave Penkler atomic_t iin_data_valid; 102dbf3e7f6SDave Penkler unsigned int iin_ep; 103dbf3e7f6SDave Penkler int iin_ep_present; 104dbf3e7f6SDave Penkler int iin_interval; 105dbf3e7f6SDave Penkler struct urb *iin_urb; 106dbf3e7f6SDave Penkler u16 iin_wMaxPacketSize; 107dbf3e7f6SDave Penkler 10829779d89SDave Penkler /* coalesced usb488_caps from usbtmc_dev_capabilities */ 10929779d89SDave Penkler __u8 usb488_caps; 11029779d89SDave Penkler 1115b775f67SGreg Kroah-Hartman /* attributes from the USB TMC spec for this device */ 1125b775f67SGreg Kroah-Hartman u8 TermChar; 1135b775f67SGreg Kroah-Hartman bool TermCharEnabled; 1145b775f67SGreg Kroah-Hartman bool auto_abort; 1155b775f67SGreg Kroah-Hartman 11686286883SOliver Neukum bool zombie; /* fd of disconnected device */ 11786286883SOliver Neukum 1185b775f67SGreg Kroah-Hartman struct usbtmc_dev_capabilities capabilities; 1195b775f67SGreg Kroah-Hartman struct kref kref; 1205b775f67SGreg Kroah-Hartman struct mutex io_mutex; /* only one i/o function running at a time */ 121dbf3e7f6SDave Penkler wait_queue_head_t waitq; 12282ed3381SDave Penkler struct fasync_struct *fasync; 1234f3c8d6eSGuido Kiener spinlock_t dev_lock; /* lock for file_list */ 1245b775f67SGreg Kroah-Hartman }; 1255b775f67SGreg Kroah-Hartman #define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref) 1265b775f67SGreg Kroah-Hartman 1274f3c8d6eSGuido Kiener /* 1284f3c8d6eSGuido Kiener * This structure holds private data for each USBTMC file handle. 1294f3c8d6eSGuido Kiener */ 1304f3c8d6eSGuido Kiener struct usbtmc_file_data { 1314f3c8d6eSGuido Kiener struct usbtmc_device_data *data; 1324f3c8d6eSGuido Kiener struct list_head file_elem; 1334f3c8d6eSGuido Kiener 134048c6d88SGuido Kiener u32 timeout; 1354f3c8d6eSGuido Kiener u8 srq_byte; 1364f3c8d6eSGuido Kiener atomic_t srq_asserted; 137739240a9SGuido Kiener atomic_t closing; 1388409e96fSGuido Kiener u8 bmTransferAttributes; /* member of DEV_DEP_MSG_IN */ 1394ddc645fSGuido Kiener 140fbd83971SGuido Kiener u8 eom_val; 14112dcaeb7SGuido Kiener u8 term_char; 14212dcaeb7SGuido Kiener bool term_char_enabled; 143ec34d08eSGuido Kiener bool auto_abort; 1444ddc645fSGuido Kiener 1454ddc645fSGuido Kiener spinlock_t err_lock; /* lock for errors */ 1464ddc645fSGuido Kiener 1474ddc645fSGuido Kiener struct usb_anchor submitted; 1484ddc645fSGuido Kiener 1494ddc645fSGuido Kiener /* data for generic_write */ 1504ddc645fSGuido Kiener struct semaphore limit_write_sem; 1514ddc645fSGuido Kiener u32 out_transfer_size; 1524ddc645fSGuido Kiener int out_status; 153bb99794aSGuido Kiener 154bb99794aSGuido Kiener /* data for generic_read */ 155bb99794aSGuido Kiener u32 in_transfer_size; 156bb99794aSGuido Kiener int in_status; 157bb99794aSGuido Kiener int in_urbs_used; 158bb99794aSGuido Kiener struct usb_anchor in_anchor; 159bb99794aSGuido Kiener wait_queue_head_t wait_bulk_in; 1604f3c8d6eSGuido Kiener }; 1614f3c8d6eSGuido Kiener 1625b775f67SGreg Kroah-Hartman /* Forward declarations */ 1635b775f67SGreg Kroah-Hartman static struct usb_driver usbtmc_driver; 1644ddc645fSGuido Kiener static void usbtmc_draw_down(struct usbtmc_file_data *file_data); 1655b775f67SGreg Kroah-Hartman 1665b775f67SGreg Kroah-Hartman static void usbtmc_delete(struct kref *kref) 1675b775f67SGreg Kroah-Hartman { 1685b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = to_usbtmc_data(kref); 1695b775f67SGreg Kroah-Hartman 1705b775f67SGreg Kroah-Hartman usb_put_dev(data->usb_dev); 171ab21b63eSGreg Kroah-Hartman kfree(data); 1725b775f67SGreg Kroah-Hartman } 1735b775f67SGreg Kroah-Hartman 1745b775f67SGreg Kroah-Hartman static int usbtmc_open(struct inode *inode, struct file *filp) 1755b775f67SGreg Kroah-Hartman { 1765b775f67SGreg Kroah-Hartman struct usb_interface *intf; 1775b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 1784f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data; 1795b775f67SGreg Kroah-Hartman 1805b775f67SGreg Kroah-Hartman intf = usb_find_interface(&usbtmc_driver, iminor(inode)); 1815b775f67SGreg Kroah-Hartman if (!intf) { 182f4d844cbSAndy Shevchenko pr_err("can not find device for minor %d", iminor(inode)); 183f4d844cbSAndy Shevchenko return -ENODEV; 1845b775f67SGreg Kroah-Hartman } 1855b775f67SGreg Kroah-Hartman 1864f3c8d6eSGuido Kiener file_data = kzalloc(sizeof(*file_data), GFP_KERNEL); 1874f3c8d6eSGuido Kiener if (!file_data) 1884f3c8d6eSGuido Kiener return -ENOMEM; 1894f3c8d6eSGuido Kiener 1904ddc645fSGuido Kiener spin_lock_init(&file_data->err_lock); 1914ddc645fSGuido Kiener sema_init(&file_data->limit_write_sem, MAX_URBS_IN_FLIGHT); 1924ddc645fSGuido Kiener init_usb_anchor(&file_data->submitted); 193bb99794aSGuido Kiener init_usb_anchor(&file_data->in_anchor); 194bb99794aSGuido Kiener init_waitqueue_head(&file_data->wait_bulk_in); 1954ddc645fSGuido Kiener 1965b775f67SGreg Kroah-Hartman data = usb_get_intfdata(intf); 19788aecde4SDave Penkler /* Protect reference to data from file structure until release */ 1985b775f67SGreg Kroah-Hartman kref_get(&data->kref); 1995b775f67SGreg Kroah-Hartman 2004f3c8d6eSGuido Kiener mutex_lock(&data->io_mutex); 2014f3c8d6eSGuido Kiener file_data->data = data; 2025b775f67SGreg Kroah-Hartman 203739240a9SGuido Kiener atomic_set(&file_data->closing, 0); 204739240a9SGuido Kiener 20512dcaeb7SGuido Kiener /* copy default values from device settings */ 206048c6d88SGuido Kiener file_data->timeout = USBTMC_TIMEOUT; 20712dcaeb7SGuido Kiener file_data->term_char = data->TermChar; 20812dcaeb7SGuido Kiener file_data->term_char_enabled = data->TermCharEnabled; 209ec34d08eSGuido Kiener file_data->auto_abort = data->auto_abort; 210fbd83971SGuido Kiener file_data->eom_val = 1; 211048c6d88SGuido Kiener 2124f3c8d6eSGuido Kiener INIT_LIST_HEAD(&file_data->file_elem); 2134f3c8d6eSGuido Kiener spin_lock_irq(&data->dev_lock); 2144f3c8d6eSGuido Kiener list_add_tail(&file_data->file_elem, &data->file_list); 2154f3c8d6eSGuido Kiener spin_unlock_irq(&data->dev_lock); 2164f3c8d6eSGuido Kiener mutex_unlock(&data->io_mutex); 2174f3c8d6eSGuido Kiener 2184f3c8d6eSGuido Kiener /* Store pointer in file structure's private data field */ 2194f3c8d6eSGuido Kiener filp->private_data = file_data; 2204f3c8d6eSGuido Kiener 2214f3c8d6eSGuido Kiener return 0; 2225b775f67SGreg Kroah-Hartman } 2235b775f67SGreg Kroah-Hartman 2244ddc645fSGuido Kiener /* 2254ddc645fSGuido Kiener * usbtmc_flush - called before file handle is closed 2264ddc645fSGuido Kiener */ 2274ddc645fSGuido Kiener static int usbtmc_flush(struct file *file, fl_owner_t id) 2284ddc645fSGuido Kiener { 2294ddc645fSGuido Kiener struct usbtmc_file_data *file_data; 2304ddc645fSGuido Kiener struct usbtmc_device_data *data; 2314ddc645fSGuido Kiener 2324ddc645fSGuido Kiener file_data = file->private_data; 2334ddc645fSGuido Kiener if (file_data == NULL) 2344ddc645fSGuido Kiener return -ENODEV; 2354ddc645fSGuido Kiener 236739240a9SGuido Kiener atomic_set(&file_data->closing, 1); 2374ddc645fSGuido Kiener data = file_data->data; 2384ddc645fSGuido Kiener 2394ddc645fSGuido Kiener /* wait for io to stop */ 2404ddc645fSGuido Kiener mutex_lock(&data->io_mutex); 2414ddc645fSGuido Kiener 2424ddc645fSGuido Kiener usbtmc_draw_down(file_data); 2434ddc645fSGuido Kiener 2444ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 245bb99794aSGuido Kiener file_data->in_status = 0; 246bb99794aSGuido Kiener file_data->in_transfer_size = 0; 247bb99794aSGuido Kiener file_data->in_urbs_used = 0; 2484ddc645fSGuido Kiener file_data->out_status = 0; 2494ddc645fSGuido Kiener file_data->out_transfer_size = 0; 2504ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 2514ddc645fSGuido Kiener 2524ddc645fSGuido Kiener wake_up_interruptible_all(&data->waitq); 2534ddc645fSGuido Kiener mutex_unlock(&data->io_mutex); 2544ddc645fSGuido Kiener 2554ddc645fSGuido Kiener return 0; 2564ddc645fSGuido Kiener } 2574ddc645fSGuido Kiener 2585b775f67SGreg Kroah-Hartman static int usbtmc_release(struct inode *inode, struct file *file) 2595b775f67SGreg Kroah-Hartman { 2604f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data = file->private_data; 2615b775f67SGreg Kroah-Hartman 2624f3c8d6eSGuido Kiener /* prevent IO _AND_ usbtmc_interrupt */ 2634f3c8d6eSGuido Kiener mutex_lock(&file_data->data->io_mutex); 2644f3c8d6eSGuido Kiener spin_lock_irq(&file_data->data->dev_lock); 2654f3c8d6eSGuido Kiener 2664f3c8d6eSGuido Kiener list_del(&file_data->file_elem); 2674f3c8d6eSGuido Kiener 2684f3c8d6eSGuido Kiener spin_unlock_irq(&file_data->data->dev_lock); 2694f3c8d6eSGuido Kiener mutex_unlock(&file_data->data->io_mutex); 2704f3c8d6eSGuido Kiener 2714f3c8d6eSGuido Kiener kref_put(&file_data->data->kref, usbtmc_delete); 2724f3c8d6eSGuido Kiener file_data->data = NULL; 2734f3c8d6eSGuido Kiener kfree(file_data); 2745b775f67SGreg Kroah-Hartman return 0; 2755b775f67SGreg Kroah-Hartman } 2765b775f67SGreg Kroah-Hartman 277cbe743f1SGuido Kiener static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data, 278cbe743f1SGuido Kiener u8 tag) 2795b775f67SGreg Kroah-Hartman { 280b361a6e3SChris Malley u8 *buffer; 2815b775f67SGreg Kroah-Hartman struct device *dev; 2825b775f67SGreg Kroah-Hartman int rv; 2835b775f67SGreg Kroah-Hartman int n; 2845b775f67SGreg Kroah-Hartman int actual; 2855b775f67SGreg Kroah-Hartman 2865b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 287cbe743f1SGuido Kiener buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL); 2885b775f67SGreg Kroah-Hartman if (!buffer) 2895b775f67SGreg Kroah-Hartman return -ENOMEM; 2905b775f67SGreg Kroah-Hartman 2915b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 2925b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 2935b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, 2945b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 295cbe743f1SGuido Kiener tag, data->bulk_in, 296cbe743f1SGuido Kiener buffer, 2, USB_CTRL_GET_TIMEOUT); 2975b775f67SGreg Kroah-Hartman 2985b775f67SGreg Kroah-Hartman if (rv < 0) { 2995b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 3005b775f67SGreg Kroah-Hartman goto exit; 3015b775f67SGreg Kroah-Hartman } 3025b775f67SGreg Kroah-Hartman 303cbe743f1SGuido Kiener dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n", 304cbe743f1SGuido Kiener buffer[0], buffer[1]); 3055b775f67SGreg Kroah-Hartman 3065b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_FAILED) { 307cbe743f1SGuido Kiener /* No transfer in progress and the Bulk-OUT FIFO is empty. */ 3085b775f67SGreg Kroah-Hartman rv = 0; 3095b775f67SGreg Kroah-Hartman goto exit; 3105b775f67SGreg Kroah-Hartman } 3115b775f67SGreg Kroah-Hartman 312cbe743f1SGuido Kiener if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) { 313cbe743f1SGuido Kiener /* The device returns this status if either: 314cbe743f1SGuido Kiener * - There is a transfer in progress, but the specified bTag 315cbe743f1SGuido Kiener * does not match. 316cbe743f1SGuido Kiener * - There is no transfer in progress, but the Bulk-OUT FIFO 317cbe743f1SGuido Kiener * is not empty. 318cbe743f1SGuido Kiener */ 319cbe743f1SGuido Kiener rv = -ENOMSG; 320cbe743f1SGuido Kiener goto exit; 321cbe743f1SGuido Kiener } 322cbe743f1SGuido Kiener 3235b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 3245b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", 3255b775f67SGreg Kroah-Hartman buffer[0]); 3265b775f67SGreg Kroah-Hartman rv = -EPERM; 3275b775f67SGreg Kroah-Hartman goto exit; 3285b775f67SGreg Kroah-Hartman } 3295b775f67SGreg Kroah-Hartman 3305b775f67SGreg Kroah-Hartman n = 0; 3315b775f67SGreg Kroah-Hartman 332cbe743f1SGuido Kiener usbtmc_abort_bulk_in_status: 3335b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 3345b775f67SGreg Kroah-Hartman 335cbe743f1SGuido Kiener /* Data must be present. So use low timeout 300 ms */ 3365b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 3375b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 3385b775f67SGreg Kroah-Hartman data->bulk_in), 339cbe743f1SGuido Kiener buffer, USBTMC_BUFSIZE, 340cbe743f1SGuido Kiener &actual, 300); 341cbe743f1SGuido Kiener 342cbe743f1SGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1, 343cbe743f1SGuido Kiener buffer, actual, true); 3445b775f67SGreg Kroah-Hartman 3455b775f67SGreg Kroah-Hartman n++; 3465b775f67SGreg Kroah-Hartman 3475b775f67SGreg Kroah-Hartman if (rv < 0) { 3485b775f67SGreg Kroah-Hartman dev_err(dev, "usb_bulk_msg returned %d\n", rv); 349cbe743f1SGuido Kiener if (rv != -ETIMEDOUT) 3505b775f67SGreg Kroah-Hartman goto exit; 3515b775f67SGreg Kroah-Hartman } 3525b775f67SGreg Kroah-Hartman 353cbe743f1SGuido Kiener if (actual == USBTMC_BUFSIZE) 354cbe743f1SGuido Kiener goto usbtmc_abort_bulk_in_status; 355cbe743f1SGuido Kiener 356cbe743f1SGuido Kiener if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) { 3575b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 3585b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 3595b775f67SGreg Kroah-Hartman rv = -EPERM; 3605b775f67SGreg Kroah-Hartman goto exit; 3615b775f67SGreg Kroah-Hartman } 3625b775f67SGreg Kroah-Hartman 3635b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 3645b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 3655b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, 3665b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 3675b775f67SGreg Kroah-Hartman 0, data->bulk_in, buffer, 0x08, 368cbe743f1SGuido Kiener USB_CTRL_GET_TIMEOUT); 3695b775f67SGreg Kroah-Hartman 3705b775f67SGreg Kroah-Hartman if (rv < 0) { 3715b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 3725b775f67SGreg Kroah-Hartman goto exit; 3735b775f67SGreg Kroah-Hartman } 3745b775f67SGreg Kroah-Hartman 375cbe743f1SGuido Kiener dev_dbg(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); 3765b775f67SGreg Kroah-Hartman 3775b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) { 3785b775f67SGreg Kroah-Hartman rv = 0; 3795b775f67SGreg Kroah-Hartman goto exit; 3805b775f67SGreg Kroah-Hartman } 3815b775f67SGreg Kroah-Hartman 3825b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_PENDING) { 383cbe743f1SGuido Kiener dev_err(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); 3845b775f67SGreg Kroah-Hartman rv = -EPERM; 3855b775f67SGreg Kroah-Hartman goto exit; 3865b775f67SGreg Kroah-Hartman } 3875b775f67SGreg Kroah-Hartman 388cbe743f1SGuido Kiener if ((buffer[1] & 1) > 0) { 389cbe743f1SGuido Kiener /* The device has 1 or more queued packets the Host can read */ 3905b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_in_status; 391cbe743f1SGuido Kiener } 3925b775f67SGreg Kroah-Hartman 393cbe743f1SGuido Kiener /* The Host must send CHECK_ABORT_BULK_IN_STATUS at a later time. */ 394cbe743f1SGuido Kiener rv = -EAGAIN; 3955b775f67SGreg Kroah-Hartman exit: 3965b775f67SGreg Kroah-Hartman kfree(buffer); 3975b775f67SGreg Kroah-Hartman return rv; 398cbe743f1SGuido Kiener } 3995b775f67SGreg Kroah-Hartman 400cbe743f1SGuido Kiener static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) 401cbe743f1SGuido Kiener { 402cbe743f1SGuido Kiener return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read); 4035b775f67SGreg Kroah-Hartman } 4045b775f67SGreg Kroah-Hartman 4050e59088eSGuido Kiener static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data, 4060e59088eSGuido Kiener u8 tag) 4075b775f67SGreg Kroah-Hartman { 4085b775f67SGreg Kroah-Hartman struct device *dev; 4095b775f67SGreg Kroah-Hartman u8 *buffer; 4105b775f67SGreg Kroah-Hartman int rv; 4115b775f67SGreg Kroah-Hartman int n; 4125b775f67SGreg Kroah-Hartman 4135b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 4145b775f67SGreg Kroah-Hartman 4155b775f67SGreg Kroah-Hartman buffer = kmalloc(8, GFP_KERNEL); 4165b775f67SGreg Kroah-Hartman if (!buffer) 4175b775f67SGreg Kroah-Hartman return -ENOMEM; 4185b775f67SGreg Kroah-Hartman 4195b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 4205b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 4215b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, 4225b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 4230e59088eSGuido Kiener tag, data->bulk_out, 4240e59088eSGuido Kiener buffer, 2, USB_CTRL_GET_TIMEOUT); 4255b775f67SGreg Kroah-Hartman 4265b775f67SGreg Kroah-Hartman if (rv < 0) { 4275b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 4285b775f67SGreg Kroah-Hartman goto exit; 4295b775f67SGreg Kroah-Hartman } 4305b775f67SGreg Kroah-Hartman 4315b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", buffer[0]); 4325b775f67SGreg Kroah-Hartman 4335b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 4345b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", 4355b775f67SGreg Kroah-Hartman buffer[0]); 4365b775f67SGreg Kroah-Hartman rv = -EPERM; 4375b775f67SGreg Kroah-Hartman goto exit; 4385b775f67SGreg Kroah-Hartman } 4395b775f67SGreg Kroah-Hartman 4405b775f67SGreg Kroah-Hartman n = 0; 4415b775f67SGreg Kroah-Hartman 4425b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_check_status: 4430e59088eSGuido Kiener /* do not stress device with subsequent requests */ 4440e59088eSGuido Kiener msleep(50); 4455b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 4465b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 4475b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, 4485b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 4495b775f67SGreg Kroah-Hartman 0, data->bulk_out, buffer, 0x08, 4500e59088eSGuido Kiener USB_CTRL_GET_TIMEOUT); 4515b775f67SGreg Kroah-Hartman n++; 4525b775f67SGreg Kroah-Hartman if (rv < 0) { 4535b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 4545b775f67SGreg Kroah-Hartman goto exit; 4555b775f67SGreg Kroah-Hartman } 4565b775f67SGreg Kroah-Hartman 4575b775f67SGreg Kroah-Hartman dev_dbg(dev, "CHECK_ABORT_BULK_OUT returned %x\n", buffer[0]); 4585b775f67SGreg Kroah-Hartman 4595b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) 4605b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_out_clear_halt; 4615b775f67SGreg Kroah-Hartman 4625b775f67SGreg Kroah-Hartman if ((buffer[0] == USBTMC_STATUS_PENDING) && 4635b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)) 4645b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_out_check_status; 4655b775f67SGreg Kroah-Hartman 4665b775f67SGreg Kroah-Hartman rv = -EPERM; 4675b775f67SGreg Kroah-Hartman goto exit; 4685b775f67SGreg Kroah-Hartman 4695b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_clear_halt: 4703342ecdaSSarah Sharp rv = usb_clear_halt(data->usb_dev, 4713342ecdaSSarah Sharp usb_sndbulkpipe(data->usb_dev, data->bulk_out)); 4725b775f67SGreg Kroah-Hartman 4735b775f67SGreg Kroah-Hartman if (rv < 0) { 4745b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 4755b775f67SGreg Kroah-Hartman goto exit; 4765b775f67SGreg Kroah-Hartman } 4775b775f67SGreg Kroah-Hartman rv = 0; 4785b775f67SGreg Kroah-Hartman 4795b775f67SGreg Kroah-Hartman exit: 4805b775f67SGreg Kroah-Hartman kfree(buffer); 4815b775f67SGreg Kroah-Hartman return rv; 4825b775f67SGreg Kroah-Hartman } 4835b775f67SGreg Kroah-Hartman 4840e59088eSGuido Kiener static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) 4850e59088eSGuido Kiener { 4860e59088eSGuido Kiener return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write); 4870e59088eSGuido Kiener } 4880e59088eSGuido Kiener 4894f3c8d6eSGuido Kiener static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, 490dbf3e7f6SDave Penkler void __user *arg) 491dbf3e7f6SDave Penkler { 4924f3c8d6eSGuido Kiener struct usbtmc_device_data *data = file_data->data; 493dbf3e7f6SDave Penkler struct device *dev = &data->intf->dev; 4944f3c8d6eSGuido Kiener int srq_asserted = 0; 495dbf3e7f6SDave Penkler u8 *buffer; 496dbf3e7f6SDave Penkler u8 tag; 497dbf3e7f6SDave Penkler __u8 stb; 498dbf3e7f6SDave Penkler int rv; 499dbf3e7f6SDave Penkler 500dbf3e7f6SDave Penkler dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n", 501dbf3e7f6SDave Penkler data->iin_ep_present); 502dbf3e7f6SDave Penkler 5034f3c8d6eSGuido Kiener spin_lock_irq(&data->dev_lock); 5044f3c8d6eSGuido Kiener srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted); 5054f3c8d6eSGuido Kiener if (srq_asserted) { 5064f3c8d6eSGuido Kiener /* a STB with SRQ is already received */ 5074f3c8d6eSGuido Kiener stb = file_data->srq_byte; 5084f3c8d6eSGuido Kiener spin_unlock_irq(&data->dev_lock); 5094f3c8d6eSGuido Kiener rv = put_user(stb, (__u8 __user *)arg); 5104f3c8d6eSGuido Kiener dev_dbg(dev, "stb:0x%02x with srq received %d\n", 5114f3c8d6eSGuido Kiener (unsigned int)stb, rv); 5124f3c8d6eSGuido Kiener return rv; 5134f3c8d6eSGuido Kiener } 5144f3c8d6eSGuido Kiener spin_unlock_irq(&data->dev_lock); 5154f3c8d6eSGuido Kiener 516dbf3e7f6SDave Penkler buffer = kmalloc(8, GFP_KERNEL); 517dbf3e7f6SDave Penkler if (!buffer) 518dbf3e7f6SDave Penkler return -ENOMEM; 519dbf3e7f6SDave Penkler 520dbf3e7f6SDave Penkler atomic_set(&data->iin_data_valid, 0); 521dbf3e7f6SDave Penkler 522dbf3e7f6SDave Penkler rv = usb_control_msg(data->usb_dev, 523dbf3e7f6SDave Penkler usb_rcvctrlpipe(data->usb_dev, 0), 524dbf3e7f6SDave Penkler USBTMC488_REQUEST_READ_STATUS_BYTE, 525dbf3e7f6SDave Penkler USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 526dbf3e7f6SDave Penkler data->iin_bTag, 527dbf3e7f6SDave Penkler data->ifnum, 52863c97bbaSGuido Kiener buffer, 0x03, USB_CTRL_GET_TIMEOUT); 529dbf3e7f6SDave Penkler if (rv < 0) { 530dbf3e7f6SDave Penkler dev_err(dev, "stb usb_control_msg returned %d\n", rv); 531dbf3e7f6SDave Penkler goto exit; 532dbf3e7f6SDave Penkler } 533dbf3e7f6SDave Penkler 534dbf3e7f6SDave Penkler if (buffer[0] != USBTMC_STATUS_SUCCESS) { 535dbf3e7f6SDave Penkler dev_err(dev, "control status returned %x\n", buffer[0]); 536dbf3e7f6SDave Penkler rv = -EIO; 537dbf3e7f6SDave Penkler goto exit; 538dbf3e7f6SDave Penkler } 539dbf3e7f6SDave Penkler 540dbf3e7f6SDave Penkler if (data->iin_ep_present) { 541dbf3e7f6SDave Penkler rv = wait_event_interruptible_timeout( 542dbf3e7f6SDave Penkler data->waitq, 543dbf3e7f6SDave Penkler atomic_read(&data->iin_data_valid) != 0, 544048c6d88SGuido Kiener file_data->timeout); 545dbf3e7f6SDave Penkler if (rv < 0) { 546dbf3e7f6SDave Penkler dev_dbg(dev, "wait interrupted %d\n", rv); 547dbf3e7f6SDave Penkler goto exit; 548dbf3e7f6SDave Penkler } 549dbf3e7f6SDave Penkler 550dbf3e7f6SDave Penkler if (rv == 0) { 551dbf3e7f6SDave Penkler dev_dbg(dev, "wait timed out\n"); 55219e6c57eSGuido Kiener rv = -ETIMEDOUT; 553dbf3e7f6SDave Penkler goto exit; 554dbf3e7f6SDave Penkler } 555dbf3e7f6SDave Penkler 556dbf3e7f6SDave Penkler tag = data->bNotify1 & 0x7f; 557dbf3e7f6SDave Penkler if (tag != data->iin_bTag) { 558dbf3e7f6SDave Penkler dev_err(dev, "expected bTag %x got %x\n", 559dbf3e7f6SDave Penkler data->iin_bTag, tag); 560dbf3e7f6SDave Penkler } 561dbf3e7f6SDave Penkler 562dbf3e7f6SDave Penkler stb = data->bNotify2; 563dbf3e7f6SDave Penkler } else { 564dbf3e7f6SDave Penkler stb = buffer[2]; 565dbf3e7f6SDave Penkler } 566dbf3e7f6SDave Penkler 5674f3c8d6eSGuido Kiener rv = put_user(stb, (__u8 __user *)arg); 5684f3c8d6eSGuido Kiener dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)stb, rv); 569dbf3e7f6SDave Penkler 570dbf3e7f6SDave Penkler exit: 571dbf3e7f6SDave Penkler /* bump interrupt bTag */ 572dbf3e7f6SDave Penkler data->iin_bTag += 1; 573dbf3e7f6SDave Penkler if (data->iin_bTag > 127) 574dbf3e7f6SDave Penkler /* 1 is for SRQ see USBTMC-USB488 subclass spec section 4.3.1 */ 575dbf3e7f6SDave Penkler data->iin_bTag = 2; 576dbf3e7f6SDave Penkler 577dbf3e7f6SDave Penkler kfree(buffer); 578dbf3e7f6SDave Penkler return rv; 579dbf3e7f6SDave Penkler } 580dbf3e7f6SDave Penkler 581739240a9SGuido Kiener static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, 582739240a9SGuido Kiener __u32 __user *arg) 583739240a9SGuido Kiener { 584739240a9SGuido Kiener struct usbtmc_device_data *data = file_data->data; 585739240a9SGuido Kiener struct device *dev = &data->intf->dev; 586739240a9SGuido Kiener int rv; 587739240a9SGuido Kiener u32 timeout; 588739240a9SGuido Kiener unsigned long expire; 589739240a9SGuido Kiener 590739240a9SGuido Kiener if (!data->iin_ep_present) { 591739240a9SGuido Kiener dev_dbg(dev, "no interrupt endpoint present\n"); 592739240a9SGuido Kiener return -EFAULT; 593739240a9SGuido Kiener } 594739240a9SGuido Kiener 595739240a9SGuido Kiener if (get_user(timeout, arg)) 596739240a9SGuido Kiener return -EFAULT; 597739240a9SGuido Kiener 598739240a9SGuido Kiener expire = msecs_to_jiffies(timeout); 599739240a9SGuido Kiener 600739240a9SGuido Kiener mutex_unlock(&data->io_mutex); 601739240a9SGuido Kiener 602739240a9SGuido Kiener rv = wait_event_interruptible_timeout( 603739240a9SGuido Kiener data->waitq, 604739240a9SGuido Kiener atomic_read(&file_data->srq_asserted) != 0 || 605739240a9SGuido Kiener atomic_read(&file_data->closing), 606739240a9SGuido Kiener expire); 607739240a9SGuido Kiener 608739240a9SGuido Kiener mutex_lock(&data->io_mutex); 609739240a9SGuido Kiener 610739240a9SGuido Kiener /* Note! disconnect or close could be called in the meantime */ 611739240a9SGuido Kiener if (atomic_read(&file_data->closing) || data->zombie) 612739240a9SGuido Kiener rv = -ENODEV; 613739240a9SGuido Kiener 614739240a9SGuido Kiener if (rv < 0) { 615739240a9SGuido Kiener /* dev can be invalid now! */ 616739240a9SGuido Kiener pr_debug("%s - wait interrupted %d\n", __func__, rv); 617739240a9SGuido Kiener return rv; 618739240a9SGuido Kiener } 619739240a9SGuido Kiener 620739240a9SGuido Kiener if (rv == 0) { 621739240a9SGuido Kiener dev_dbg(dev, "%s - wait timed out\n", __func__); 622739240a9SGuido Kiener return -ETIMEDOUT; 623739240a9SGuido Kiener } 624739240a9SGuido Kiener 625739240a9SGuido Kiener dev_dbg(dev, "%s - srq asserted\n", __func__); 626739240a9SGuido Kiener return 0; 627739240a9SGuido Kiener } 628739240a9SGuido Kiener 629379d3d33SDave Penkler static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data, 630379d3d33SDave Penkler void __user *arg, unsigned int cmd) 631379d3d33SDave Penkler { 632379d3d33SDave Penkler struct device *dev = &data->intf->dev; 633379d3d33SDave Penkler __u8 val; 634379d3d33SDave Penkler u8 *buffer; 635379d3d33SDave Penkler u16 wValue; 636379d3d33SDave Penkler int rv; 637379d3d33SDave Penkler 638379d3d33SDave Penkler if (!(data->usb488_caps & USBTMC488_CAPABILITY_SIMPLE)) 639379d3d33SDave Penkler return -EINVAL; 640379d3d33SDave Penkler 641379d3d33SDave Penkler buffer = kmalloc(8, GFP_KERNEL); 642379d3d33SDave Penkler if (!buffer) 643379d3d33SDave Penkler return -ENOMEM; 644379d3d33SDave Penkler 645379d3d33SDave Penkler if (cmd == USBTMC488_REQUEST_REN_CONTROL) { 646379d3d33SDave Penkler rv = copy_from_user(&val, arg, sizeof(val)); 647379d3d33SDave Penkler if (rv) { 648379d3d33SDave Penkler rv = -EFAULT; 649379d3d33SDave Penkler goto exit; 650379d3d33SDave Penkler } 651379d3d33SDave Penkler wValue = val ? 1 : 0; 652379d3d33SDave Penkler } else { 653379d3d33SDave Penkler wValue = 0; 654379d3d33SDave Penkler } 655379d3d33SDave Penkler 656379d3d33SDave Penkler rv = usb_control_msg(data->usb_dev, 657379d3d33SDave Penkler usb_rcvctrlpipe(data->usb_dev, 0), 658379d3d33SDave Penkler cmd, 659379d3d33SDave Penkler USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 660379d3d33SDave Penkler wValue, 661379d3d33SDave Penkler data->ifnum, 66263c97bbaSGuido Kiener buffer, 0x01, USB_CTRL_GET_TIMEOUT); 663379d3d33SDave Penkler if (rv < 0) { 664379d3d33SDave Penkler dev_err(dev, "simple usb_control_msg failed %d\n", rv); 665379d3d33SDave Penkler goto exit; 666379d3d33SDave Penkler } else if (rv != 1) { 667379d3d33SDave Penkler dev_warn(dev, "simple usb_control_msg returned %d\n", rv); 668379d3d33SDave Penkler rv = -EIO; 669379d3d33SDave Penkler goto exit; 670379d3d33SDave Penkler } 671379d3d33SDave Penkler 672379d3d33SDave Penkler if (buffer[0] != USBTMC_STATUS_SUCCESS) { 673379d3d33SDave Penkler dev_err(dev, "simple control status returned %x\n", buffer[0]); 674379d3d33SDave Penkler rv = -EIO; 675379d3d33SDave Penkler goto exit; 676379d3d33SDave Penkler } 677379d3d33SDave Penkler rv = 0; 678379d3d33SDave Penkler 679379d3d33SDave Penkler exit: 680379d3d33SDave Penkler kfree(buffer); 681379d3d33SDave Penkler return rv; 682379d3d33SDave Penkler } 683379d3d33SDave Penkler 68488d9b2b3SAlexandre Peixoto Ferreira /* 685fe78a7c6SGuido Kiener * Sends a TRIGGER Bulk-OUT command message 686fe78a7c6SGuido Kiener * See the USBTMC-USB488 specification, Table 2. 687fe78a7c6SGuido Kiener * 688fe78a7c6SGuido Kiener * Also updates bTag_last_write. 689fe78a7c6SGuido Kiener */ 690fe78a7c6SGuido Kiener static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data) 691fe78a7c6SGuido Kiener { 692fe78a7c6SGuido Kiener struct usbtmc_device_data *data = file_data->data; 693fe78a7c6SGuido Kiener int retval; 694fe78a7c6SGuido Kiener u8 *buffer; 695fe78a7c6SGuido Kiener int actual; 696fe78a7c6SGuido Kiener 697fe78a7c6SGuido Kiener buffer = kzalloc(USBTMC_HEADER_SIZE, GFP_KERNEL); 698fe78a7c6SGuido Kiener if (!buffer) 699fe78a7c6SGuido Kiener return -ENOMEM; 700fe78a7c6SGuido Kiener 701fe78a7c6SGuido Kiener buffer[0] = 128; 702fe78a7c6SGuido Kiener buffer[1] = data->bTag; 703fe78a7c6SGuido Kiener buffer[2] = ~data->bTag; 704fe78a7c6SGuido Kiener 705fe78a7c6SGuido Kiener retval = usb_bulk_msg(data->usb_dev, 706fe78a7c6SGuido Kiener usb_sndbulkpipe(data->usb_dev, 707fe78a7c6SGuido Kiener data->bulk_out), 708fe78a7c6SGuido Kiener buffer, USBTMC_HEADER_SIZE, 709fe78a7c6SGuido Kiener &actual, file_data->timeout); 710fe78a7c6SGuido Kiener 711fe78a7c6SGuido Kiener /* Store bTag (in case we need to abort) */ 712fe78a7c6SGuido Kiener data->bTag_last_write = data->bTag; 713fe78a7c6SGuido Kiener 714fe78a7c6SGuido Kiener /* Increment bTag -- and increment again if zero */ 715fe78a7c6SGuido Kiener data->bTag++; 716fe78a7c6SGuido Kiener if (!data->bTag) 717fe78a7c6SGuido Kiener data->bTag++; 718fe78a7c6SGuido Kiener 719fe78a7c6SGuido Kiener kfree(buffer); 720fe78a7c6SGuido Kiener if (retval < 0) { 721fe78a7c6SGuido Kiener dev_err(&data->intf->dev, "%s returned %d\n", 722fe78a7c6SGuido Kiener __func__, retval); 723fe78a7c6SGuido Kiener return retval; 724fe78a7c6SGuido Kiener } 725fe78a7c6SGuido Kiener 726fe78a7c6SGuido Kiener return 0; 727fe78a7c6SGuido Kiener } 728fe78a7c6SGuido Kiener 7294ddc645fSGuido Kiener static struct urb *usbtmc_create_urb(void) 7304ddc645fSGuido Kiener { 7314ddc645fSGuido Kiener const size_t bufsize = USBTMC_BUFSIZE; 7324ddc645fSGuido Kiener u8 *dmabuf = NULL; 7334ddc645fSGuido Kiener struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); 7344ddc645fSGuido Kiener 7354ddc645fSGuido Kiener if (!urb) 7364ddc645fSGuido Kiener return NULL; 7374ddc645fSGuido Kiener 7384ddc645fSGuido Kiener dmabuf = kmalloc(bufsize, GFP_KERNEL); 7394ddc645fSGuido Kiener if (!dmabuf) { 7404ddc645fSGuido Kiener usb_free_urb(urb); 7414ddc645fSGuido Kiener return NULL; 7424ddc645fSGuido Kiener } 7434ddc645fSGuido Kiener 7444ddc645fSGuido Kiener urb->transfer_buffer = dmabuf; 7454ddc645fSGuido Kiener urb->transfer_buffer_length = bufsize; 7464ddc645fSGuido Kiener urb->transfer_flags |= URB_FREE_BUFFER; 7474ddc645fSGuido Kiener return urb; 7484ddc645fSGuido Kiener } 7494ddc645fSGuido Kiener 750bb99794aSGuido Kiener static void usbtmc_read_bulk_cb(struct urb *urb) 751bb99794aSGuido Kiener { 752bb99794aSGuido Kiener struct usbtmc_file_data *file_data = urb->context; 753bb99794aSGuido Kiener int status = urb->status; 754bb99794aSGuido Kiener unsigned long flags; 755bb99794aSGuido Kiener 756bb99794aSGuido Kiener /* sync/async unlink faults aren't errors */ 757bb99794aSGuido Kiener if (status) { 758bb99794aSGuido Kiener if (!(/* status == -ENOENT || */ 759bb99794aSGuido Kiener status == -ECONNRESET || 760bb99794aSGuido Kiener status == -EREMOTEIO || /* Short packet */ 761bb99794aSGuido Kiener status == -ESHUTDOWN)) 762bb99794aSGuido Kiener dev_err(&file_data->data->intf->dev, 763bb99794aSGuido Kiener "%s - nonzero read bulk status received: %d\n", 764bb99794aSGuido Kiener __func__, status); 765bb99794aSGuido Kiener 766bb99794aSGuido Kiener spin_lock_irqsave(&file_data->err_lock, flags); 767bb99794aSGuido Kiener if (!file_data->in_status) 768bb99794aSGuido Kiener file_data->in_status = status; 769bb99794aSGuido Kiener spin_unlock_irqrestore(&file_data->err_lock, flags); 770bb99794aSGuido Kiener } 771bb99794aSGuido Kiener 772bb99794aSGuido Kiener spin_lock_irqsave(&file_data->err_lock, flags); 773bb99794aSGuido Kiener file_data->in_transfer_size += urb->actual_length; 774bb99794aSGuido Kiener dev_dbg(&file_data->data->intf->dev, 775bb99794aSGuido Kiener "%s - total size: %u current: %d status: %d\n", 776bb99794aSGuido Kiener __func__, file_data->in_transfer_size, 777bb99794aSGuido Kiener urb->actual_length, status); 778bb99794aSGuido Kiener spin_unlock_irqrestore(&file_data->err_lock, flags); 779bb99794aSGuido Kiener usb_anchor_urb(urb, &file_data->in_anchor); 780bb99794aSGuido Kiener 781bb99794aSGuido Kiener wake_up_interruptible(&file_data->wait_bulk_in); 782bb99794aSGuido Kiener wake_up_interruptible(&file_data->data->waitq); 783bb99794aSGuido Kiener } 784bb99794aSGuido Kiener 785bb99794aSGuido Kiener static inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data) 786bb99794aSGuido Kiener { 787bb99794aSGuido Kiener bool data_or_error; 788bb99794aSGuido Kiener 789bb99794aSGuido Kiener spin_lock_irq(&file_data->err_lock); 790bb99794aSGuido Kiener data_or_error = !usb_anchor_empty(&file_data->in_anchor) 791bb99794aSGuido Kiener || file_data->in_status; 792bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 793bb99794aSGuido Kiener dev_dbg(&file_data->data->intf->dev, "%s: returns %d\n", __func__, 794bb99794aSGuido Kiener data_or_error); 795bb99794aSGuido Kiener return data_or_error; 796bb99794aSGuido Kiener } 797bb99794aSGuido Kiener 798bb99794aSGuido Kiener static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, 799bb99794aSGuido Kiener void __user *user_buffer, 800bb99794aSGuido Kiener u32 transfer_size, 801bb99794aSGuido Kiener u32 *transferred, 802bb99794aSGuido Kiener u32 flags) 803bb99794aSGuido Kiener { 804bb99794aSGuido Kiener struct usbtmc_device_data *data = file_data->data; 805bb99794aSGuido Kiener struct device *dev = &data->intf->dev; 806bb99794aSGuido Kiener u32 done = 0; 807bb99794aSGuido Kiener u32 remaining; 808bb99794aSGuido Kiener const u32 bufsize = USBTMC_BUFSIZE; 809bb99794aSGuido Kiener int retval = 0; 810bb99794aSGuido Kiener u32 max_transfer_size; 811bb99794aSGuido Kiener unsigned long expire; 812bb99794aSGuido Kiener int bufcount = 1; 813bb99794aSGuido Kiener int again = 0; 814bb99794aSGuido Kiener 815bb99794aSGuido Kiener /* mutex already locked */ 816bb99794aSGuido Kiener 817bb99794aSGuido Kiener *transferred = done; 818bb99794aSGuido Kiener 819bb99794aSGuido Kiener max_transfer_size = transfer_size; 820bb99794aSGuido Kiener 821bb99794aSGuido Kiener if (flags & USBTMC_FLAG_IGNORE_TRAILER) { 822bb99794aSGuido Kiener /* The device may send extra alignment bytes (up to 823bb99794aSGuido Kiener * wMaxPacketSize – 1) to avoid sending a zero-length 824bb99794aSGuido Kiener * packet 825bb99794aSGuido Kiener */ 826bb99794aSGuido Kiener remaining = transfer_size; 827bb99794aSGuido Kiener if ((max_transfer_size % data->wMaxPacketSize) == 0) 828bb99794aSGuido Kiener max_transfer_size += (data->wMaxPacketSize - 1); 829bb99794aSGuido Kiener } else { 830bb99794aSGuido Kiener /* round down to bufsize to avoid truncated data left */ 831bb99794aSGuido Kiener if (max_transfer_size > bufsize) { 832bb99794aSGuido Kiener max_transfer_size = 833bb99794aSGuido Kiener roundup(max_transfer_size + 1 - bufsize, 834bb99794aSGuido Kiener bufsize); 835bb99794aSGuido Kiener } 836bb99794aSGuido Kiener remaining = max_transfer_size; 837bb99794aSGuido Kiener } 838bb99794aSGuido Kiener 839bb99794aSGuido Kiener spin_lock_irq(&file_data->err_lock); 840bb99794aSGuido Kiener 841bb99794aSGuido Kiener if (file_data->in_status) { 842bb99794aSGuido Kiener /* return the very first error */ 843bb99794aSGuido Kiener retval = file_data->in_status; 844bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 845bb99794aSGuido Kiener goto error; 846bb99794aSGuido Kiener } 847bb99794aSGuido Kiener 848bb99794aSGuido Kiener if (flags & USBTMC_FLAG_ASYNC) { 849bb99794aSGuido Kiener if (usb_anchor_empty(&file_data->in_anchor)) 850bb99794aSGuido Kiener again = 1; 851bb99794aSGuido Kiener 852bb99794aSGuido Kiener if (file_data->in_urbs_used == 0) { 853bb99794aSGuido Kiener file_data->in_transfer_size = 0; 854bb99794aSGuido Kiener file_data->in_status = 0; 855bb99794aSGuido Kiener } 856bb99794aSGuido Kiener } else { 857bb99794aSGuido Kiener file_data->in_transfer_size = 0; 858bb99794aSGuido Kiener file_data->in_status = 0; 859bb99794aSGuido Kiener } 860bb99794aSGuido Kiener 861bb99794aSGuido Kiener if (max_transfer_size == 0) { 862bb99794aSGuido Kiener bufcount = 0; 863bb99794aSGuido Kiener } else { 864bb99794aSGuido Kiener bufcount = roundup(max_transfer_size, bufsize) / bufsize; 865bb99794aSGuido Kiener if (bufcount > file_data->in_urbs_used) 866bb99794aSGuido Kiener bufcount -= file_data->in_urbs_used; 867bb99794aSGuido Kiener else 868bb99794aSGuido Kiener bufcount = 0; 869bb99794aSGuido Kiener 870bb99794aSGuido Kiener if (bufcount + file_data->in_urbs_used > MAX_URBS_IN_FLIGHT) { 871bb99794aSGuido Kiener bufcount = MAX_URBS_IN_FLIGHT - 872bb99794aSGuido Kiener file_data->in_urbs_used; 873bb99794aSGuido Kiener } 874bb99794aSGuido Kiener } 875bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 876bb99794aSGuido Kiener 877bb99794aSGuido Kiener dev_dbg(dev, "%s: requested=%u flags=0x%X size=%u bufs=%d used=%d\n", 878bb99794aSGuido Kiener __func__, transfer_size, flags, 879bb99794aSGuido Kiener max_transfer_size, bufcount, file_data->in_urbs_used); 880bb99794aSGuido Kiener 881bb99794aSGuido Kiener while (bufcount > 0) { 882bb99794aSGuido Kiener u8 *dmabuf = NULL; 883bb99794aSGuido Kiener struct urb *urb = usbtmc_create_urb(); 884bb99794aSGuido Kiener 885bb99794aSGuido Kiener if (!urb) { 886bb99794aSGuido Kiener retval = -ENOMEM; 887bb99794aSGuido Kiener goto error; 888bb99794aSGuido Kiener } 889bb99794aSGuido Kiener 890bb99794aSGuido Kiener dmabuf = urb->transfer_buffer; 891bb99794aSGuido Kiener 892bb99794aSGuido Kiener usb_fill_bulk_urb(urb, data->usb_dev, 893bb99794aSGuido Kiener usb_rcvbulkpipe(data->usb_dev, data->bulk_in), 894bb99794aSGuido Kiener dmabuf, bufsize, 895bb99794aSGuido Kiener usbtmc_read_bulk_cb, file_data); 896bb99794aSGuido Kiener 897bb99794aSGuido Kiener usb_anchor_urb(urb, &file_data->submitted); 898bb99794aSGuido Kiener retval = usb_submit_urb(urb, GFP_KERNEL); 899bb99794aSGuido Kiener /* urb is anchored. We can release our reference. */ 900bb99794aSGuido Kiener usb_free_urb(urb); 901bb99794aSGuido Kiener if (unlikely(retval)) { 902bb99794aSGuido Kiener usb_unanchor_urb(urb); 903bb99794aSGuido Kiener goto error; 904bb99794aSGuido Kiener } 905bb99794aSGuido Kiener file_data->in_urbs_used++; 906bb99794aSGuido Kiener bufcount--; 907bb99794aSGuido Kiener } 908bb99794aSGuido Kiener 909bb99794aSGuido Kiener if (again) { 910bb99794aSGuido Kiener dev_dbg(dev, "%s: ret=again\n", __func__); 911bb99794aSGuido Kiener return -EAGAIN; 912bb99794aSGuido Kiener } 913bb99794aSGuido Kiener 914bb99794aSGuido Kiener if (user_buffer == NULL) 915bb99794aSGuido Kiener return -EINVAL; 916bb99794aSGuido Kiener 917bb99794aSGuido Kiener expire = msecs_to_jiffies(file_data->timeout); 918bb99794aSGuido Kiener 919bb99794aSGuido Kiener while (max_transfer_size > 0) { 920bb99794aSGuido Kiener u32 this_part; 921bb99794aSGuido Kiener struct urb *urb = NULL; 922bb99794aSGuido Kiener 923bb99794aSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC)) { 924bb99794aSGuido Kiener dev_dbg(dev, "%s: before wait time %lu\n", 925bb99794aSGuido Kiener __func__, expire); 926bb99794aSGuido Kiener retval = wait_event_interruptible_timeout( 927bb99794aSGuido Kiener file_data->wait_bulk_in, 928bb99794aSGuido Kiener usbtmc_do_transfer(file_data), 929bb99794aSGuido Kiener expire); 930bb99794aSGuido Kiener 931bb99794aSGuido Kiener dev_dbg(dev, "%s: wait returned %d\n", 932bb99794aSGuido Kiener __func__, retval); 933bb99794aSGuido Kiener 934bb99794aSGuido Kiener if (retval <= 0) { 935bb99794aSGuido Kiener if (retval == 0) 936bb99794aSGuido Kiener retval = -ETIMEDOUT; 937bb99794aSGuido Kiener goto error; 938bb99794aSGuido Kiener } 939bb99794aSGuido Kiener } 940bb99794aSGuido Kiener 941bb99794aSGuido Kiener urb = usb_get_from_anchor(&file_data->in_anchor); 942bb99794aSGuido Kiener if (!urb) { 943bb99794aSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC)) { 944bb99794aSGuido Kiener /* synchronous case: must not happen */ 945bb99794aSGuido Kiener retval = -EFAULT; 946bb99794aSGuido Kiener goto error; 947bb99794aSGuido Kiener } 948bb99794aSGuido Kiener 949bb99794aSGuido Kiener /* asynchronous case: ready, do not block or wait */ 950bb99794aSGuido Kiener *transferred = done; 951bb99794aSGuido Kiener dev_dbg(dev, "%s: (async) done=%u ret=0\n", 952bb99794aSGuido Kiener __func__, done); 953bb99794aSGuido Kiener return 0; 954bb99794aSGuido Kiener } 955bb99794aSGuido Kiener 956bb99794aSGuido Kiener file_data->in_urbs_used--; 957bb99794aSGuido Kiener 958bb99794aSGuido Kiener if (max_transfer_size > urb->actual_length) 959bb99794aSGuido Kiener max_transfer_size -= urb->actual_length; 960bb99794aSGuido Kiener else 961bb99794aSGuido Kiener max_transfer_size = 0; 962bb99794aSGuido Kiener 963bb99794aSGuido Kiener if (remaining > urb->actual_length) 964bb99794aSGuido Kiener this_part = urb->actual_length; 965bb99794aSGuido Kiener else 966bb99794aSGuido Kiener this_part = remaining; 967bb99794aSGuido Kiener 968bb99794aSGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1, 969bb99794aSGuido Kiener urb->transfer_buffer, urb->actual_length, true); 970bb99794aSGuido Kiener 971bb99794aSGuido Kiener if (copy_to_user(user_buffer + done, 972bb99794aSGuido Kiener urb->transfer_buffer, this_part)) { 973bb99794aSGuido Kiener usb_free_urb(urb); 974bb99794aSGuido Kiener retval = -EFAULT; 975bb99794aSGuido Kiener goto error; 976bb99794aSGuido Kiener } 977bb99794aSGuido Kiener 978bb99794aSGuido Kiener remaining -= this_part; 979bb99794aSGuido Kiener done += this_part; 980bb99794aSGuido Kiener 981bb99794aSGuido Kiener spin_lock_irq(&file_data->err_lock); 982bb99794aSGuido Kiener if (urb->status) { 983bb99794aSGuido Kiener /* return the very first error */ 984bb99794aSGuido Kiener retval = file_data->in_status; 985bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 986bb99794aSGuido Kiener usb_free_urb(urb); 987bb99794aSGuido Kiener goto error; 988bb99794aSGuido Kiener } 989bb99794aSGuido Kiener spin_unlock_irq(&file_data->err_lock); 990bb99794aSGuido Kiener 991bb99794aSGuido Kiener if (urb->actual_length < bufsize) { 992bb99794aSGuido Kiener /* short packet or ZLP received => ready */ 993bb99794aSGuido Kiener usb_free_urb(urb); 994bb99794aSGuido Kiener retval = 1; 995bb99794aSGuido Kiener break; 996bb99794aSGuido Kiener } 997bb99794aSGuido Kiener 998bb99794aSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC) && 999bb99794aSGuido Kiener max_transfer_size > (bufsize * file_data->in_urbs_used)) { 1000bb99794aSGuido Kiener /* resubmit, since other buffers still not enough */ 1001bb99794aSGuido Kiener usb_anchor_urb(urb, &file_data->submitted); 1002bb99794aSGuido Kiener retval = usb_submit_urb(urb, GFP_KERNEL); 1003bb99794aSGuido Kiener if (unlikely(retval)) { 1004bb99794aSGuido Kiener usb_unanchor_urb(urb); 1005bb99794aSGuido Kiener usb_free_urb(urb); 1006bb99794aSGuido Kiener goto error; 1007bb99794aSGuido Kiener } 1008bb99794aSGuido Kiener file_data->in_urbs_used++; 1009bb99794aSGuido Kiener } 1010bb99794aSGuido Kiener usb_free_urb(urb); 1011bb99794aSGuido Kiener retval = 0; 1012bb99794aSGuido Kiener } 1013bb99794aSGuido Kiener 1014bb99794aSGuido Kiener error: 1015bb99794aSGuido Kiener *transferred = done; 1016bb99794aSGuido Kiener 1017bb99794aSGuido Kiener dev_dbg(dev, "%s: before kill\n", __func__); 1018bb99794aSGuido Kiener /* Attention: killing urbs can take long time (2 ms) */ 1019bb99794aSGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 1020bb99794aSGuido Kiener dev_dbg(dev, "%s: after kill\n", __func__); 1021bb99794aSGuido Kiener usb_scuttle_anchored_urbs(&file_data->in_anchor); 1022bb99794aSGuido Kiener file_data->in_urbs_used = 0; 1023bb99794aSGuido Kiener file_data->in_status = 0; /* no spinlock needed here */ 1024bb99794aSGuido Kiener dev_dbg(dev, "%s: done=%u ret=%d\n", __func__, done, retval); 1025bb99794aSGuido Kiener 1026bb99794aSGuido Kiener return retval; 1027bb99794aSGuido Kiener } 1028bb99794aSGuido Kiener 1029bb99794aSGuido Kiener static ssize_t usbtmc_ioctl_generic_read(struct usbtmc_file_data *file_data, 1030bb99794aSGuido Kiener void __user *arg) 1031bb99794aSGuido Kiener { 1032bb99794aSGuido Kiener struct usbtmc_message msg; 1033bb99794aSGuido Kiener ssize_t retval = 0; 1034bb99794aSGuido Kiener 1035bb99794aSGuido Kiener /* mutex already locked */ 1036bb99794aSGuido Kiener 1037bb99794aSGuido Kiener if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message))) 1038bb99794aSGuido Kiener return -EFAULT; 1039bb99794aSGuido Kiener 1040bb99794aSGuido Kiener retval = usbtmc_generic_read(file_data, msg.message, 1041bb99794aSGuido Kiener msg.transfer_size, &msg.transferred, 1042bb99794aSGuido Kiener msg.flags); 1043bb99794aSGuido Kiener 1044bb99794aSGuido Kiener if (put_user(msg.transferred, 1045bb99794aSGuido Kiener &((struct usbtmc_message __user *)arg)->transferred)) 1046bb99794aSGuido Kiener return -EFAULT; 1047bb99794aSGuido Kiener 1048bb99794aSGuido Kiener return retval; 1049bb99794aSGuido Kiener } 1050bb99794aSGuido Kiener 10514ddc645fSGuido Kiener static void usbtmc_write_bulk_cb(struct urb *urb) 10524ddc645fSGuido Kiener { 10534ddc645fSGuido Kiener struct usbtmc_file_data *file_data = urb->context; 10544ddc645fSGuido Kiener int wakeup = 0; 10554ddc645fSGuido Kiener unsigned long flags; 10564ddc645fSGuido Kiener 10574ddc645fSGuido Kiener spin_lock_irqsave(&file_data->err_lock, flags); 10584ddc645fSGuido Kiener file_data->out_transfer_size += urb->actual_length; 10594ddc645fSGuido Kiener 10604ddc645fSGuido Kiener /* sync/async unlink faults aren't errors */ 10614ddc645fSGuido Kiener if (urb->status) { 10624ddc645fSGuido Kiener if (!(urb->status == -ENOENT || 10634ddc645fSGuido Kiener urb->status == -ECONNRESET || 10644ddc645fSGuido Kiener urb->status == -ESHUTDOWN)) 10654ddc645fSGuido Kiener dev_err(&file_data->data->intf->dev, 10664ddc645fSGuido Kiener "%s - nonzero write bulk status received: %d\n", 10674ddc645fSGuido Kiener __func__, urb->status); 10684ddc645fSGuido Kiener 10694ddc645fSGuido Kiener if (!file_data->out_status) { 10704ddc645fSGuido Kiener file_data->out_status = urb->status; 10714ddc645fSGuido Kiener wakeup = 1; 10724ddc645fSGuido Kiener } 10734ddc645fSGuido Kiener } 10744ddc645fSGuido Kiener spin_unlock_irqrestore(&file_data->err_lock, flags); 10754ddc645fSGuido Kiener 10764ddc645fSGuido Kiener dev_dbg(&file_data->data->intf->dev, 10774ddc645fSGuido Kiener "%s - write bulk total size: %u\n", 10784ddc645fSGuido Kiener __func__, file_data->out_transfer_size); 10794ddc645fSGuido Kiener 10804ddc645fSGuido Kiener up(&file_data->limit_write_sem); 10814ddc645fSGuido Kiener if (usb_anchor_empty(&file_data->submitted) || wakeup) 10824ddc645fSGuido Kiener wake_up_interruptible(&file_data->data->waitq); 10834ddc645fSGuido Kiener } 10844ddc645fSGuido Kiener 10854ddc645fSGuido Kiener static ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data, 10864ddc645fSGuido Kiener const void __user *user_buffer, 10874ddc645fSGuido Kiener u32 transfer_size, 10884ddc645fSGuido Kiener u32 *transferred, 10894ddc645fSGuido Kiener u32 flags) 10904ddc645fSGuido Kiener { 10914ddc645fSGuido Kiener struct usbtmc_device_data *data = file_data->data; 10924ddc645fSGuido Kiener struct device *dev; 10934ddc645fSGuido Kiener u32 done = 0; 10944ddc645fSGuido Kiener u32 remaining; 10954ddc645fSGuido Kiener unsigned long expire; 10964ddc645fSGuido Kiener const u32 bufsize = USBTMC_BUFSIZE; 10974ddc645fSGuido Kiener struct urb *urb = NULL; 10984ddc645fSGuido Kiener int retval = 0; 10994ddc645fSGuido Kiener u32 timeout; 11004ddc645fSGuido Kiener 11014ddc645fSGuido Kiener *transferred = 0; 11024ddc645fSGuido Kiener 11034ddc645fSGuido Kiener /* Get pointer to private data structure */ 11044ddc645fSGuido Kiener dev = &data->intf->dev; 11054ddc645fSGuido Kiener 11064ddc645fSGuido Kiener dev_dbg(dev, "%s: size=%u flags=0x%X sema=%u\n", 11074ddc645fSGuido Kiener __func__, transfer_size, flags, 11084ddc645fSGuido Kiener file_data->limit_write_sem.count); 11094ddc645fSGuido Kiener 11104ddc645fSGuido Kiener if (flags & USBTMC_FLAG_APPEND) { 11114ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 11124ddc645fSGuido Kiener retval = file_data->out_status; 11134ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 11144ddc645fSGuido Kiener if (retval < 0) 11154ddc645fSGuido Kiener return retval; 11164ddc645fSGuido Kiener } else { 11174ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 11184ddc645fSGuido Kiener file_data->out_transfer_size = 0; 11194ddc645fSGuido Kiener file_data->out_status = 0; 11204ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 11214ddc645fSGuido Kiener } 11224ddc645fSGuido Kiener 11234ddc645fSGuido Kiener remaining = transfer_size; 11244ddc645fSGuido Kiener if (remaining > INT_MAX) 11254ddc645fSGuido Kiener remaining = INT_MAX; 11264ddc645fSGuido Kiener 11274ddc645fSGuido Kiener timeout = file_data->timeout; 11284ddc645fSGuido Kiener expire = msecs_to_jiffies(timeout); 11294ddc645fSGuido Kiener 11304ddc645fSGuido Kiener while (remaining > 0) { 11314ddc645fSGuido Kiener u32 this_part, aligned; 11324ddc645fSGuido Kiener u8 *buffer = NULL; 11334ddc645fSGuido Kiener 11344ddc645fSGuido Kiener if (flags & USBTMC_FLAG_ASYNC) { 11354ddc645fSGuido Kiener if (down_trylock(&file_data->limit_write_sem)) { 11364ddc645fSGuido Kiener retval = (done)?(0):(-EAGAIN); 11374ddc645fSGuido Kiener goto exit; 11384ddc645fSGuido Kiener } 11394ddc645fSGuido Kiener } else { 11404ddc645fSGuido Kiener retval = down_timeout(&file_data->limit_write_sem, 11414ddc645fSGuido Kiener expire); 11424ddc645fSGuido Kiener if (retval < 0) { 11434ddc645fSGuido Kiener retval = -ETIMEDOUT; 11444ddc645fSGuido Kiener goto error; 11454ddc645fSGuido Kiener } 11464ddc645fSGuido Kiener } 11474ddc645fSGuido Kiener 11484ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 11494ddc645fSGuido Kiener retval = file_data->out_status; 11504ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 11514ddc645fSGuido Kiener if (retval < 0) { 11524ddc645fSGuido Kiener up(&file_data->limit_write_sem); 11534ddc645fSGuido Kiener goto error; 11544ddc645fSGuido Kiener } 11554ddc645fSGuido Kiener 11564ddc645fSGuido Kiener /* prepare next urb to send */ 11574ddc645fSGuido Kiener urb = usbtmc_create_urb(); 11584ddc645fSGuido Kiener if (!urb) { 11594ddc645fSGuido Kiener retval = -ENOMEM; 11604ddc645fSGuido Kiener up(&file_data->limit_write_sem); 11614ddc645fSGuido Kiener goto error; 11624ddc645fSGuido Kiener } 11634ddc645fSGuido Kiener buffer = urb->transfer_buffer; 11644ddc645fSGuido Kiener 11654ddc645fSGuido Kiener if (remaining > bufsize) 11664ddc645fSGuido Kiener this_part = bufsize; 11674ddc645fSGuido Kiener else 11684ddc645fSGuido Kiener this_part = remaining; 11694ddc645fSGuido Kiener 11704ddc645fSGuido Kiener if (copy_from_user(buffer, user_buffer + done, this_part)) { 11714ddc645fSGuido Kiener retval = -EFAULT; 11724ddc645fSGuido Kiener up(&file_data->limit_write_sem); 11734ddc645fSGuido Kiener goto error; 11744ddc645fSGuido Kiener } 11754ddc645fSGuido Kiener 11764ddc645fSGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 11774ddc645fSGuido Kiener 16, 1, buffer, this_part, true); 11784ddc645fSGuido Kiener 11794ddc645fSGuido Kiener /* fill bulk with 32 bit alignment to meet USBTMC specification 11804ddc645fSGuido Kiener * (size + 3 & ~3) rounds up and simplifies user code 11814ddc645fSGuido Kiener */ 11824ddc645fSGuido Kiener aligned = (this_part + 3) & ~3; 11834ddc645fSGuido Kiener dev_dbg(dev, "write(size:%u align:%u done:%u)\n", 11844ddc645fSGuido Kiener (unsigned int)this_part, 11854ddc645fSGuido Kiener (unsigned int)aligned, 11864ddc645fSGuido Kiener (unsigned int)done); 11874ddc645fSGuido Kiener 11884ddc645fSGuido Kiener usb_fill_bulk_urb(urb, data->usb_dev, 11894ddc645fSGuido Kiener usb_sndbulkpipe(data->usb_dev, data->bulk_out), 11904ddc645fSGuido Kiener urb->transfer_buffer, aligned, 11914ddc645fSGuido Kiener usbtmc_write_bulk_cb, file_data); 11924ddc645fSGuido Kiener 11934ddc645fSGuido Kiener usb_anchor_urb(urb, &file_data->submitted); 11944ddc645fSGuido Kiener retval = usb_submit_urb(urb, GFP_KERNEL); 11954ddc645fSGuido Kiener if (unlikely(retval)) { 11964ddc645fSGuido Kiener usb_unanchor_urb(urb); 11974ddc645fSGuido Kiener up(&file_data->limit_write_sem); 11984ddc645fSGuido Kiener goto error; 11994ddc645fSGuido Kiener } 12004ddc645fSGuido Kiener 12014ddc645fSGuido Kiener usb_free_urb(urb); 12024ddc645fSGuido Kiener urb = NULL; /* urb will be finally released by usb driver */ 12034ddc645fSGuido Kiener 12044ddc645fSGuido Kiener remaining -= this_part; 12054ddc645fSGuido Kiener done += this_part; 12064ddc645fSGuido Kiener } 12074ddc645fSGuido Kiener 12084ddc645fSGuido Kiener /* All urbs are on the fly */ 12094ddc645fSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC)) { 12104ddc645fSGuido Kiener if (!usb_wait_anchor_empty_timeout(&file_data->submitted, 12114ddc645fSGuido Kiener timeout)) { 12124ddc645fSGuido Kiener retval = -ETIMEDOUT; 12134ddc645fSGuido Kiener goto error; 12144ddc645fSGuido Kiener } 12154ddc645fSGuido Kiener } 12164ddc645fSGuido Kiener 12174ddc645fSGuido Kiener retval = 0; 12184ddc645fSGuido Kiener goto exit; 12194ddc645fSGuido Kiener 12204ddc645fSGuido Kiener error: 12214ddc645fSGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 12224ddc645fSGuido Kiener exit: 12234ddc645fSGuido Kiener usb_free_urb(urb); 12244ddc645fSGuido Kiener 12254ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 12264ddc645fSGuido Kiener if (!(flags & USBTMC_FLAG_ASYNC)) 12274ddc645fSGuido Kiener done = file_data->out_transfer_size; 12284ddc645fSGuido Kiener if (!retval && file_data->out_status) 12294ddc645fSGuido Kiener retval = file_data->out_status; 12304ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 12314ddc645fSGuido Kiener 12324ddc645fSGuido Kiener *transferred = done; 12334ddc645fSGuido Kiener 12344ddc645fSGuido Kiener dev_dbg(dev, "%s: done=%u, retval=%d, urbstat=%d\n", 12354ddc645fSGuido Kiener __func__, done, retval, file_data->out_status); 12364ddc645fSGuido Kiener 12374ddc645fSGuido Kiener return retval; 12384ddc645fSGuido Kiener } 12394ddc645fSGuido Kiener 12404ddc645fSGuido Kiener static ssize_t usbtmc_ioctl_generic_write(struct usbtmc_file_data *file_data, 12414ddc645fSGuido Kiener void __user *arg) 12424ddc645fSGuido Kiener { 12434ddc645fSGuido Kiener struct usbtmc_message msg; 12444ddc645fSGuido Kiener ssize_t retval = 0; 12454ddc645fSGuido Kiener 12464ddc645fSGuido Kiener /* mutex already locked */ 12474ddc645fSGuido Kiener 12484ddc645fSGuido Kiener if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message))) 12494ddc645fSGuido Kiener return -EFAULT; 12504ddc645fSGuido Kiener 12514ddc645fSGuido Kiener retval = usbtmc_generic_write(file_data, msg.message, 12524ddc645fSGuido Kiener msg.transfer_size, &msg.transferred, 12534ddc645fSGuido Kiener msg.flags); 12544ddc645fSGuido Kiener 12554ddc645fSGuido Kiener if (put_user(msg.transferred, 12564ddc645fSGuido Kiener &((struct usbtmc_message __user *)arg)->transferred)) 12574ddc645fSGuido Kiener return -EFAULT; 12584ddc645fSGuido Kiener 12594ddc645fSGuido Kiener return retval; 12604ddc645fSGuido Kiener } 12614ddc645fSGuido Kiener 1262fe78a7c6SGuido Kiener /* 1263b1498451SGuido Kiener * Get the generic write result 1264b1498451SGuido Kiener */ 1265b1498451SGuido Kiener static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data, 1266b1498451SGuido Kiener void __user *arg) 1267b1498451SGuido Kiener { 1268b1498451SGuido Kiener u32 transferred; 1269b1498451SGuido Kiener int retval; 1270b1498451SGuido Kiener 1271b1498451SGuido Kiener spin_lock_irq(&file_data->err_lock); 1272b1498451SGuido Kiener transferred = file_data->out_transfer_size; 1273b1498451SGuido Kiener retval = file_data->out_status; 1274b1498451SGuido Kiener spin_unlock_irq(&file_data->err_lock); 1275b1498451SGuido Kiener 1276b1498451SGuido Kiener if (put_user(transferred, (__u32 __user *)arg)) 1277b1498451SGuido Kiener return -EFAULT; 1278b1498451SGuido Kiener 1279b1498451SGuido Kiener return retval; 1280b1498451SGuido Kiener } 1281b1498451SGuido Kiener 1282b1498451SGuido Kiener /* 128388aecde4SDave Penkler * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint. 128488d9b2b3SAlexandre Peixoto Ferreira * @transfer_size: number of bytes to request from the device. 128588d9b2b3SAlexandre Peixoto Ferreira * 128688d9b2b3SAlexandre Peixoto Ferreira * See the USBTMC specification, Table 4. 128788d9b2b3SAlexandre Peixoto Ferreira * 128888d9b2b3SAlexandre Peixoto Ferreira * Also updates bTag_last_write. 128988d9b2b3SAlexandre Peixoto Ferreira */ 1290048c6d88SGuido Kiener static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data, 1291d7604ff0SGuido Kiener u32 transfer_size) 129288d9b2b3SAlexandre Peixoto Ferreira { 1293048c6d88SGuido Kiener struct usbtmc_device_data *data = file_data->data; 129488d9b2b3SAlexandre Peixoto Ferreira int retval; 1295d846b765SOliver Neukum u8 *buffer; 129688d9b2b3SAlexandre Peixoto Ferreira int actual; 129788d9b2b3SAlexandre Peixoto Ferreira 1298d846b765SOliver Neukum buffer = kmalloc(USBTMC_HEADER_SIZE, GFP_KERNEL); 1299d846b765SOliver Neukum if (!buffer) 1300d846b765SOliver Neukum return -ENOMEM; 130188d9b2b3SAlexandre Peixoto Ferreira /* Setup IO buffer for REQUEST_DEV_DEP_MSG_IN message 130288d9b2b3SAlexandre Peixoto Ferreira * Refer to class specs for details 130388d9b2b3SAlexandre Peixoto Ferreira */ 130488d9b2b3SAlexandre Peixoto Ferreira buffer[0] = 2; 130588d9b2b3SAlexandre Peixoto Ferreira buffer[1] = data->bTag; 1306bbf4976eSAndy Shevchenko buffer[2] = ~data->bTag; 130788d9b2b3SAlexandre Peixoto Ferreira buffer[3] = 0; /* Reserved */ 1308bbf4976eSAndy Shevchenko buffer[4] = transfer_size >> 0; 1309bbf4976eSAndy Shevchenko buffer[5] = transfer_size >> 8; 1310bbf4976eSAndy Shevchenko buffer[6] = transfer_size >> 16; 1311bbf4976eSAndy Shevchenko buffer[7] = transfer_size >> 24; 131212dcaeb7SGuido Kiener buffer[8] = file_data->term_char_enabled * 2; 131388d9b2b3SAlexandre Peixoto Ferreira /* Use term character? */ 131412dcaeb7SGuido Kiener buffer[9] = file_data->term_char; 131588d9b2b3SAlexandre Peixoto Ferreira buffer[10] = 0; /* Reserved */ 131688d9b2b3SAlexandre Peixoto Ferreira buffer[11] = 0; /* Reserved */ 131788d9b2b3SAlexandre Peixoto Ferreira 131888d9b2b3SAlexandre Peixoto Ferreira /* Send bulk URB */ 131988d9b2b3SAlexandre Peixoto Ferreira retval = usb_bulk_msg(data->usb_dev, 132088d9b2b3SAlexandre Peixoto Ferreira usb_sndbulkpipe(data->usb_dev, 132188d9b2b3SAlexandre Peixoto Ferreira data->bulk_out), 1322048c6d88SGuido Kiener buffer, USBTMC_HEADER_SIZE, 1323048c6d88SGuido Kiener &actual, file_data->timeout); 132488d9b2b3SAlexandre Peixoto Ferreira 132588d9b2b3SAlexandre Peixoto Ferreira /* Store bTag (in case we need to abort) */ 132688d9b2b3SAlexandre Peixoto Ferreira data->bTag_last_write = data->bTag; 132788d9b2b3SAlexandre Peixoto Ferreira 132888d9b2b3SAlexandre Peixoto Ferreira /* Increment bTag -- and increment again if zero */ 132988d9b2b3SAlexandre Peixoto Ferreira data->bTag++; 133088d9b2b3SAlexandre Peixoto Ferreira if (!data->bTag) 1331bbf4976eSAndy Shevchenko data->bTag++; 133288d9b2b3SAlexandre Peixoto Ferreira 1333d846b765SOliver Neukum kfree(buffer); 1334d7604ff0SGuido Kiener if (retval < 0) 1335d7604ff0SGuido Kiener dev_err(&data->intf->dev, "%s returned %d\n", 1336d7604ff0SGuido Kiener __func__, retval); 133788d9b2b3SAlexandre Peixoto Ferreira 1338d7604ff0SGuido Kiener return retval; 133988d9b2b3SAlexandre Peixoto Ferreira } 134088d9b2b3SAlexandre Peixoto Ferreira 13415b775f67SGreg Kroah-Hartman static ssize_t usbtmc_read(struct file *filp, char __user *buf, 13425b775f67SGreg Kroah-Hartman size_t count, loff_t *f_pos) 13435b775f67SGreg Kroah-Hartman { 13444f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data; 13455b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 13465b775f67SGreg Kroah-Hartman struct device *dev; 1347d7604ff0SGuido Kiener const u32 bufsize = USBTMC_BUFSIZE; 1348665d7662SGuus Sliepen u32 n_characters; 13495b775f67SGreg Kroah-Hartman u8 *buffer; 13505b775f67SGreg Kroah-Hartman int actual; 1351d7604ff0SGuido Kiener u32 done = 0; 1352d7604ff0SGuido Kiener u32 remaining; 13535b775f67SGreg Kroah-Hartman int retval; 13545b775f67SGreg Kroah-Hartman 13555b775f67SGreg Kroah-Hartman /* Get pointer to private data structure */ 13564f3c8d6eSGuido Kiener file_data = filp->private_data; 13574f3c8d6eSGuido Kiener data = file_data->data; 13585b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 13595b775f67SGreg Kroah-Hartman 1360d7604ff0SGuido Kiener buffer = kmalloc(bufsize, GFP_KERNEL); 13615b775f67SGreg Kroah-Hartman if (!buffer) 13625b775f67SGreg Kroah-Hartman return -ENOMEM; 13635b775f67SGreg Kroah-Hartman 13645b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 136586286883SOliver Neukum if (data->zombie) { 136686286883SOliver Neukum retval = -ENODEV; 136786286883SOliver Neukum goto exit; 136886286883SOliver Neukum } 13695b775f67SGreg Kroah-Hartman 1370d7604ff0SGuido Kiener if (count > INT_MAX) 1371d7604ff0SGuido Kiener count = INT_MAX; 1372d7604ff0SGuido Kiener 1373d7604ff0SGuido Kiener dev_dbg(dev, "%s(count:%zu)\n", __func__, count); 1374d2ddce37SAlexandre Peixoto Ferreira 1375048c6d88SGuido Kiener retval = send_request_dev_dep_msg_in(file_data, count); 1376d2ddce37SAlexandre Peixoto Ferreira 1377d2ddce37SAlexandre Peixoto Ferreira if (retval < 0) { 1378ec34d08eSGuido Kiener if (file_data->auto_abort) 1379d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_out(data); 1380d2ddce37SAlexandre Peixoto Ferreira goto exit; 1381d2ddce37SAlexandre Peixoto Ferreira } 1382d2ddce37SAlexandre Peixoto Ferreira 1383d2ddce37SAlexandre Peixoto Ferreira /* Loop until we have fetched everything we requested */ 13845b775f67SGreg Kroah-Hartman remaining = count; 13855b775f67SGreg Kroah-Hartman 13865b775f67SGreg Kroah-Hartman /* Send bulk URB */ 13875b775f67SGreg Kroah-Hartman retval = usb_bulk_msg(data->usb_dev, 13885b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 13895b775f67SGreg Kroah-Hartman data->bulk_in), 1390d7604ff0SGuido Kiener buffer, bufsize, &actual, 1391048c6d88SGuido Kiener file_data->timeout); 13925b775f67SGreg Kroah-Hartman 1393d7604ff0SGuido Kiener dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n", 1394d7604ff0SGuido Kiener __func__, retval, actual); 1395d2ddce37SAlexandre Peixoto Ferreira 13965b775f67SGreg Kroah-Hartman /* Store bTag (in case we need to abort) */ 13975b775f67SGreg Kroah-Hartman data->bTag_last_read = data->bTag; 13985b775f67SGreg Kroah-Hartman 13995b775f67SGreg Kroah-Hartman if (retval < 0) { 1400ec34d08eSGuido Kiener if (file_data->auto_abort) 1401d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_in(data); 1402d2ddce37SAlexandre Peixoto Ferreira goto exit; 1403d2ddce37SAlexandre Peixoto Ferreira } 1404d2ddce37SAlexandre Peixoto Ferreira 1405d2ddce37SAlexandre Peixoto Ferreira /* Sanity checks for the header */ 1406d2ddce37SAlexandre Peixoto Ferreira if (actual < USBTMC_HEADER_SIZE) { 1407d7604ff0SGuido Kiener dev_err(dev, "Device sent too small first packet: %u < %u\n", 1408d7604ff0SGuido Kiener actual, USBTMC_HEADER_SIZE); 1409ec34d08eSGuido Kiener if (file_data->auto_abort) 1410d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_in(data); 1411d2ddce37SAlexandre Peixoto Ferreira goto exit; 1412d2ddce37SAlexandre Peixoto Ferreira } 1413d2ddce37SAlexandre Peixoto Ferreira 1414d2ddce37SAlexandre Peixoto Ferreira if (buffer[0] != 2) { 1415d7604ff0SGuido Kiener dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", 1416d7604ff0SGuido Kiener buffer[0]); 1417ec34d08eSGuido Kiener if (file_data->auto_abort) 1418d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_in(data); 1419d2ddce37SAlexandre Peixoto Ferreira goto exit; 1420d2ddce37SAlexandre Peixoto Ferreira } 1421d2ddce37SAlexandre Peixoto Ferreira 1422d2ddce37SAlexandre Peixoto Ferreira if (buffer[1] != data->bTag_last_write) { 1423d7604ff0SGuido Kiener dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", 1424d7604ff0SGuido Kiener buffer[1], data->bTag_last_write); 1425ec34d08eSGuido Kiener if (file_data->auto_abort) 14265b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_in(data); 14275b775f67SGreg Kroah-Hartman goto exit; 14285b775f67SGreg Kroah-Hartman } 14295b775f67SGreg Kroah-Hartman 14305b775f67SGreg Kroah-Hartman /* How many characters did the instrument send? */ 14315b775f67SGreg Kroah-Hartman n_characters = buffer[4] + 14325b775f67SGreg Kroah-Hartman (buffer[5] << 8) + 14335b775f67SGreg Kroah-Hartman (buffer[6] << 16) + 14345b775f67SGreg Kroah-Hartman (buffer[7] << 24); 14355b775f67SGreg Kroah-Hartman 14368409e96fSGuido Kiener file_data->bmTransferAttributes = buffer[8]; 14378409e96fSGuido Kiener 1438d7604ff0SGuido Kiener dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", 1439d7604ff0SGuido Kiener n_characters, buffer[8]); 1440d7604ff0SGuido Kiener 1441d7604ff0SGuido Kiener if (n_characters > remaining) { 1442d7604ff0SGuido Kiener dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", 1443d7604ff0SGuido Kiener n_characters, count); 1444ec34d08eSGuido Kiener if (file_data->auto_abort) 1445d2ddce37SAlexandre Peixoto Ferreira usbtmc_ioctl_abort_bulk_in(data); 1446d2ddce37SAlexandre Peixoto Ferreira goto exit; 1447665d7662SGuus Sliepen } 1448665d7662SGuus Sliepen 1449d7604ff0SGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 1450d7604ff0SGuido Kiener 16, 1, buffer, actual, true); 1451d7604ff0SGuido Kiener 1452d7604ff0SGuido Kiener remaining = n_characters; 1453d7604ff0SGuido Kiener 1454d2ddce37SAlexandre Peixoto Ferreira /* Remove the USBTMC header */ 1455d2ddce37SAlexandre Peixoto Ferreira actual -= USBTMC_HEADER_SIZE; 1456d2ddce37SAlexandre Peixoto Ferreira 1457d2ddce37SAlexandre Peixoto Ferreira /* Remove padding if it exists */ 1458d2ddce37SAlexandre Peixoto Ferreira if (actual > remaining) 1459d2ddce37SAlexandre Peixoto Ferreira actual = remaining; 1460d2ddce37SAlexandre Peixoto Ferreira 1461d2ddce37SAlexandre Peixoto Ferreira remaining -= actual; 1462d2ddce37SAlexandre Peixoto Ferreira 14635b775f67SGreg Kroah-Hartman /* Copy buffer to user space */ 1464d7604ff0SGuido Kiener if (copy_to_user(buf, &buffer[USBTMC_HEADER_SIZE], actual)) { 14655b775f67SGreg Kroah-Hartman /* There must have been an addressing problem */ 14665b775f67SGreg Kroah-Hartman retval = -EFAULT; 14675b775f67SGreg Kroah-Hartman goto exit; 14685b775f67SGreg Kroah-Hartman } 14695b775f67SGreg Kroah-Hartman 1470d7604ff0SGuido Kiener if ((actual + USBTMC_HEADER_SIZE) == bufsize) { 1471d7604ff0SGuido Kiener retval = usbtmc_generic_read(file_data, buf + actual, 1472d7604ff0SGuido Kiener remaining, 1473d7604ff0SGuido Kiener &done, 1474d7604ff0SGuido Kiener USBTMC_FLAG_IGNORE_TRAILER); 1475d7604ff0SGuido Kiener if (retval < 0) 1476d2ddce37SAlexandre Peixoto Ferreira goto exit; 1477d2ddce37SAlexandre Peixoto Ferreira } 1478d2ddce37SAlexandre Peixoto Ferreira done += actual; 14795b775f67SGreg Kroah-Hartman 14805b775f67SGreg Kroah-Hartman /* Update file position value */ 14815b775f67SGreg Kroah-Hartman *f_pos = *f_pos + done; 14825b775f67SGreg Kroah-Hartman retval = done; 14835b775f67SGreg Kroah-Hartman 14845b775f67SGreg Kroah-Hartman exit: 14855b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 14865b775f67SGreg Kroah-Hartman kfree(buffer); 14875b775f67SGreg Kroah-Hartman return retval; 14885b775f67SGreg Kroah-Hartman } 14895b775f67SGreg Kroah-Hartman 14905b775f67SGreg Kroah-Hartman static ssize_t usbtmc_write(struct file *filp, const char __user *buf, 14915b775f67SGreg Kroah-Hartman size_t count, loff_t *f_pos) 14925b775f67SGreg Kroah-Hartman { 14934f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data; 14945b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 14954d5e18d9SGuido Kiener struct urb *urb = NULL; 14964d5e18d9SGuido Kiener ssize_t retval = 0; 14975b775f67SGreg Kroah-Hartman u8 *buffer; 14984d5e18d9SGuido Kiener u32 remaining, done; 14994d5e18d9SGuido Kiener u32 transfersize, aligned, buflen; 15005b775f67SGreg Kroah-Hartman 15014f3c8d6eSGuido Kiener file_data = filp->private_data; 15024f3c8d6eSGuido Kiener data = file_data->data; 15035b775f67SGreg Kroah-Hartman 15045b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 15054d5e18d9SGuido Kiener 150686286883SOliver Neukum if (data->zombie) { 150786286883SOliver Neukum retval = -ENODEV; 150886286883SOliver Neukum goto exit; 150986286883SOliver Neukum } 15105b775f67SGreg Kroah-Hartman 15115b775f67SGreg Kroah-Hartman done = 0; 15125b775f67SGreg Kroah-Hartman 15134d5e18d9SGuido Kiener spin_lock_irq(&file_data->err_lock); 15144d5e18d9SGuido Kiener file_data->out_transfer_size = 0; 15154d5e18d9SGuido Kiener file_data->out_status = 0; 15164d5e18d9SGuido Kiener spin_unlock_irq(&file_data->err_lock); 15174d5e18d9SGuido Kiener 15184d5e18d9SGuido Kiener if (!count) 15194d5e18d9SGuido Kiener goto exit; 15204d5e18d9SGuido Kiener 15214d5e18d9SGuido Kiener if (down_trylock(&file_data->limit_write_sem)) { 15224d5e18d9SGuido Kiener /* previous calls were async */ 15234d5e18d9SGuido Kiener retval = -EBUSY; 15244d5e18d9SGuido Kiener goto exit; 15254d5e18d9SGuido Kiener } 15264d5e18d9SGuido Kiener 15274d5e18d9SGuido Kiener urb = usbtmc_create_urb(); 15284d5e18d9SGuido Kiener if (!urb) { 15294d5e18d9SGuido Kiener retval = -ENOMEM; 15304d5e18d9SGuido Kiener up(&file_data->limit_write_sem); 15314d5e18d9SGuido Kiener goto exit; 15324d5e18d9SGuido Kiener } 15334d5e18d9SGuido Kiener 15344d5e18d9SGuido Kiener buffer = urb->transfer_buffer; 15354d5e18d9SGuido Kiener buflen = urb->transfer_buffer_length; 15364d5e18d9SGuido Kiener 15374d5e18d9SGuido Kiener if (count > INT_MAX) { 15384d5e18d9SGuido Kiener transfersize = INT_MAX; 15395b775f67SGreg Kroah-Hartman buffer[8] = 0; 15405b775f67SGreg Kroah-Hartman } else { 15414d5e18d9SGuido Kiener transfersize = count; 1542fbd83971SGuido Kiener buffer[8] = file_data->eom_val; 15435b775f67SGreg Kroah-Hartman } 15445b775f67SGreg Kroah-Hartman 15455b775f67SGreg Kroah-Hartman /* Setup IO buffer for DEV_DEP_MSG_OUT message */ 15465b775f67SGreg Kroah-Hartman buffer[0] = 1; 15475b775f67SGreg Kroah-Hartman buffer[1] = data->bTag; 1548bbf4976eSAndy Shevchenko buffer[2] = ~data->bTag; 15495b775f67SGreg Kroah-Hartman buffer[3] = 0; /* Reserved */ 15504d5e18d9SGuido Kiener buffer[4] = transfersize >> 0; 15514d5e18d9SGuido Kiener buffer[5] = transfersize >> 8; 15524d5e18d9SGuido Kiener buffer[6] = transfersize >> 16; 15534d5e18d9SGuido Kiener buffer[7] = transfersize >> 24; 15545b775f67SGreg Kroah-Hartman /* buffer[8] is set above... */ 15555b775f67SGreg Kroah-Hartman buffer[9] = 0; /* Reserved */ 15565b775f67SGreg Kroah-Hartman buffer[10] = 0; /* Reserved */ 15575b775f67SGreg Kroah-Hartman buffer[11] = 0; /* Reserved */ 15585b775f67SGreg Kroah-Hartman 15594d5e18d9SGuido Kiener remaining = transfersize; 15604d5e18d9SGuido Kiener 15614d5e18d9SGuido Kiener if (transfersize + USBTMC_HEADER_SIZE > buflen) { 15624d5e18d9SGuido Kiener transfersize = buflen - USBTMC_HEADER_SIZE; 15634d5e18d9SGuido Kiener aligned = buflen; 15644d5e18d9SGuido Kiener } else { 15654d5e18d9SGuido Kiener aligned = (transfersize + (USBTMC_HEADER_SIZE + 3)) & ~3; 15664d5e18d9SGuido Kiener } 15674d5e18d9SGuido Kiener 15684d5e18d9SGuido Kiener if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf, transfersize)) { 15695b775f67SGreg Kroah-Hartman retval = -EFAULT; 15704d5e18d9SGuido Kiener up(&file_data->limit_write_sem); 15715b775f67SGreg Kroah-Hartman goto exit; 15725b775f67SGreg Kroah-Hartman } 15735b775f67SGreg Kroah-Hartman 15744d5e18d9SGuido Kiener dev_dbg(&data->intf->dev, "%s(size:%u align:%u)\n", __func__, 15754d5e18d9SGuido Kiener (unsigned int)transfersize, (unsigned int)aligned); 15765b775f67SGreg Kroah-Hartman 15774d5e18d9SGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 15784d5e18d9SGuido Kiener 16, 1, buffer, aligned, true); 15794d5e18d9SGuido Kiener 15804d5e18d9SGuido Kiener usb_fill_bulk_urb(urb, data->usb_dev, 15814d5e18d9SGuido Kiener usb_sndbulkpipe(data->usb_dev, data->bulk_out), 15824d5e18d9SGuido Kiener urb->transfer_buffer, aligned, 15834d5e18d9SGuido Kiener usbtmc_write_bulk_cb, file_data); 15844d5e18d9SGuido Kiener 15854d5e18d9SGuido Kiener usb_anchor_urb(urb, &file_data->submitted); 15864d5e18d9SGuido Kiener retval = usb_submit_urb(urb, GFP_KERNEL); 15874d5e18d9SGuido Kiener if (unlikely(retval)) { 15884d5e18d9SGuido Kiener usb_unanchor_urb(urb); 15894d5e18d9SGuido Kiener up(&file_data->limit_write_sem); 15904d5e18d9SGuido Kiener goto exit; 15914d5e18d9SGuido Kiener } 15924d5e18d9SGuido Kiener 15934d5e18d9SGuido Kiener remaining -= transfersize; 15945b775f67SGreg Kroah-Hartman 15955b775f67SGreg Kroah-Hartman data->bTag_last_write = data->bTag; 15965b775f67SGreg Kroah-Hartman data->bTag++; 15975b775f67SGreg Kroah-Hartman 15985b775f67SGreg Kroah-Hartman if (!data->bTag) 15995b775f67SGreg Kroah-Hartman data->bTag++; 16005b775f67SGreg Kroah-Hartman 16014d5e18d9SGuido Kiener /* call generic_write even when remaining = 0 */ 16024d5e18d9SGuido Kiener retval = usbtmc_generic_write(file_data, buf + transfersize, remaining, 16034d5e18d9SGuido Kiener &done, USBTMC_FLAG_APPEND); 16044d5e18d9SGuido Kiener /* truncate alignment bytes */ 16054d5e18d9SGuido Kiener if (done > remaining) 16064d5e18d9SGuido Kiener done = remaining; 16074d5e18d9SGuido Kiener 16084d5e18d9SGuido Kiener /*add size of first urb*/ 16094d5e18d9SGuido Kiener done += transfersize; 16104d5e18d9SGuido Kiener 16115b775f67SGreg Kroah-Hartman if (retval < 0) { 16124d5e18d9SGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 16134d5e18d9SGuido Kiener 16145b775f67SGreg Kroah-Hartman dev_err(&data->intf->dev, 16154d5e18d9SGuido Kiener "Unable to send data, error %d\n", (int)retval); 1616ec34d08eSGuido Kiener if (file_data->auto_abort) 16175b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_out(data); 16185b775f67SGreg Kroah-Hartman goto exit; 16195b775f67SGreg Kroah-Hartman } 16205b775f67SGreg Kroah-Hartman 16214d5e18d9SGuido Kiener retval = done; 16225b775f67SGreg Kroah-Hartman exit: 16234d5e18d9SGuido Kiener usb_free_urb(urb); 16245b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 16255b775f67SGreg Kroah-Hartman return retval; 16265b775f67SGreg Kroah-Hartman } 16275b775f67SGreg Kroah-Hartman 16285b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) 16295b775f67SGreg Kroah-Hartman { 16305b775f67SGreg Kroah-Hartman struct device *dev; 16315b775f67SGreg Kroah-Hartman u8 *buffer; 16325b775f67SGreg Kroah-Hartman int rv; 16335b775f67SGreg Kroah-Hartman int n; 1634ab53eb97SRickard Strandqvist int actual = 0; 16355b775f67SGreg Kroah-Hartman 16365b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 16375b775f67SGreg Kroah-Hartman 16385b775f67SGreg Kroah-Hartman dev_dbg(dev, "Sending INITIATE_CLEAR request\n"); 16395b775f67SGreg Kroah-Hartman 1640dfee02acSGuido Kiener buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL); 16415b775f67SGreg Kroah-Hartman if (!buffer) 16425b775f67SGreg Kroah-Hartman return -ENOMEM; 16435b775f67SGreg Kroah-Hartman 16445b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 16455b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 16465b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_CLEAR, 16475b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 1648dfee02acSGuido Kiener 0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT); 16495b775f67SGreg Kroah-Hartman if (rv < 0) { 16505b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 16515b775f67SGreg Kroah-Hartman goto exit; 16525b775f67SGreg Kroah-Hartman } 16535b775f67SGreg Kroah-Hartman 16545b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); 16555b775f67SGreg Kroah-Hartman 16565b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 16575b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); 16585b775f67SGreg Kroah-Hartman rv = -EPERM; 16595b775f67SGreg Kroah-Hartman goto exit; 16605b775f67SGreg Kroah-Hartman } 16615b775f67SGreg Kroah-Hartman 16625b775f67SGreg Kroah-Hartman n = 0; 16635b775f67SGreg Kroah-Hartman 16645b775f67SGreg Kroah-Hartman usbtmc_clear_check_status: 16655b775f67SGreg Kroah-Hartman 16665b775f67SGreg Kroah-Hartman dev_dbg(dev, "Sending CHECK_CLEAR_STATUS request\n"); 16675b775f67SGreg Kroah-Hartman 16685b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 16695b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 16705b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_CLEAR_STATUS, 16715b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 1672dfee02acSGuido Kiener 0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT); 16735b775f67SGreg Kroah-Hartman if (rv < 0) { 16745b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 16755b775f67SGreg Kroah-Hartman goto exit; 16765b775f67SGreg Kroah-Hartman } 16775b775f67SGreg Kroah-Hartman 16785b775f67SGreg Kroah-Hartman dev_dbg(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); 16795b775f67SGreg Kroah-Hartman 16805b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) 16815b775f67SGreg Kroah-Hartman goto usbtmc_clear_bulk_out_halt; 16825b775f67SGreg Kroah-Hartman 16835b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_PENDING) { 16845b775f67SGreg Kroah-Hartman dev_err(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); 16855b775f67SGreg Kroah-Hartman rv = -EPERM; 16865b775f67SGreg Kroah-Hartman goto exit; 16875b775f67SGreg Kroah-Hartman } 16885b775f67SGreg Kroah-Hartman 1689dfee02acSGuido Kiener if ((buffer[1] & 1) != 0) { 16905b775f67SGreg Kroah-Hartman do { 16915b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 16925b775f67SGreg Kroah-Hartman 16935b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 16945b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 16955b775f67SGreg Kroah-Hartman data->bulk_in), 1696dfee02acSGuido Kiener buffer, USBTMC_BUFSIZE, 1697dfee02acSGuido Kiener &actual, USB_CTRL_GET_TIMEOUT); 1698dfee02acSGuido Kiener 1699dfee02acSGuido Kiener print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 1700dfee02acSGuido Kiener 16, 1, buffer, actual, true); 1701dfee02acSGuido Kiener 17025b775f67SGreg Kroah-Hartman n++; 17035b775f67SGreg Kroah-Hartman 17045b775f67SGreg Kroah-Hartman if (rv < 0) { 17055b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", 17065b775f67SGreg Kroah-Hartman rv); 17075b775f67SGreg Kroah-Hartman goto exit; 17085b775f67SGreg Kroah-Hartman } 1709dfee02acSGuido Kiener } while ((actual == USBTMC_BUFSIZE) && 17105b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); 1711dfee02acSGuido Kiener } else { 1712dfee02acSGuido Kiener /* do not stress device with subsequent requests */ 1713dfee02acSGuido Kiener msleep(50); 1714dfee02acSGuido Kiener n++; 1715dfee02acSGuido Kiener } 17165b775f67SGreg Kroah-Hartman 1717dfee02acSGuido Kiener if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) { 17185b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 17195b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 17205b775f67SGreg Kroah-Hartman rv = -EPERM; 17215b775f67SGreg Kroah-Hartman goto exit; 17225b775f67SGreg Kroah-Hartman } 17235b775f67SGreg Kroah-Hartman 17245b775f67SGreg Kroah-Hartman goto usbtmc_clear_check_status; 17255b775f67SGreg Kroah-Hartman 17265b775f67SGreg Kroah-Hartman usbtmc_clear_bulk_out_halt: 17275b775f67SGreg Kroah-Hartman 17283342ecdaSSarah Sharp rv = usb_clear_halt(data->usb_dev, 17293342ecdaSSarah Sharp usb_sndbulkpipe(data->usb_dev, data->bulk_out)); 17305b775f67SGreg Kroah-Hartman if (rv < 0) { 1731dfee02acSGuido Kiener dev_err(dev, "usb_clear_halt returned %d\n", rv); 17325b775f67SGreg Kroah-Hartman goto exit; 17335b775f67SGreg Kroah-Hartman } 17345b775f67SGreg Kroah-Hartman rv = 0; 17355b775f67SGreg Kroah-Hartman 17365b775f67SGreg Kroah-Hartman exit: 17375b775f67SGreg Kroah-Hartman kfree(buffer); 17385b775f67SGreg Kroah-Hartman return rv; 17395b775f67SGreg Kroah-Hartman } 17405b775f67SGreg Kroah-Hartman 17415b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data) 17425b775f67SGreg Kroah-Hartman { 17435b775f67SGreg Kroah-Hartman int rv; 17445b775f67SGreg Kroah-Hartman 17453342ecdaSSarah Sharp rv = usb_clear_halt(data->usb_dev, 17463342ecdaSSarah Sharp usb_sndbulkpipe(data->usb_dev, data->bulk_out)); 17475b775f67SGreg Kroah-Hartman 1748*fd784cadSGuido Kiener if (rv < 0) 1749*fd784cadSGuido Kiener dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv); 17505b775f67SGreg Kroah-Hartman return rv; 17515b775f67SGreg Kroah-Hartman } 17525b775f67SGreg Kroah-Hartman 17535b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) 17545b775f67SGreg Kroah-Hartman { 17555b775f67SGreg Kroah-Hartman int rv; 17565b775f67SGreg Kroah-Hartman 17573342ecdaSSarah Sharp rv = usb_clear_halt(data->usb_dev, 17583342ecdaSSarah Sharp usb_rcvbulkpipe(data->usb_dev, data->bulk_in)); 17595b775f67SGreg Kroah-Hartman 1760*fd784cadSGuido Kiener if (rv < 0) 1761*fd784cadSGuido Kiener dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv); 17625b775f67SGreg Kroah-Hartman return rv; 17635b775f67SGreg Kroah-Hartman } 17645b775f67SGreg Kroah-Hartman 17654ddc645fSGuido Kiener static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data) 17664ddc645fSGuido Kiener { 17674ddc645fSGuido Kiener spin_lock_irq(&file_data->err_lock); 1768bb99794aSGuido Kiener file_data->in_status = -ECANCELED; 17694ddc645fSGuido Kiener file_data->out_status = -ECANCELED; 17704ddc645fSGuido Kiener spin_unlock_irq(&file_data->err_lock); 17714ddc645fSGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 17724ddc645fSGuido Kiener return 0; 17734ddc645fSGuido Kiener } 17744ddc645fSGuido Kiener 1775987b8199SGuido Kiener static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data) 1776987b8199SGuido Kiener { 1777987b8199SGuido Kiener usb_kill_anchored_urbs(&file_data->submitted); 1778987b8199SGuido Kiener usb_scuttle_anchored_urbs(&file_data->in_anchor); 1779987b8199SGuido Kiener spin_lock_irq(&file_data->err_lock); 1780987b8199SGuido Kiener file_data->in_status = 0; 1781987b8199SGuido Kiener file_data->in_transfer_size = 0; 1782987b8199SGuido Kiener file_data->out_status = 0; 1783987b8199SGuido Kiener file_data->out_transfer_size = 0; 1784987b8199SGuido Kiener spin_unlock_irq(&file_data->err_lock); 1785987b8199SGuido Kiener 1786987b8199SGuido Kiener file_data->in_urbs_used = 0; 1787987b8199SGuido Kiener return 0; 1788987b8199SGuido Kiener } 1789987b8199SGuido Kiener 17905b775f67SGreg Kroah-Hartman static int get_capabilities(struct usbtmc_device_data *data) 17915b775f67SGreg Kroah-Hartman { 17925b775f67SGreg Kroah-Hartman struct device *dev = &data->usb_dev->dev; 17935b775f67SGreg Kroah-Hartman char *buffer; 1794ca157c4aSOliver Neukum int rv = 0; 17955b775f67SGreg Kroah-Hartman 17965b775f67SGreg Kroah-Hartman buffer = kmalloc(0x18, GFP_KERNEL); 17975b775f67SGreg Kroah-Hartman if (!buffer) 17985b775f67SGreg Kroah-Hartman return -ENOMEM; 17995b775f67SGreg Kroah-Hartman 18005b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), 18015b775f67SGreg Kroah-Hartman USBTMC_REQUEST_GET_CAPABILITIES, 18025b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 180363c97bbaSGuido Kiener 0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT); 18045b775f67SGreg Kroah-Hartman if (rv < 0) { 18055b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 1806ca157c4aSOliver Neukum goto err_out; 18075b775f67SGreg Kroah-Hartman } 18085b775f67SGreg Kroah-Hartman 18095b775f67SGreg Kroah-Hartman dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); 18105b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 18115b775f67SGreg Kroah-Hartman dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); 1812ca157c4aSOliver Neukum rv = -EPERM; 1813ca157c4aSOliver Neukum goto err_out; 18145b775f67SGreg Kroah-Hartman } 1815d0a38365SGergely Imreh dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]); 1816d0a38365SGergely Imreh dev_dbg(dev, "Device capabilities are %x\n", buffer[5]); 1817d0a38365SGergely Imreh dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]); 1818d0a38365SGergely Imreh dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]); 18195b775f67SGreg Kroah-Hartman 18205b775f67SGreg Kroah-Hartman data->capabilities.interface_capabilities = buffer[4]; 18215b775f67SGreg Kroah-Hartman data->capabilities.device_capabilities = buffer[5]; 18225b775f67SGreg Kroah-Hartman data->capabilities.usb488_interface_capabilities = buffer[14]; 18235b775f67SGreg Kroah-Hartman data->capabilities.usb488_device_capabilities = buffer[15]; 182429779d89SDave Penkler data->usb488_caps = (buffer[14] & 0x07) | ((buffer[15] & 0x0f) << 4); 1825d0a38365SGergely Imreh rv = 0; 18265b775f67SGreg Kroah-Hartman 1827ca157c4aSOliver Neukum err_out: 18285b775f67SGreg Kroah-Hartman kfree(buffer); 1829ca157c4aSOliver Neukum return rv; 18305b775f67SGreg Kroah-Hartman } 18315b775f67SGreg Kroah-Hartman 18325b775f67SGreg Kroah-Hartman #define capability_attribute(name) \ 18332a6eb8acSGreg Kroah-Hartman static ssize_t name##_show(struct device *dev, \ 18345b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 18355b775f67SGreg Kroah-Hartman { \ 18365b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 18375b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 18385b775f67SGreg Kroah-Hartman \ 18395b775f67SGreg Kroah-Hartman return sprintf(buf, "%d\n", data->capabilities.name); \ 18405b775f67SGreg Kroah-Hartman } \ 18412a6eb8acSGreg Kroah-Hartman static DEVICE_ATTR_RO(name) 18425b775f67SGreg Kroah-Hartman 18435b775f67SGreg Kroah-Hartman capability_attribute(interface_capabilities); 18445b775f67SGreg Kroah-Hartman capability_attribute(device_capabilities); 18455b775f67SGreg Kroah-Hartman capability_attribute(usb488_interface_capabilities); 18465b775f67SGreg Kroah-Hartman capability_attribute(usb488_device_capabilities); 18475b775f67SGreg Kroah-Hartman 18485b775f67SGreg Kroah-Hartman static struct attribute *capability_attrs[] = { 18495b775f67SGreg Kroah-Hartman &dev_attr_interface_capabilities.attr, 18505b775f67SGreg Kroah-Hartman &dev_attr_device_capabilities.attr, 18515b775f67SGreg Kroah-Hartman &dev_attr_usb488_interface_capabilities.attr, 18525b775f67SGreg Kroah-Hartman &dev_attr_usb488_device_capabilities.attr, 18535b775f67SGreg Kroah-Hartman NULL, 18545b775f67SGreg Kroah-Hartman }; 18555b775f67SGreg Kroah-Hartman 1856a70df964SArvind Yadav static const struct attribute_group capability_attr_grp = { 18575b775f67SGreg Kroah-Hartman .attrs = capability_attrs, 18585b775f67SGreg Kroah-Hartman }; 18595b775f67SGreg Kroah-Hartman 18602a6eb8acSGreg Kroah-Hartman static ssize_t TermChar_show(struct device *dev, 18615b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 18625b775f67SGreg Kroah-Hartman { 18635b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); 18645b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); 18655b775f67SGreg Kroah-Hartman 18665b775f67SGreg Kroah-Hartman return sprintf(buf, "%c\n", data->TermChar); 18675b775f67SGreg Kroah-Hartman } 18685b775f67SGreg Kroah-Hartman 18692a6eb8acSGreg Kroah-Hartman static ssize_t TermChar_store(struct device *dev, 18705b775f67SGreg Kroah-Hartman struct device_attribute *attr, 18715b775f67SGreg Kroah-Hartman const char *buf, size_t count) 18725b775f67SGreg Kroah-Hartman { 18735b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); 18745b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); 18755b775f67SGreg Kroah-Hartman 18765b775f67SGreg Kroah-Hartman if (count < 1) 18775b775f67SGreg Kroah-Hartman return -EINVAL; 18785b775f67SGreg Kroah-Hartman data->TermChar = buf[0]; 18795b775f67SGreg Kroah-Hartman return count; 18805b775f67SGreg Kroah-Hartman } 18812a6eb8acSGreg Kroah-Hartman static DEVICE_ATTR_RW(TermChar); 18825b775f67SGreg Kroah-Hartman 18835b775f67SGreg Kroah-Hartman #define data_attribute(name) \ 18842a6eb8acSGreg Kroah-Hartman static ssize_t name##_show(struct device *dev, \ 18855b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 18865b775f67SGreg Kroah-Hartman { \ 18875b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 18885b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 18895b775f67SGreg Kroah-Hartman \ 18905b775f67SGreg Kroah-Hartman return sprintf(buf, "%d\n", data->name); \ 18915b775f67SGreg Kroah-Hartman } \ 18922a6eb8acSGreg Kroah-Hartman static ssize_t name##_store(struct device *dev, \ 18935b775f67SGreg Kroah-Hartman struct device_attribute *attr, \ 18945b775f67SGreg Kroah-Hartman const char *buf, size_t count) \ 18955b775f67SGreg Kroah-Hartman { \ 18965b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 18975b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 18985b775f67SGreg Kroah-Hartman ssize_t result; \ 18995b775f67SGreg Kroah-Hartman unsigned val; \ 19005b775f67SGreg Kroah-Hartman \ 19015b775f67SGreg Kroah-Hartman result = sscanf(buf, "%u\n", &val); \ 19025b775f67SGreg Kroah-Hartman if (result != 1) \ 19035b775f67SGreg Kroah-Hartman result = -EINVAL; \ 19045b775f67SGreg Kroah-Hartman data->name = val; \ 19055b775f67SGreg Kroah-Hartman if (result < 0) \ 19065b775f67SGreg Kroah-Hartman return result; \ 19075b775f67SGreg Kroah-Hartman else \ 19085b775f67SGreg Kroah-Hartman return count; \ 19095b775f67SGreg Kroah-Hartman } \ 19102a6eb8acSGreg Kroah-Hartman static DEVICE_ATTR_RW(name) 19115b775f67SGreg Kroah-Hartman 19125b775f67SGreg Kroah-Hartman data_attribute(TermCharEnabled); 19135b775f67SGreg Kroah-Hartman data_attribute(auto_abort); 19145b775f67SGreg Kroah-Hartman 19155b775f67SGreg Kroah-Hartman static struct attribute *data_attrs[] = { 19165b775f67SGreg Kroah-Hartman &dev_attr_TermChar.attr, 19175b775f67SGreg Kroah-Hartman &dev_attr_TermCharEnabled.attr, 19185b775f67SGreg Kroah-Hartman &dev_attr_auto_abort.attr, 19195b775f67SGreg Kroah-Hartman NULL, 19205b775f67SGreg Kroah-Hartman }; 19215b775f67SGreg Kroah-Hartman 1922a70df964SArvind Yadav static const struct attribute_group data_attr_grp = { 19235b775f67SGreg Kroah-Hartman .attrs = data_attrs, 19245b775f67SGreg Kroah-Hartman }; 19255b775f67SGreg Kroah-Hartman 19265b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) 19275b775f67SGreg Kroah-Hartman { 19285b775f67SGreg Kroah-Hartman struct device *dev; 19295b775f67SGreg Kroah-Hartman u8 *buffer; 19305b775f67SGreg Kroah-Hartman int rv; 19315b775f67SGreg Kroah-Hartman 19325b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 19335b775f67SGreg Kroah-Hartman 19345b775f67SGreg Kroah-Hartman buffer = kmalloc(2, GFP_KERNEL); 19355b775f67SGreg Kroah-Hartman if (!buffer) 19365b775f67SGreg Kroah-Hartman return -ENOMEM; 19375b775f67SGreg Kroah-Hartman 19385b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 19395b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 19405b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INDICATOR_PULSE, 19415b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 194263c97bbaSGuido Kiener 0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT); 19435b775f67SGreg Kroah-Hartman 19445b775f67SGreg Kroah-Hartman if (rv < 0) { 19455b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 19465b775f67SGreg Kroah-Hartman goto exit; 19475b775f67SGreg Kroah-Hartman } 19485b775f67SGreg Kroah-Hartman 19495b775f67SGreg Kroah-Hartman dev_dbg(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); 19505b775f67SGreg Kroah-Hartman 19515b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 19525b775f67SGreg Kroah-Hartman dev_err(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); 19535b775f67SGreg Kroah-Hartman rv = -EPERM; 19545b775f67SGreg Kroah-Hartman goto exit; 19555b775f67SGreg Kroah-Hartman } 19565b775f67SGreg Kroah-Hartman rv = 0; 19575b775f67SGreg Kroah-Hartman 19585b775f67SGreg Kroah-Hartman exit: 19595b775f67SGreg Kroah-Hartman kfree(buffer); 19605b775f67SGreg Kroah-Hartman return rv; 19615b775f67SGreg Kroah-Hartman } 19625b775f67SGreg Kroah-Hartman 1963658f24f4SGuido Kiener static int usbtmc_ioctl_request(struct usbtmc_device_data *data, 1964658f24f4SGuido Kiener void __user *arg) 1965658f24f4SGuido Kiener { 1966658f24f4SGuido Kiener struct device *dev = &data->intf->dev; 1967658f24f4SGuido Kiener struct usbtmc_ctrlrequest request; 1968658f24f4SGuido Kiener u8 *buffer = NULL; 1969658f24f4SGuido Kiener int rv; 1970658f24f4SGuido Kiener unsigned long res; 1971658f24f4SGuido Kiener 1972658f24f4SGuido Kiener res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest)); 1973658f24f4SGuido Kiener if (res) 1974658f24f4SGuido Kiener return -EFAULT; 1975658f24f4SGuido Kiener 1976658f24f4SGuido Kiener buffer = kmalloc(request.req.wLength, GFP_KERNEL); 1977658f24f4SGuido Kiener if (!buffer) 1978658f24f4SGuido Kiener return -ENOMEM; 1979658f24f4SGuido Kiener 1980658f24f4SGuido Kiener if (request.req.wLength > USBTMC_BUFSIZE) 1981658f24f4SGuido Kiener return -EMSGSIZE; 1982658f24f4SGuido Kiener 1983658f24f4SGuido Kiener if (request.req.wLength) { 1984658f24f4SGuido Kiener buffer = kmalloc(request.req.wLength, GFP_KERNEL); 1985658f24f4SGuido Kiener if (!buffer) 1986658f24f4SGuido Kiener return -ENOMEM; 1987658f24f4SGuido Kiener 1988658f24f4SGuido Kiener if ((request.req.bRequestType & USB_DIR_IN) == 0) { 1989658f24f4SGuido Kiener /* Send control data to device */ 1990658f24f4SGuido Kiener res = copy_from_user(buffer, request.data, 1991658f24f4SGuido Kiener request.req.wLength); 1992658f24f4SGuido Kiener if (res) { 1993658f24f4SGuido Kiener rv = -EFAULT; 1994658f24f4SGuido Kiener goto exit; 1995658f24f4SGuido Kiener } 1996658f24f4SGuido Kiener } 1997658f24f4SGuido Kiener } 1998658f24f4SGuido Kiener 1999658f24f4SGuido Kiener rv = usb_control_msg(data->usb_dev, 2000658f24f4SGuido Kiener usb_rcvctrlpipe(data->usb_dev, 0), 2001658f24f4SGuido Kiener request.req.bRequest, 2002658f24f4SGuido Kiener request.req.bRequestType, 2003658f24f4SGuido Kiener request.req.wValue, 2004658f24f4SGuido Kiener request.req.wIndex, 2005658f24f4SGuido Kiener buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT); 2006658f24f4SGuido Kiener 2007658f24f4SGuido Kiener if (rv < 0) { 2008658f24f4SGuido Kiener dev_err(dev, "%s failed %d\n", __func__, rv); 2009658f24f4SGuido Kiener goto exit; 2010658f24f4SGuido Kiener } 2011658f24f4SGuido Kiener 2012658f24f4SGuido Kiener if (rv && (request.req.bRequestType & USB_DIR_IN)) { 2013658f24f4SGuido Kiener /* Read control data from device */ 2014658f24f4SGuido Kiener res = copy_to_user(request.data, buffer, rv); 2015658f24f4SGuido Kiener if (res) 2016658f24f4SGuido Kiener rv = -EFAULT; 2017658f24f4SGuido Kiener } 2018658f24f4SGuido Kiener 2019658f24f4SGuido Kiener exit: 2020658f24f4SGuido Kiener kfree(buffer); 2021658f24f4SGuido Kiener return rv; 2022658f24f4SGuido Kiener } 2023658f24f4SGuido Kiener 2024048c6d88SGuido Kiener /* 2025048c6d88SGuido Kiener * Get the usb timeout value 2026048c6d88SGuido Kiener */ 2027048c6d88SGuido Kiener static int usbtmc_ioctl_get_timeout(struct usbtmc_file_data *file_data, 2028048c6d88SGuido Kiener void __user *arg) 2029048c6d88SGuido Kiener { 2030048c6d88SGuido Kiener u32 timeout; 2031048c6d88SGuido Kiener 2032048c6d88SGuido Kiener timeout = file_data->timeout; 2033048c6d88SGuido Kiener 2034048c6d88SGuido Kiener return put_user(timeout, (__u32 __user *)arg); 2035048c6d88SGuido Kiener } 2036048c6d88SGuido Kiener 2037048c6d88SGuido Kiener /* 2038048c6d88SGuido Kiener * Set the usb timeout value 2039048c6d88SGuido Kiener */ 2040048c6d88SGuido Kiener static int usbtmc_ioctl_set_timeout(struct usbtmc_file_data *file_data, 2041048c6d88SGuido Kiener void __user *arg) 2042048c6d88SGuido Kiener { 2043048c6d88SGuido Kiener u32 timeout; 2044048c6d88SGuido Kiener 2045048c6d88SGuido Kiener if (get_user(timeout, (__u32 __user *)arg)) 2046048c6d88SGuido Kiener return -EFAULT; 2047048c6d88SGuido Kiener 2048048c6d88SGuido Kiener /* Note that timeout = 0 means 2049048c6d88SGuido Kiener * MAX_SCHEDULE_TIMEOUT in usb_control_msg 2050048c6d88SGuido Kiener */ 2051048c6d88SGuido Kiener if (timeout < USBTMC_MIN_TIMEOUT) 2052048c6d88SGuido Kiener return -EINVAL; 2053048c6d88SGuido Kiener 2054048c6d88SGuido Kiener file_data->timeout = timeout; 2055048c6d88SGuido Kiener 2056048c6d88SGuido Kiener return 0; 2057048c6d88SGuido Kiener } 2058048c6d88SGuido Kiener 2059fbd83971SGuido Kiener /* 2060fbd83971SGuido Kiener * enables/disables sending EOM on write 2061fbd83971SGuido Kiener */ 2062fbd83971SGuido Kiener static int usbtmc_ioctl_eom_enable(struct usbtmc_file_data *file_data, 2063fbd83971SGuido Kiener void __user *arg) 2064fbd83971SGuido Kiener { 2065fbd83971SGuido Kiener u8 eom_enable; 2066fbd83971SGuido Kiener 2067fbd83971SGuido Kiener if (copy_from_user(&eom_enable, arg, sizeof(eom_enable))) 2068fbd83971SGuido Kiener return -EFAULT; 2069fbd83971SGuido Kiener 2070fbd83971SGuido Kiener if (eom_enable > 1) 2071fbd83971SGuido Kiener return -EINVAL; 2072fbd83971SGuido Kiener 2073fbd83971SGuido Kiener file_data->eom_val = eom_enable; 2074fbd83971SGuido Kiener 2075fbd83971SGuido Kiener return 0; 2076fbd83971SGuido Kiener } 2077fbd83971SGuido Kiener 207812dcaeb7SGuido Kiener /* 207912dcaeb7SGuido Kiener * Configure termination character for read() 208012dcaeb7SGuido Kiener */ 208112dcaeb7SGuido Kiener static int usbtmc_ioctl_config_termc(struct usbtmc_file_data *file_data, 208212dcaeb7SGuido Kiener void __user *arg) 208312dcaeb7SGuido Kiener { 208412dcaeb7SGuido Kiener struct usbtmc_termchar termc; 208512dcaeb7SGuido Kiener 208612dcaeb7SGuido Kiener if (copy_from_user(&termc, arg, sizeof(termc))) 208712dcaeb7SGuido Kiener return -EFAULT; 208812dcaeb7SGuido Kiener 208912dcaeb7SGuido Kiener if ((termc.term_char_enabled > 1) || 209012dcaeb7SGuido Kiener (termc.term_char_enabled && 209112dcaeb7SGuido Kiener !(file_data->data->capabilities.device_capabilities & 1))) 209212dcaeb7SGuido Kiener return -EINVAL; 209312dcaeb7SGuido Kiener 209412dcaeb7SGuido Kiener file_data->term_char = termc.term_char; 209512dcaeb7SGuido Kiener file_data->term_char_enabled = termc.term_char_enabled; 209612dcaeb7SGuido Kiener 209712dcaeb7SGuido Kiener return 0; 209812dcaeb7SGuido Kiener } 209912dcaeb7SGuido Kiener 21005b775f67SGreg Kroah-Hartman static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 21015b775f67SGreg Kroah-Hartman { 21024f3c8d6eSGuido Kiener struct usbtmc_file_data *file_data; 21035b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 21045b775f67SGreg Kroah-Hartman int retval = -EBADRQC; 2105ec34d08eSGuido Kiener __u8 tmp_byte; 21065b775f67SGreg Kroah-Hartman 21074f3c8d6eSGuido Kiener file_data = file->private_data; 21084f3c8d6eSGuido Kiener data = file_data->data; 21094f3c8d6eSGuido Kiener 21105b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 211186286883SOliver Neukum if (data->zombie) { 211286286883SOliver Neukum retval = -ENODEV; 211386286883SOliver Neukum goto skip_io_on_zombie; 211486286883SOliver Neukum } 21155b775f67SGreg Kroah-Hartman 21165b775f67SGreg Kroah-Hartman switch (cmd) { 21175b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR_OUT_HALT: 21185b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear_out_halt(data); 2119a92b63e7SGreg Kroah-Hartman break; 21205b775f67SGreg Kroah-Hartman 21215b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR_IN_HALT: 21225b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear_in_halt(data); 2123a92b63e7SGreg Kroah-Hartman break; 21245b775f67SGreg Kroah-Hartman 21255b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_INDICATOR_PULSE: 21265b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_indicator_pulse(data); 2127a92b63e7SGreg Kroah-Hartman break; 21285b775f67SGreg Kroah-Hartman 21295b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR: 21305b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear(data); 2131a92b63e7SGreg Kroah-Hartman break; 21325b775f67SGreg Kroah-Hartman 21335b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_ABORT_BULK_OUT: 21345b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_abort_bulk_out(data); 2135a92b63e7SGreg Kroah-Hartman break; 21365b775f67SGreg Kroah-Hartman 21375b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_ABORT_BULK_IN: 21385b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_abort_bulk_in(data); 2139a92b63e7SGreg Kroah-Hartman break; 2140dbf3e7f6SDave Penkler 2141658f24f4SGuido Kiener case USBTMC_IOCTL_CTRL_REQUEST: 2142658f24f4SGuido Kiener retval = usbtmc_ioctl_request(data, (void __user *)arg); 2143658f24f4SGuido Kiener break; 2144658f24f4SGuido Kiener 2145048c6d88SGuido Kiener case USBTMC_IOCTL_GET_TIMEOUT: 2146048c6d88SGuido Kiener retval = usbtmc_ioctl_get_timeout(file_data, 2147048c6d88SGuido Kiener (void __user *)arg); 2148048c6d88SGuido Kiener break; 2149048c6d88SGuido Kiener 2150048c6d88SGuido Kiener case USBTMC_IOCTL_SET_TIMEOUT: 2151048c6d88SGuido Kiener retval = usbtmc_ioctl_set_timeout(file_data, 2152048c6d88SGuido Kiener (void __user *)arg); 2153048c6d88SGuido Kiener break; 2154048c6d88SGuido Kiener 2155fbd83971SGuido Kiener case USBTMC_IOCTL_EOM_ENABLE: 2156fbd83971SGuido Kiener retval = usbtmc_ioctl_eom_enable(file_data, 2157fbd83971SGuido Kiener (void __user *)arg); 2158fbd83971SGuido Kiener break; 2159fbd83971SGuido Kiener 216012dcaeb7SGuido Kiener case USBTMC_IOCTL_CONFIG_TERMCHAR: 216112dcaeb7SGuido Kiener retval = usbtmc_ioctl_config_termc(file_data, 216212dcaeb7SGuido Kiener (void __user *)arg); 216312dcaeb7SGuido Kiener break; 216412dcaeb7SGuido Kiener 21654ddc645fSGuido Kiener case USBTMC_IOCTL_WRITE: 21664ddc645fSGuido Kiener retval = usbtmc_ioctl_generic_write(file_data, 21674ddc645fSGuido Kiener (void __user *)arg); 21684ddc645fSGuido Kiener break; 21694ddc645fSGuido Kiener 2170bb99794aSGuido Kiener case USBTMC_IOCTL_READ: 2171bb99794aSGuido Kiener retval = usbtmc_ioctl_generic_read(file_data, 2172bb99794aSGuido Kiener (void __user *)arg); 2173bb99794aSGuido Kiener break; 2174bb99794aSGuido Kiener 2175b1498451SGuido Kiener case USBTMC_IOCTL_WRITE_RESULT: 2176b1498451SGuido Kiener retval = usbtmc_ioctl_write_result(file_data, 2177b1498451SGuido Kiener (void __user *)arg); 2178b1498451SGuido Kiener break; 2179b1498451SGuido Kiener 2180e013477bSGuido Kiener case USBTMC_IOCTL_API_VERSION: 2181e013477bSGuido Kiener retval = put_user(USBTMC_API_VERSION, 2182e013477bSGuido Kiener (__u32 __user *)arg); 2183e013477bSGuido Kiener break; 2184e013477bSGuido Kiener 218529779d89SDave Penkler case USBTMC488_IOCTL_GET_CAPS: 2186*fd784cadSGuido Kiener retval = put_user(data->usb488_caps, 2187*fd784cadSGuido Kiener (unsigned char __user *)arg); 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