15b775f67SGreg Kroah-Hartman /** 2af901ca1SAndré Goddard Rosa * drivers/usb/class/usbtmc.c - USB Test & Measurement class driver 35b775f67SGreg Kroah-Hartman * 45b775f67SGreg Kroah-Hartman * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany 55b775f67SGreg Kroah-Hartman * Copyright (C) 2008 Novell, Inc. 65b775f67SGreg Kroah-Hartman * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> 75b775f67SGreg Kroah-Hartman * 85b775f67SGreg Kroah-Hartman * This program is free software; you can redistribute it and/or 95b775f67SGreg Kroah-Hartman * modify it under the terms of the GNU General Public License 105b775f67SGreg Kroah-Hartman * as published by the Free Software Foundation; either version 2 115b775f67SGreg Kroah-Hartman * of the License, or (at your option) any later version. 125b775f67SGreg Kroah-Hartman * 135b775f67SGreg Kroah-Hartman * This program is distributed in the hope that it will be useful, 145b775f67SGreg Kroah-Hartman * but WITHOUT ANY WARRANTY; without even the implied warranty of 155b775f67SGreg Kroah-Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 165b775f67SGreg Kroah-Hartman * GNU General Public License for more details. 175b775f67SGreg Kroah-Hartman * 185b775f67SGreg Kroah-Hartman * The GNU General Public License is available at 195b775f67SGreg Kroah-Hartman * http://www.gnu.org/copyleft/gpl.html. 205b775f67SGreg Kroah-Hartman */ 215b775f67SGreg Kroah-Hartman 225b775f67SGreg Kroah-Hartman #include <linux/init.h> 235b775f67SGreg Kroah-Hartman #include <linux/module.h> 24857cc4dfSIlpo Järvinen #include <linux/kernel.h> 255b775f67SGreg Kroah-Hartman #include <linux/fs.h> 265b775f67SGreg Kroah-Hartman #include <linux/uaccess.h> 275b775f67SGreg Kroah-Hartman #include <linux/kref.h> 285b775f67SGreg Kroah-Hartman #include <linux/mutex.h> 295b775f67SGreg Kroah-Hartman #include <linux/usb.h> 305b775f67SGreg Kroah-Hartman #include <linux/usb/tmc.h> 315b775f67SGreg Kroah-Hartman 325b775f67SGreg Kroah-Hartman 335b775f67SGreg Kroah-Hartman #define USBTMC_MINOR_BASE 176 345b775f67SGreg Kroah-Hartman 355b775f67SGreg Kroah-Hartman /* 365b775f67SGreg Kroah-Hartman * Size of driver internal IO buffer. Must be multiple of 4 and at least as 375b775f67SGreg Kroah-Hartman * large as wMaxPacketSize (which is usually 512 bytes). 385b775f67SGreg Kroah-Hartman */ 395b775f67SGreg Kroah-Hartman #define USBTMC_SIZE_IOBUFFER 2048 405b775f67SGreg Kroah-Hartman 415b775f67SGreg Kroah-Hartman /* Default USB timeout (in milliseconds) */ 4235f76e89SGergely Imreh #define USBTMC_TIMEOUT 5000 435b775f67SGreg Kroah-Hartman 445b775f67SGreg Kroah-Hartman /* 455b775f67SGreg Kroah-Hartman * Maximum number of read cycles to empty bulk in endpoint during CLEAR and 465b775f67SGreg Kroah-Hartman * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short 475b775f67SGreg Kroah-Hartman * packet is never read. 485b775f67SGreg Kroah-Hartman */ 495b775f67SGreg Kroah-Hartman #define USBTMC_MAX_READS_TO_CLEAR_BULK_IN 100 505b775f67SGreg Kroah-Hartman 515b775f67SGreg Kroah-Hartman static struct usb_device_id usbtmc_devices[] = { 525b775f67SGreg Kroah-Hartman { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), }, 53228dd05dSGreg Kroah-Hartman { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), }, 545b775f67SGreg Kroah-Hartman { 0, } /* terminating entry */ 555b775f67SGreg Kroah-Hartman }; 565413aa46SGreg Kroah-Hartman MODULE_DEVICE_TABLE(usb, usbtmc_devices); 575b775f67SGreg Kroah-Hartman 585b775f67SGreg Kroah-Hartman /* 595b775f67SGreg Kroah-Hartman * This structure is the capabilities for the device 60d0a38365SGergely Imreh * See section 4.2.1.8 of the USBTMC specification, 61d0a38365SGergely Imreh * and section 4.2.2 of the USBTMC usb488 subclass 62d0a38365SGergely Imreh * specification for details. 635b775f67SGreg Kroah-Hartman */ 645b775f67SGreg Kroah-Hartman struct usbtmc_dev_capabilities { 655b775f67SGreg Kroah-Hartman __u8 interface_capabilities; 665b775f67SGreg Kroah-Hartman __u8 device_capabilities; 675b775f67SGreg Kroah-Hartman __u8 usb488_interface_capabilities; 685b775f67SGreg Kroah-Hartman __u8 usb488_device_capabilities; 695b775f67SGreg Kroah-Hartman }; 705b775f67SGreg Kroah-Hartman 715b775f67SGreg Kroah-Hartman /* This structure holds private data for each USBTMC device. One copy is 725b775f67SGreg Kroah-Hartman * allocated for each USBTMC device in the driver's probe function. 735b775f67SGreg Kroah-Hartman */ 745b775f67SGreg Kroah-Hartman struct usbtmc_device_data { 755b775f67SGreg Kroah-Hartman const struct usb_device_id *id; 765b775f67SGreg Kroah-Hartman struct usb_device *usb_dev; 775b775f67SGreg Kroah-Hartman struct usb_interface *intf; 785b775f67SGreg Kroah-Hartman 795b775f67SGreg Kroah-Hartman unsigned int bulk_in; 805b775f67SGreg Kroah-Hartman unsigned int bulk_out; 815b775f67SGreg Kroah-Hartman 825b775f67SGreg Kroah-Hartman u8 bTag; 835b775f67SGreg Kroah-Hartman u8 bTag_last_write; /* needed for abort */ 845b775f67SGreg Kroah-Hartman u8 bTag_last_read; /* needed for abort */ 855b775f67SGreg Kroah-Hartman 865b775f67SGreg Kroah-Hartman /* attributes from the USB TMC spec for this device */ 875b775f67SGreg Kroah-Hartman u8 TermChar; 885b775f67SGreg Kroah-Hartman bool TermCharEnabled; 895b775f67SGreg Kroah-Hartman bool auto_abort; 905b775f67SGreg Kroah-Hartman 9186286883SOliver Neukum bool zombie; /* fd of disconnected device */ 9286286883SOliver Neukum 935b775f67SGreg Kroah-Hartman struct usbtmc_dev_capabilities capabilities; 945b775f67SGreg Kroah-Hartman struct kref kref; 955b775f67SGreg Kroah-Hartman struct mutex io_mutex; /* only one i/o function running at a time */ 965b775f67SGreg Kroah-Hartman }; 975b775f67SGreg Kroah-Hartman #define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref) 985b775f67SGreg Kroah-Hartman 995b775f67SGreg Kroah-Hartman /* Forward declarations */ 1005b775f67SGreg Kroah-Hartman static struct usb_driver usbtmc_driver; 1015b775f67SGreg Kroah-Hartman 1025b775f67SGreg Kroah-Hartman static void usbtmc_delete(struct kref *kref) 1035b775f67SGreg Kroah-Hartman { 1045b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = to_usbtmc_data(kref); 1055b775f67SGreg Kroah-Hartman 1065b775f67SGreg Kroah-Hartman usb_put_dev(data->usb_dev); 1075b775f67SGreg Kroah-Hartman kfree(data); 1085b775f67SGreg Kroah-Hartman } 1095b775f67SGreg Kroah-Hartman 1105b775f67SGreg Kroah-Hartman static int usbtmc_open(struct inode *inode, struct file *filp) 1115b775f67SGreg Kroah-Hartman { 1125b775f67SGreg Kroah-Hartman struct usb_interface *intf; 1135b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 1145b10916eSGreg Kroah-Hartman int retval = 0; 1155b775f67SGreg Kroah-Hartman 1165b775f67SGreg Kroah-Hartman intf = usb_find_interface(&usbtmc_driver, iminor(inode)); 1175b775f67SGreg Kroah-Hartman if (!intf) { 1185b775f67SGreg Kroah-Hartman printk(KERN_ERR KBUILD_MODNAME 1195b775f67SGreg Kroah-Hartman ": can not find device for minor %d", iminor(inode)); 1205b10916eSGreg Kroah-Hartman retval = -ENODEV; 1215b775f67SGreg Kroah-Hartman goto exit; 1225b775f67SGreg Kroah-Hartman } 1235b775f67SGreg Kroah-Hartman 1245b775f67SGreg Kroah-Hartman data = usb_get_intfdata(intf); 1255b775f67SGreg Kroah-Hartman kref_get(&data->kref); 1265b775f67SGreg Kroah-Hartman 1275b775f67SGreg Kroah-Hartman /* Store pointer in file structure's private data field */ 1285b775f67SGreg Kroah-Hartman filp->private_data = data; 1295b775f67SGreg Kroah-Hartman 1305b775f67SGreg Kroah-Hartman exit: 1315b775f67SGreg Kroah-Hartman return retval; 1325b775f67SGreg Kroah-Hartman } 1335b775f67SGreg Kroah-Hartman 1345b775f67SGreg Kroah-Hartman static int usbtmc_release(struct inode *inode, struct file *file) 1355b775f67SGreg Kroah-Hartman { 1365b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = file->private_data; 1375b775f67SGreg Kroah-Hartman 1385b775f67SGreg Kroah-Hartman kref_put(&data->kref, usbtmc_delete); 1395b775f67SGreg Kroah-Hartman return 0; 1405b775f67SGreg Kroah-Hartman } 1415b775f67SGreg Kroah-Hartman 1425b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) 1435b775f67SGreg Kroah-Hartman { 144b361a6e3SChris Malley u8 *buffer; 1455b775f67SGreg Kroah-Hartman struct device *dev; 1465b775f67SGreg Kroah-Hartman int rv; 1475b775f67SGreg Kroah-Hartman int n; 1485b775f67SGreg Kroah-Hartman int actual; 1495b775f67SGreg Kroah-Hartman struct usb_host_interface *current_setting; 1505b775f67SGreg Kroah-Hartman int max_size; 1515b775f67SGreg Kroah-Hartman 1525b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 1535b775f67SGreg Kroah-Hartman buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); 1545b775f67SGreg Kroah-Hartman if (!buffer) 1555b775f67SGreg Kroah-Hartman return -ENOMEM; 1565b775f67SGreg Kroah-Hartman 1575b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 1585b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 1595b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, 1605b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 1615b775f67SGreg Kroah-Hartman data->bTag_last_read, data->bulk_in, 1625b775f67SGreg Kroah-Hartman buffer, 2, USBTMC_TIMEOUT); 1635b775f67SGreg Kroah-Hartman 1645b775f67SGreg Kroah-Hartman if (rv < 0) { 1655b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 1665b775f67SGreg Kroah-Hartman goto exit; 1675b775f67SGreg Kroah-Hartman } 1685b775f67SGreg Kroah-Hartman 1695b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); 1705b775f67SGreg Kroah-Hartman 1715b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_FAILED) { 1725b775f67SGreg Kroah-Hartman rv = 0; 1735b775f67SGreg Kroah-Hartman goto exit; 1745b775f67SGreg Kroah-Hartman } 1755b775f67SGreg Kroah-Hartman 1765b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 1775b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", 1785b775f67SGreg Kroah-Hartman buffer[0]); 1795b775f67SGreg Kroah-Hartman rv = -EPERM; 1805b775f67SGreg Kroah-Hartman goto exit; 1815b775f67SGreg Kroah-Hartman } 1825b775f67SGreg Kroah-Hartman 1835b775f67SGreg Kroah-Hartman max_size = 0; 1845b775f67SGreg Kroah-Hartman current_setting = data->intf->cur_altsetting; 1855b775f67SGreg Kroah-Hartman for (n = 0; n < current_setting->desc.bNumEndpoints; n++) 1865b775f67SGreg Kroah-Hartman if (current_setting->endpoint[n].desc.bEndpointAddress == 1875b775f67SGreg Kroah-Hartman data->bulk_in) 1885b775f67SGreg Kroah-Hartman max_size = le16_to_cpu(current_setting->endpoint[n]. 1895b775f67SGreg Kroah-Hartman desc.wMaxPacketSize); 1905b775f67SGreg Kroah-Hartman 1915b775f67SGreg Kroah-Hartman if (max_size == 0) { 1925b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't get wMaxPacketSize\n"); 1935b775f67SGreg Kroah-Hartman rv = -EPERM; 1945b775f67SGreg Kroah-Hartman goto exit; 1955b775f67SGreg Kroah-Hartman } 1965b775f67SGreg Kroah-Hartman 1975b775f67SGreg Kroah-Hartman dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size); 1985b775f67SGreg Kroah-Hartman 1995b775f67SGreg Kroah-Hartman n = 0; 2005b775f67SGreg Kroah-Hartman 2015b775f67SGreg Kroah-Hartman do { 2025b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 2035b775f67SGreg Kroah-Hartman 2045b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 2055b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 2065b775f67SGreg Kroah-Hartman data->bulk_in), 2075b775f67SGreg Kroah-Hartman buffer, USBTMC_SIZE_IOBUFFER, 2085b775f67SGreg Kroah-Hartman &actual, USBTMC_TIMEOUT); 2095b775f67SGreg Kroah-Hartman 2105b775f67SGreg Kroah-Hartman n++; 2115b775f67SGreg Kroah-Hartman 2125b775f67SGreg Kroah-Hartman if (rv < 0) { 2135b775f67SGreg Kroah-Hartman dev_err(dev, "usb_bulk_msg returned %d\n", rv); 2145b775f67SGreg Kroah-Hartman goto exit; 2155b775f67SGreg Kroah-Hartman } 2165b775f67SGreg Kroah-Hartman } while ((actual == max_size) && 2175b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); 2185b775f67SGreg Kroah-Hartman 2195b775f67SGreg Kroah-Hartman if (actual == max_size) { 2205b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 2215b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 2225b775f67SGreg Kroah-Hartman rv = -EPERM; 2235b775f67SGreg Kroah-Hartman goto exit; 2245b775f67SGreg Kroah-Hartman } 2255b775f67SGreg Kroah-Hartman 2265b775f67SGreg Kroah-Hartman n = 0; 2275b775f67SGreg Kroah-Hartman 2285b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_in_status: 2295b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 2305b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 2315b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, 2325b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 2335b775f67SGreg Kroah-Hartman 0, data->bulk_in, buffer, 0x08, 2345b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 2355b775f67SGreg Kroah-Hartman 2365b775f67SGreg Kroah-Hartman if (rv < 0) { 2375b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 2385b775f67SGreg Kroah-Hartman goto exit; 2395b775f67SGreg Kroah-Hartman } 2405b775f67SGreg Kroah-Hartman 2415b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); 2425b775f67SGreg Kroah-Hartman 2435b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) { 2445b775f67SGreg Kroah-Hartman rv = 0; 2455b775f67SGreg Kroah-Hartman goto exit; 2465b775f67SGreg Kroah-Hartman } 2475b775f67SGreg Kroah-Hartman 2485b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_PENDING) { 2495b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); 2505b775f67SGreg Kroah-Hartman rv = -EPERM; 2515b775f67SGreg Kroah-Hartman goto exit; 2525b775f67SGreg Kroah-Hartman } 2535b775f67SGreg Kroah-Hartman 2545b775f67SGreg Kroah-Hartman if (buffer[1] == 1) 2555b775f67SGreg Kroah-Hartman do { 2565b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 2575b775f67SGreg Kroah-Hartman 2585b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 2595b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 2605b775f67SGreg Kroah-Hartman data->bulk_in), 2615b775f67SGreg Kroah-Hartman buffer, USBTMC_SIZE_IOBUFFER, 2625b775f67SGreg Kroah-Hartman &actual, USBTMC_TIMEOUT); 2635b775f67SGreg Kroah-Hartman 2645b775f67SGreg Kroah-Hartman n++; 2655b775f67SGreg Kroah-Hartman 2665b775f67SGreg Kroah-Hartman if (rv < 0) { 2675b775f67SGreg Kroah-Hartman dev_err(dev, "usb_bulk_msg returned %d\n", rv); 2685b775f67SGreg Kroah-Hartman goto exit; 2695b775f67SGreg Kroah-Hartman } 2705b775f67SGreg Kroah-Hartman } while ((actual = max_size) && 2715b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); 2725b775f67SGreg Kroah-Hartman 2735b775f67SGreg Kroah-Hartman if (actual == max_size) { 2745b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 2755b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 2765b775f67SGreg Kroah-Hartman rv = -EPERM; 2775b775f67SGreg Kroah-Hartman goto exit; 2785b775f67SGreg Kroah-Hartman } 2795b775f67SGreg Kroah-Hartman 2805b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_in_status; 2815b775f67SGreg Kroah-Hartman 2825b775f67SGreg Kroah-Hartman exit: 2835b775f67SGreg Kroah-Hartman kfree(buffer); 2845b775f67SGreg Kroah-Hartman return rv; 2855b775f67SGreg Kroah-Hartman 2865b775f67SGreg Kroah-Hartman } 2875b775f67SGreg Kroah-Hartman 2885b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) 2895b775f67SGreg Kroah-Hartman { 2905b775f67SGreg Kroah-Hartman struct device *dev; 2915b775f67SGreg Kroah-Hartman u8 *buffer; 2925b775f67SGreg Kroah-Hartman int rv; 2935b775f67SGreg Kroah-Hartman int n; 2945b775f67SGreg Kroah-Hartman 2955b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 2965b775f67SGreg Kroah-Hartman 2975b775f67SGreg Kroah-Hartman buffer = kmalloc(8, GFP_KERNEL); 2985b775f67SGreg Kroah-Hartman if (!buffer) 2995b775f67SGreg Kroah-Hartman return -ENOMEM; 3005b775f67SGreg Kroah-Hartman 3015b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 3025b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 3035b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, 3045b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 3055b775f67SGreg Kroah-Hartman data->bTag_last_write, data->bulk_out, 3065b775f67SGreg Kroah-Hartman buffer, 2, USBTMC_TIMEOUT); 3075b775f67SGreg Kroah-Hartman 3085b775f67SGreg Kroah-Hartman if (rv < 0) { 3095b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 3105b775f67SGreg Kroah-Hartman goto exit; 3115b775f67SGreg Kroah-Hartman } 3125b775f67SGreg Kroah-Hartman 3135b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", buffer[0]); 3145b775f67SGreg Kroah-Hartman 3155b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 3165b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", 3175b775f67SGreg Kroah-Hartman buffer[0]); 3185b775f67SGreg Kroah-Hartman rv = -EPERM; 3195b775f67SGreg Kroah-Hartman goto exit; 3205b775f67SGreg Kroah-Hartman } 3215b775f67SGreg Kroah-Hartman 3225b775f67SGreg Kroah-Hartman n = 0; 3235b775f67SGreg Kroah-Hartman 3245b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_check_status: 3255b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 3265b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 3275b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, 3285b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 3295b775f67SGreg Kroah-Hartman 0, data->bulk_out, buffer, 0x08, 3305b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 3315b775f67SGreg Kroah-Hartman n++; 3325b775f67SGreg Kroah-Hartman if (rv < 0) { 3335b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 3345b775f67SGreg Kroah-Hartman goto exit; 3355b775f67SGreg Kroah-Hartman } 3365b775f67SGreg Kroah-Hartman 3375b775f67SGreg Kroah-Hartman dev_dbg(dev, "CHECK_ABORT_BULK_OUT returned %x\n", buffer[0]); 3385b775f67SGreg Kroah-Hartman 3395b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) 3405b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_out_clear_halt; 3415b775f67SGreg Kroah-Hartman 3425b775f67SGreg Kroah-Hartman if ((buffer[0] == USBTMC_STATUS_PENDING) && 3435b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)) 3445b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_out_check_status; 3455b775f67SGreg Kroah-Hartman 3465b775f67SGreg Kroah-Hartman rv = -EPERM; 3475b775f67SGreg Kroah-Hartman goto exit; 3485b775f67SGreg Kroah-Hartman 3495b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_clear_halt: 3505b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 3515b775f67SGreg Kroah-Hartman usb_sndctrlpipe(data->usb_dev, 0), 3525b775f67SGreg Kroah-Hartman USB_REQ_CLEAR_FEATURE, 3535b775f67SGreg Kroah-Hartman USB_DIR_OUT | USB_TYPE_STANDARD | 3545b775f67SGreg Kroah-Hartman USB_RECIP_ENDPOINT, 3555b775f67SGreg Kroah-Hartman USB_ENDPOINT_HALT, data->bulk_out, buffer, 3565b775f67SGreg Kroah-Hartman 0, USBTMC_TIMEOUT); 3575b775f67SGreg Kroah-Hartman 3585b775f67SGreg Kroah-Hartman if (rv < 0) { 3595b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 3605b775f67SGreg Kroah-Hartman goto exit; 3615b775f67SGreg Kroah-Hartman } 3625b775f67SGreg Kroah-Hartman rv = 0; 3635b775f67SGreg Kroah-Hartman 3645b775f67SGreg Kroah-Hartman exit: 3655b775f67SGreg Kroah-Hartman kfree(buffer); 3665b775f67SGreg Kroah-Hartman return rv; 3675b775f67SGreg Kroah-Hartman } 3685b775f67SGreg Kroah-Hartman 3695b775f67SGreg Kroah-Hartman static ssize_t usbtmc_read(struct file *filp, char __user *buf, 3705b775f67SGreg Kroah-Hartman size_t count, loff_t *f_pos) 3715b775f67SGreg Kroah-Hartman { 3725b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 3735b775f67SGreg Kroah-Hartman struct device *dev; 374665d7662SGuus Sliepen u32 n_characters; 3755b775f67SGreg Kroah-Hartman u8 *buffer; 3765b775f67SGreg Kroah-Hartman int actual; 377665d7662SGuus Sliepen size_t done; 378665d7662SGuus Sliepen size_t remaining; 3795b775f67SGreg Kroah-Hartman int retval; 380665d7662SGuus Sliepen size_t this_part; 3815b775f67SGreg Kroah-Hartman 3825b775f67SGreg Kroah-Hartman /* Get pointer to private data structure */ 3835b775f67SGreg Kroah-Hartman data = filp->private_data; 3845b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 3855b775f67SGreg Kroah-Hartman 3865b775f67SGreg Kroah-Hartman buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); 3875b775f67SGreg Kroah-Hartman if (!buffer) 3885b775f67SGreg Kroah-Hartman return -ENOMEM; 3895b775f67SGreg Kroah-Hartman 3905b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 39186286883SOliver Neukum if (data->zombie) { 39286286883SOliver Neukum retval = -ENODEV; 39386286883SOliver Neukum goto exit; 39486286883SOliver Neukum } 3955b775f67SGreg Kroah-Hartman 3965b775f67SGreg Kroah-Hartman remaining = count; 3975b775f67SGreg Kroah-Hartman done = 0; 3985b775f67SGreg Kroah-Hartman 3995b775f67SGreg Kroah-Hartman while (remaining > 0) { 4005b775f67SGreg Kroah-Hartman if (remaining > USBTMC_SIZE_IOBUFFER - 12 - 3) 4015b775f67SGreg Kroah-Hartman this_part = USBTMC_SIZE_IOBUFFER - 12 - 3; 4025b775f67SGreg Kroah-Hartman else 4035b775f67SGreg Kroah-Hartman this_part = remaining; 4045b775f67SGreg Kroah-Hartman 4055b775f67SGreg Kroah-Hartman /* Setup IO buffer for DEV_DEP_MSG_IN message 4065b775f67SGreg Kroah-Hartman * Refer to class specs for details 4075b775f67SGreg Kroah-Hartman */ 4085b775f67SGreg Kroah-Hartman buffer[0] = 2; 4095b775f67SGreg Kroah-Hartman buffer[1] = data->bTag; 4105b775f67SGreg Kroah-Hartman buffer[2] = ~(data->bTag); 4115b775f67SGreg Kroah-Hartman buffer[3] = 0; /* Reserved */ 412c2cd26e1SSteve Holland buffer[4] = (this_part) & 255; 413c2cd26e1SSteve Holland buffer[5] = ((this_part) >> 8) & 255; 414c2cd26e1SSteve Holland buffer[6] = ((this_part) >> 16) & 255; 415c2cd26e1SSteve Holland buffer[7] = ((this_part) >> 24) & 255; 4165b775f67SGreg Kroah-Hartman buffer[8] = data->TermCharEnabled * 2; 4175b775f67SGreg Kroah-Hartman /* Use term character? */ 4185b775f67SGreg Kroah-Hartman buffer[9] = data->TermChar; 4195b775f67SGreg Kroah-Hartman buffer[10] = 0; /* Reserved */ 4205b775f67SGreg Kroah-Hartman buffer[11] = 0; /* Reserved */ 4215b775f67SGreg Kroah-Hartman 4225b775f67SGreg Kroah-Hartman /* Send bulk URB */ 4235b775f67SGreg Kroah-Hartman retval = usb_bulk_msg(data->usb_dev, 4245b775f67SGreg Kroah-Hartman usb_sndbulkpipe(data->usb_dev, 4255b775f67SGreg Kroah-Hartman data->bulk_out), 4265b775f67SGreg Kroah-Hartman buffer, 12, &actual, USBTMC_TIMEOUT); 4275b775f67SGreg Kroah-Hartman 4285b775f67SGreg Kroah-Hartman /* Store bTag (in case we need to abort) */ 4295b775f67SGreg Kroah-Hartman data->bTag_last_write = data->bTag; 4305b775f67SGreg Kroah-Hartman 4315b775f67SGreg Kroah-Hartman /* Increment bTag -- and increment again if zero */ 4325b775f67SGreg Kroah-Hartman data->bTag++; 4335b775f67SGreg Kroah-Hartman if (!data->bTag) 4345b775f67SGreg Kroah-Hartman (data->bTag)++; 4355b775f67SGreg Kroah-Hartman 4365b775f67SGreg Kroah-Hartman if (retval < 0) { 4375b775f67SGreg Kroah-Hartman dev_err(dev, "usb_bulk_msg returned %d\n", retval); 4385b775f67SGreg Kroah-Hartman if (data->auto_abort) 4395b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_out(data); 4405b775f67SGreg Kroah-Hartman goto exit; 4415b775f67SGreg Kroah-Hartman } 4425b775f67SGreg Kroah-Hartman 4435b775f67SGreg Kroah-Hartman /* Send bulk URB */ 4445b775f67SGreg Kroah-Hartman retval = usb_bulk_msg(data->usb_dev, 4455b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 4465b775f67SGreg Kroah-Hartman data->bulk_in), 4475b775f67SGreg Kroah-Hartman buffer, USBTMC_SIZE_IOBUFFER, &actual, 4485b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 4495b775f67SGreg Kroah-Hartman 4505b775f67SGreg Kroah-Hartman /* Store bTag (in case we need to abort) */ 4515b775f67SGreg Kroah-Hartman data->bTag_last_read = data->bTag; 4525b775f67SGreg Kroah-Hartman 4535b775f67SGreg Kroah-Hartman if (retval < 0) { 4545b775f67SGreg Kroah-Hartman dev_err(dev, "Unable to read data, error %d\n", retval); 4555b775f67SGreg Kroah-Hartman if (data->auto_abort) 4565b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_in(data); 4575b775f67SGreg Kroah-Hartman goto exit; 4585b775f67SGreg Kroah-Hartman } 4595b775f67SGreg Kroah-Hartman 4605b775f67SGreg Kroah-Hartman /* How many characters did the instrument send? */ 4615b775f67SGreg Kroah-Hartman n_characters = buffer[4] + 4625b775f67SGreg Kroah-Hartman (buffer[5] << 8) + 4635b775f67SGreg Kroah-Hartman (buffer[6] << 16) + 4645b775f67SGreg Kroah-Hartman (buffer[7] << 24); 4655b775f67SGreg Kroah-Hartman 466665d7662SGuus Sliepen /* Ensure the instrument doesn't lie about it */ 467665d7662SGuus Sliepen if(n_characters > actual - 12) { 468a2fbf10eSRandy Dunlap dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12); 469665d7662SGuus Sliepen n_characters = actual - 12; 470665d7662SGuus Sliepen } 471665d7662SGuus Sliepen 472665d7662SGuus Sliepen /* Ensure the instrument doesn't send more back than requested */ 473665d7662SGuus Sliepen if(n_characters > this_part) { 474665d7662SGuus Sliepen dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part); 475665d7662SGuus Sliepen n_characters = this_part; 476665d7662SGuus Sliepen } 477665d7662SGuus Sliepen 47892d07e42SSteve Holland /* Bound amount of data received by amount of data requested */ 47992d07e42SSteve Holland if (n_characters > this_part) 48092d07e42SSteve Holland n_characters = this_part; 48192d07e42SSteve Holland 4825b775f67SGreg Kroah-Hartman /* Copy buffer to user space */ 4835b775f67SGreg Kroah-Hartman if (copy_to_user(buf + done, &buffer[12], n_characters)) { 4845b775f67SGreg Kroah-Hartman /* There must have been an addressing problem */ 4855b775f67SGreg Kroah-Hartman retval = -EFAULT; 4865b775f67SGreg Kroah-Hartman goto exit; 4875b775f67SGreg Kroah-Hartman } 4885b775f67SGreg Kroah-Hartman 4895b775f67SGreg Kroah-Hartman done += n_characters; 4904143d178SSteve Holland /* Terminate if end-of-message bit recieved from device */ 4914143d178SSteve Holland if ((buffer[8] & 0x01) && (actual >= n_characters + 12)) 4925b775f67SGreg Kroah-Hartman remaining = 0; 493665d7662SGuus Sliepen else 494665d7662SGuus Sliepen remaining -= n_characters; 4955b775f67SGreg Kroah-Hartman } 4965b775f67SGreg Kroah-Hartman 4975b775f67SGreg Kroah-Hartman /* Update file position value */ 4985b775f67SGreg Kroah-Hartman *f_pos = *f_pos + done; 4995b775f67SGreg Kroah-Hartman retval = done; 5005b775f67SGreg Kroah-Hartman 5015b775f67SGreg Kroah-Hartman exit: 5025b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 5035b775f67SGreg Kroah-Hartman kfree(buffer); 5045b775f67SGreg Kroah-Hartman return retval; 5055b775f67SGreg Kroah-Hartman } 5065b775f67SGreg Kroah-Hartman 5075b775f67SGreg Kroah-Hartman static ssize_t usbtmc_write(struct file *filp, const char __user *buf, 5085b775f67SGreg Kroah-Hartman size_t count, loff_t *f_pos) 5095b775f67SGreg Kroah-Hartman { 5105b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 5115b775f67SGreg Kroah-Hartman u8 *buffer; 5125b775f67SGreg Kroah-Hartman int retval; 5135b775f67SGreg Kroah-Hartman int actual; 5145b775f67SGreg Kroah-Hartman unsigned long int n_bytes; 5155b775f67SGreg Kroah-Hartman int remaining; 5165b775f67SGreg Kroah-Hartman int done; 5175b775f67SGreg Kroah-Hartman int this_part; 5185b775f67SGreg Kroah-Hartman 5195b775f67SGreg Kroah-Hartman data = filp->private_data; 5205b775f67SGreg Kroah-Hartman 5215b775f67SGreg Kroah-Hartman buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); 5225b775f67SGreg Kroah-Hartman if (!buffer) 5235b775f67SGreg Kroah-Hartman return -ENOMEM; 5245b775f67SGreg Kroah-Hartman 5255b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 52686286883SOliver Neukum if (data->zombie) { 52786286883SOliver Neukum retval = -ENODEV; 52886286883SOliver Neukum goto exit; 52986286883SOliver Neukum } 5305b775f67SGreg Kroah-Hartman 5315b775f67SGreg Kroah-Hartman remaining = count; 5325b775f67SGreg Kroah-Hartman done = 0; 5335b775f67SGreg Kroah-Hartman 5345b775f67SGreg Kroah-Hartman while (remaining > 0) { 5355b775f67SGreg Kroah-Hartman if (remaining > USBTMC_SIZE_IOBUFFER - 12) { 5365b775f67SGreg Kroah-Hartman this_part = USBTMC_SIZE_IOBUFFER - 12; 5375b775f67SGreg Kroah-Hartman buffer[8] = 0; 5385b775f67SGreg Kroah-Hartman } else { 5395b775f67SGreg Kroah-Hartman this_part = remaining; 5405b775f67SGreg Kroah-Hartman buffer[8] = 1; 5415b775f67SGreg Kroah-Hartman } 5425b775f67SGreg Kroah-Hartman 5435b775f67SGreg Kroah-Hartman /* Setup IO buffer for DEV_DEP_MSG_OUT message */ 5445b775f67SGreg Kroah-Hartman buffer[0] = 1; 5455b775f67SGreg Kroah-Hartman buffer[1] = data->bTag; 5465b775f67SGreg Kroah-Hartman buffer[2] = ~(data->bTag); 5475b775f67SGreg Kroah-Hartman buffer[3] = 0; /* Reserved */ 5485b775f67SGreg Kroah-Hartman buffer[4] = this_part & 255; 5495b775f67SGreg Kroah-Hartman buffer[5] = (this_part >> 8) & 255; 5505b775f67SGreg Kroah-Hartman buffer[6] = (this_part >> 16) & 255; 5515b775f67SGreg Kroah-Hartman buffer[7] = (this_part >> 24) & 255; 5525b775f67SGreg Kroah-Hartman /* buffer[8] is set above... */ 5535b775f67SGreg Kroah-Hartman buffer[9] = 0; /* Reserved */ 5545b775f67SGreg Kroah-Hartman buffer[10] = 0; /* Reserved */ 5555b775f67SGreg Kroah-Hartman buffer[11] = 0; /* Reserved */ 5565b775f67SGreg Kroah-Hartman 5575b775f67SGreg Kroah-Hartman if (copy_from_user(&buffer[12], buf + done, this_part)) { 5585b775f67SGreg Kroah-Hartman retval = -EFAULT; 5595b775f67SGreg Kroah-Hartman goto exit; 5605b775f67SGreg Kroah-Hartman } 5615b775f67SGreg Kroah-Hartman 562857cc4dfSIlpo Järvinen n_bytes = roundup(12 + this_part, 4); 563857cc4dfSIlpo Järvinen memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part)); 5645b775f67SGreg Kroah-Hartman 5655b775f67SGreg Kroah-Hartman retval = usb_bulk_msg(data->usb_dev, 5665b775f67SGreg Kroah-Hartman usb_sndbulkpipe(data->usb_dev, 5675b775f67SGreg Kroah-Hartman data->bulk_out), 5685b775f67SGreg Kroah-Hartman buffer, n_bytes, &actual, USBTMC_TIMEOUT); 5695b775f67SGreg Kroah-Hartman 5705b775f67SGreg Kroah-Hartman data->bTag_last_write = data->bTag; 5715b775f67SGreg Kroah-Hartman data->bTag++; 5725b775f67SGreg Kroah-Hartman 5735b775f67SGreg Kroah-Hartman if (!data->bTag) 5745b775f67SGreg Kroah-Hartman data->bTag++; 5755b775f67SGreg Kroah-Hartman 5765b775f67SGreg Kroah-Hartman if (retval < 0) { 5775b775f67SGreg Kroah-Hartman dev_err(&data->intf->dev, 5785b775f67SGreg Kroah-Hartman "Unable to send data, error %d\n", retval); 5795b775f67SGreg Kroah-Hartman if (data->auto_abort) 5805b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_out(data); 5815b775f67SGreg Kroah-Hartman goto exit; 5825b775f67SGreg Kroah-Hartman } 5835b775f67SGreg Kroah-Hartman 5845b775f67SGreg Kroah-Hartman remaining -= this_part; 5855b775f67SGreg Kroah-Hartman done += this_part; 5865b775f67SGreg Kroah-Hartman } 5875b775f67SGreg Kroah-Hartman 5885b775f67SGreg Kroah-Hartman retval = count; 5895b775f67SGreg Kroah-Hartman exit: 5905b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 5915b775f67SGreg Kroah-Hartman kfree(buffer); 5925b775f67SGreg Kroah-Hartman return retval; 5935b775f67SGreg Kroah-Hartman } 5945b775f67SGreg Kroah-Hartman 5955b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) 5965b775f67SGreg Kroah-Hartman { 5975b775f67SGreg Kroah-Hartman struct usb_host_interface *current_setting; 5985b775f67SGreg Kroah-Hartman struct usb_endpoint_descriptor *desc; 5995b775f67SGreg Kroah-Hartman struct device *dev; 6005b775f67SGreg Kroah-Hartman u8 *buffer; 6015b775f67SGreg Kroah-Hartman int rv; 6025b775f67SGreg Kroah-Hartman int n; 6035b775f67SGreg Kroah-Hartman int actual; 6045b775f67SGreg Kroah-Hartman int max_size; 6055b775f67SGreg Kroah-Hartman 6065b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 6075b775f67SGreg Kroah-Hartman 6085b775f67SGreg Kroah-Hartman dev_dbg(dev, "Sending INITIATE_CLEAR request\n"); 6095b775f67SGreg Kroah-Hartman 6105b775f67SGreg Kroah-Hartman buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); 6115b775f67SGreg Kroah-Hartman if (!buffer) 6125b775f67SGreg Kroah-Hartman return -ENOMEM; 6135b775f67SGreg Kroah-Hartman 6145b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 6155b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 6165b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_CLEAR, 6175b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 6185b775f67SGreg Kroah-Hartman 0, 0, buffer, 1, USBTMC_TIMEOUT); 6195b775f67SGreg Kroah-Hartman if (rv < 0) { 6205b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 6215b775f67SGreg Kroah-Hartman goto exit; 6225b775f67SGreg Kroah-Hartman } 6235b775f67SGreg Kroah-Hartman 6245b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); 6255b775f67SGreg Kroah-Hartman 6265b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 6275b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); 6285b775f67SGreg Kroah-Hartman rv = -EPERM; 6295b775f67SGreg Kroah-Hartman goto exit; 6305b775f67SGreg Kroah-Hartman } 6315b775f67SGreg Kroah-Hartman 6325b775f67SGreg Kroah-Hartman max_size = 0; 6335b775f67SGreg Kroah-Hartman current_setting = data->intf->cur_altsetting; 6345b775f67SGreg Kroah-Hartman for (n = 0; n < current_setting->desc.bNumEndpoints; n++) { 6355b775f67SGreg Kroah-Hartman desc = ¤t_setting->endpoint[n].desc; 6365b775f67SGreg Kroah-Hartman if (desc->bEndpointAddress == data->bulk_in) 6375b775f67SGreg Kroah-Hartman max_size = le16_to_cpu(desc->wMaxPacketSize); 6385b775f67SGreg Kroah-Hartman } 6395b775f67SGreg Kroah-Hartman 6405b775f67SGreg Kroah-Hartman if (max_size == 0) { 6415b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't get wMaxPacketSize\n"); 6425b775f67SGreg Kroah-Hartman rv = -EPERM; 6435b775f67SGreg Kroah-Hartman goto exit; 6445b775f67SGreg Kroah-Hartman } 6455b775f67SGreg Kroah-Hartman 6465b775f67SGreg Kroah-Hartman dev_dbg(dev, "wMaxPacketSize is %d\n", max_size); 6475b775f67SGreg Kroah-Hartman 6485b775f67SGreg Kroah-Hartman n = 0; 6495b775f67SGreg Kroah-Hartman 6505b775f67SGreg Kroah-Hartman usbtmc_clear_check_status: 6515b775f67SGreg Kroah-Hartman 6525b775f67SGreg Kroah-Hartman dev_dbg(dev, "Sending CHECK_CLEAR_STATUS request\n"); 6535b775f67SGreg Kroah-Hartman 6545b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 6555b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 6565b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_CLEAR_STATUS, 6575b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 6585b775f67SGreg Kroah-Hartman 0, 0, buffer, 2, USBTMC_TIMEOUT); 6595b775f67SGreg Kroah-Hartman if (rv < 0) { 6605b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 6615b775f67SGreg Kroah-Hartman goto exit; 6625b775f67SGreg Kroah-Hartman } 6635b775f67SGreg Kroah-Hartman 6645b775f67SGreg Kroah-Hartman dev_dbg(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); 6655b775f67SGreg Kroah-Hartman 6665b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) 6675b775f67SGreg Kroah-Hartman goto usbtmc_clear_bulk_out_halt; 6685b775f67SGreg Kroah-Hartman 6695b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_PENDING) { 6705b775f67SGreg Kroah-Hartman dev_err(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); 6715b775f67SGreg Kroah-Hartman rv = -EPERM; 6725b775f67SGreg Kroah-Hartman goto exit; 6735b775f67SGreg Kroah-Hartman } 6745b775f67SGreg Kroah-Hartman 6755b775f67SGreg Kroah-Hartman if (buffer[1] == 1) 6765b775f67SGreg Kroah-Hartman do { 6775b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 6785b775f67SGreg Kroah-Hartman 6795b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 6805b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 6815b775f67SGreg Kroah-Hartman data->bulk_in), 6825b775f67SGreg Kroah-Hartman buffer, USBTMC_SIZE_IOBUFFER, 6835b775f67SGreg Kroah-Hartman &actual, USBTMC_TIMEOUT); 6845b775f67SGreg Kroah-Hartman n++; 6855b775f67SGreg Kroah-Hartman 6865b775f67SGreg Kroah-Hartman if (rv < 0) { 6875b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", 6885b775f67SGreg Kroah-Hartman rv); 6895b775f67SGreg Kroah-Hartman goto exit; 6905b775f67SGreg Kroah-Hartman } 6915b775f67SGreg Kroah-Hartman } while ((actual == max_size) && 6925b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); 6935b775f67SGreg Kroah-Hartman 6945b775f67SGreg Kroah-Hartman if (actual == max_size) { 6955b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 6965b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 6975b775f67SGreg Kroah-Hartman rv = -EPERM; 6985b775f67SGreg Kroah-Hartman goto exit; 6995b775f67SGreg Kroah-Hartman } 7005b775f67SGreg Kroah-Hartman 7015b775f67SGreg Kroah-Hartman goto usbtmc_clear_check_status; 7025b775f67SGreg Kroah-Hartman 7035b775f67SGreg Kroah-Hartman usbtmc_clear_bulk_out_halt: 7045b775f67SGreg Kroah-Hartman 7055b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 7065b775f67SGreg Kroah-Hartman usb_sndctrlpipe(data->usb_dev, 0), 7075b775f67SGreg Kroah-Hartman USB_REQ_CLEAR_FEATURE, 7085b775f67SGreg Kroah-Hartman USB_DIR_OUT | USB_TYPE_STANDARD | 7095b775f67SGreg Kroah-Hartman USB_RECIP_ENDPOINT, 7105b775f67SGreg Kroah-Hartman USB_ENDPOINT_HALT, 7115b775f67SGreg Kroah-Hartman data->bulk_out, buffer, 0, 7125b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 7135b775f67SGreg Kroah-Hartman if (rv < 0) { 7145b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 7155b775f67SGreg Kroah-Hartman goto exit; 7165b775f67SGreg Kroah-Hartman } 7175b775f67SGreg Kroah-Hartman rv = 0; 7185b775f67SGreg Kroah-Hartman 7195b775f67SGreg Kroah-Hartman exit: 7205b775f67SGreg Kroah-Hartman kfree(buffer); 7215b775f67SGreg Kroah-Hartman return rv; 7225b775f67SGreg Kroah-Hartman } 7235b775f67SGreg Kroah-Hartman 7245b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data) 7255b775f67SGreg Kroah-Hartman { 7265b775f67SGreg Kroah-Hartman u8 *buffer; 7275b775f67SGreg Kroah-Hartman int rv; 7285b775f67SGreg Kroah-Hartman 7295b775f67SGreg Kroah-Hartman buffer = kmalloc(2, GFP_KERNEL); 7305b775f67SGreg Kroah-Hartman if (!buffer) 7315b775f67SGreg Kroah-Hartman return -ENOMEM; 7325b775f67SGreg Kroah-Hartman 7335b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 7345b775f67SGreg Kroah-Hartman usb_sndctrlpipe(data->usb_dev, 0), 7355b775f67SGreg Kroah-Hartman USB_REQ_CLEAR_FEATURE, 7365b775f67SGreg Kroah-Hartman USB_DIR_OUT | USB_TYPE_STANDARD | 7375b775f67SGreg Kroah-Hartman USB_RECIP_ENDPOINT, 7385b775f67SGreg Kroah-Hartman USB_ENDPOINT_HALT, data->bulk_out, 7395b775f67SGreg Kroah-Hartman buffer, 0, USBTMC_TIMEOUT); 7405b775f67SGreg Kroah-Hartman 7415b775f67SGreg Kroah-Hartman if (rv < 0) { 7425b775f67SGreg Kroah-Hartman dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", 7435b775f67SGreg Kroah-Hartman rv); 7445b775f67SGreg Kroah-Hartman goto exit; 7455b775f67SGreg Kroah-Hartman } 7465b775f67SGreg Kroah-Hartman rv = 0; 7475b775f67SGreg Kroah-Hartman 7485b775f67SGreg Kroah-Hartman exit: 7495b775f67SGreg Kroah-Hartman kfree(buffer); 7505b775f67SGreg Kroah-Hartman return rv; 7515b775f67SGreg Kroah-Hartman } 7525b775f67SGreg Kroah-Hartman 7535b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) 7545b775f67SGreg Kroah-Hartman { 7555b775f67SGreg Kroah-Hartman u8 *buffer; 7565b775f67SGreg Kroah-Hartman int rv; 7575b775f67SGreg Kroah-Hartman 7585b775f67SGreg Kroah-Hartman buffer = kmalloc(2, GFP_KERNEL); 7595b775f67SGreg Kroah-Hartman if (!buffer) 7605b775f67SGreg Kroah-Hartman return -ENOMEM; 7615b775f67SGreg Kroah-Hartman 7625b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, usb_sndctrlpipe(data->usb_dev, 0), 7635b775f67SGreg Kroah-Hartman USB_REQ_CLEAR_FEATURE, 7645b775f67SGreg Kroah-Hartman USB_DIR_OUT | USB_TYPE_STANDARD | 7655b775f67SGreg Kroah-Hartman USB_RECIP_ENDPOINT, 7665b775f67SGreg Kroah-Hartman USB_ENDPOINT_HALT, data->bulk_in, buffer, 0, 7675b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 7685b775f67SGreg Kroah-Hartman 7695b775f67SGreg Kroah-Hartman if (rv < 0) { 7705b775f67SGreg Kroah-Hartman dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", 7715b775f67SGreg Kroah-Hartman rv); 7725b775f67SGreg Kroah-Hartman goto exit; 7735b775f67SGreg Kroah-Hartman } 7745b775f67SGreg Kroah-Hartman rv = 0; 7755b775f67SGreg Kroah-Hartman 7765b775f67SGreg Kroah-Hartman exit: 7775b775f67SGreg Kroah-Hartman kfree(buffer); 7785b775f67SGreg Kroah-Hartman return rv; 7795b775f67SGreg Kroah-Hartman } 7805b775f67SGreg Kroah-Hartman 7815b775f67SGreg Kroah-Hartman static int get_capabilities(struct usbtmc_device_data *data) 7825b775f67SGreg Kroah-Hartman { 7835b775f67SGreg Kroah-Hartman struct device *dev = &data->usb_dev->dev; 7845b775f67SGreg Kroah-Hartman char *buffer; 785ca157c4aSOliver Neukum int rv = 0; 7865b775f67SGreg Kroah-Hartman 7875b775f67SGreg Kroah-Hartman buffer = kmalloc(0x18, GFP_KERNEL); 7885b775f67SGreg Kroah-Hartman if (!buffer) 7895b775f67SGreg Kroah-Hartman return -ENOMEM; 7905b775f67SGreg Kroah-Hartman 7915b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), 7925b775f67SGreg Kroah-Hartman USBTMC_REQUEST_GET_CAPABILITIES, 7935b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 7945b775f67SGreg Kroah-Hartman 0, 0, buffer, 0x18, USBTMC_TIMEOUT); 7955b775f67SGreg Kroah-Hartman if (rv < 0) { 7965b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 797ca157c4aSOliver Neukum goto err_out; 7985b775f67SGreg Kroah-Hartman } 7995b775f67SGreg Kroah-Hartman 8005b775f67SGreg Kroah-Hartman dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); 8015b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 8025b775f67SGreg Kroah-Hartman dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); 803ca157c4aSOliver Neukum rv = -EPERM; 804ca157c4aSOliver Neukum goto err_out; 8055b775f67SGreg Kroah-Hartman } 806d0a38365SGergely Imreh dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]); 807d0a38365SGergely Imreh dev_dbg(dev, "Device capabilities are %x\n", buffer[5]); 808d0a38365SGergely Imreh dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]); 809d0a38365SGergely Imreh dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]); 8105b775f67SGreg Kroah-Hartman 8115b775f67SGreg Kroah-Hartman data->capabilities.interface_capabilities = buffer[4]; 8125b775f67SGreg Kroah-Hartman data->capabilities.device_capabilities = buffer[5]; 8135b775f67SGreg Kroah-Hartman data->capabilities.usb488_interface_capabilities = buffer[14]; 8145b775f67SGreg Kroah-Hartman data->capabilities.usb488_device_capabilities = buffer[15]; 815d0a38365SGergely Imreh rv = 0; 8165b775f67SGreg Kroah-Hartman 817ca157c4aSOliver Neukum err_out: 8185b775f67SGreg Kroah-Hartman kfree(buffer); 819ca157c4aSOliver Neukum return rv; 8205b775f67SGreg Kroah-Hartman } 8215b775f67SGreg Kroah-Hartman 8225b775f67SGreg Kroah-Hartman #define capability_attribute(name) \ 8235b775f67SGreg Kroah-Hartman static ssize_t show_##name(struct device *dev, \ 8245b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 8255b775f67SGreg Kroah-Hartman { \ 8265b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 8275b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 8285b775f67SGreg Kroah-Hartman \ 8295b775f67SGreg Kroah-Hartman return sprintf(buf, "%d\n", data->capabilities.name); \ 8305b775f67SGreg Kroah-Hartman } \ 8315b775f67SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) 8325b775f67SGreg Kroah-Hartman 8335b775f67SGreg Kroah-Hartman capability_attribute(interface_capabilities); 8345b775f67SGreg Kroah-Hartman capability_attribute(device_capabilities); 8355b775f67SGreg Kroah-Hartman capability_attribute(usb488_interface_capabilities); 8365b775f67SGreg Kroah-Hartman capability_attribute(usb488_device_capabilities); 8375b775f67SGreg Kroah-Hartman 8385b775f67SGreg Kroah-Hartman static struct attribute *capability_attrs[] = { 8395b775f67SGreg Kroah-Hartman &dev_attr_interface_capabilities.attr, 8405b775f67SGreg Kroah-Hartman &dev_attr_device_capabilities.attr, 8415b775f67SGreg Kroah-Hartman &dev_attr_usb488_interface_capabilities.attr, 8425b775f67SGreg Kroah-Hartman &dev_attr_usb488_device_capabilities.attr, 8435b775f67SGreg Kroah-Hartman NULL, 8445b775f67SGreg Kroah-Hartman }; 8455b775f67SGreg Kroah-Hartman 8465b775f67SGreg Kroah-Hartman static struct attribute_group capability_attr_grp = { 8475b775f67SGreg Kroah-Hartman .attrs = capability_attrs, 8485b775f67SGreg Kroah-Hartman }; 8495b775f67SGreg Kroah-Hartman 8505b775f67SGreg Kroah-Hartman static ssize_t show_TermChar(struct device *dev, 8515b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 8525b775f67SGreg Kroah-Hartman { 8535b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); 8545b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); 8555b775f67SGreg Kroah-Hartman 8565b775f67SGreg Kroah-Hartman return sprintf(buf, "%c\n", data->TermChar); 8575b775f67SGreg Kroah-Hartman } 8585b775f67SGreg Kroah-Hartman 8595b775f67SGreg Kroah-Hartman static ssize_t store_TermChar(struct device *dev, 8605b775f67SGreg Kroah-Hartman struct device_attribute *attr, 8615b775f67SGreg Kroah-Hartman const char *buf, size_t count) 8625b775f67SGreg Kroah-Hartman { 8635b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); 8645b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); 8655b775f67SGreg Kroah-Hartman 8665b775f67SGreg Kroah-Hartman if (count < 1) 8675b775f67SGreg Kroah-Hartman return -EINVAL; 8685b775f67SGreg Kroah-Hartman data->TermChar = buf[0]; 8695b775f67SGreg Kroah-Hartman return count; 8705b775f67SGreg Kroah-Hartman } 8715b775f67SGreg Kroah-Hartman static DEVICE_ATTR(TermChar, S_IRUGO, show_TermChar, store_TermChar); 8725b775f67SGreg Kroah-Hartman 8735b775f67SGreg Kroah-Hartman #define data_attribute(name) \ 8745b775f67SGreg Kroah-Hartman static ssize_t show_##name(struct device *dev, \ 8755b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 8765b775f67SGreg Kroah-Hartman { \ 8775b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 8785b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 8795b775f67SGreg Kroah-Hartman \ 8805b775f67SGreg Kroah-Hartman return sprintf(buf, "%d\n", data->name); \ 8815b775f67SGreg Kroah-Hartman } \ 8825b775f67SGreg Kroah-Hartman static ssize_t store_##name(struct device *dev, \ 8835b775f67SGreg Kroah-Hartman struct device_attribute *attr, \ 8845b775f67SGreg Kroah-Hartman const char *buf, size_t count) \ 8855b775f67SGreg Kroah-Hartman { \ 8865b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 8875b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 8885b775f67SGreg Kroah-Hartman ssize_t result; \ 8895b775f67SGreg Kroah-Hartman unsigned val; \ 8905b775f67SGreg Kroah-Hartman \ 8915b775f67SGreg Kroah-Hartman result = sscanf(buf, "%u\n", &val); \ 8925b775f67SGreg Kroah-Hartman if (result != 1) \ 8935b775f67SGreg Kroah-Hartman result = -EINVAL; \ 8945b775f67SGreg Kroah-Hartman data->name = val; \ 8955b775f67SGreg Kroah-Hartman if (result < 0) \ 8965b775f67SGreg Kroah-Hartman return result; \ 8975b775f67SGreg Kroah-Hartman else \ 8985b775f67SGreg Kroah-Hartman return count; \ 8995b775f67SGreg Kroah-Hartman } \ 9005b775f67SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_##name, store_##name) 9015b775f67SGreg Kroah-Hartman 9025b775f67SGreg Kroah-Hartman data_attribute(TermCharEnabled); 9035b775f67SGreg Kroah-Hartman data_attribute(auto_abort); 9045b775f67SGreg Kroah-Hartman 9055b775f67SGreg Kroah-Hartman static struct attribute *data_attrs[] = { 9065b775f67SGreg Kroah-Hartman &dev_attr_TermChar.attr, 9075b775f67SGreg Kroah-Hartman &dev_attr_TermCharEnabled.attr, 9085b775f67SGreg Kroah-Hartman &dev_attr_auto_abort.attr, 9095b775f67SGreg Kroah-Hartman NULL, 9105b775f67SGreg Kroah-Hartman }; 9115b775f67SGreg Kroah-Hartman 9125b775f67SGreg Kroah-Hartman static struct attribute_group data_attr_grp = { 9135b775f67SGreg Kroah-Hartman .attrs = data_attrs, 9145b775f67SGreg Kroah-Hartman }; 9155b775f67SGreg Kroah-Hartman 9165b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) 9175b775f67SGreg Kroah-Hartman { 9185b775f67SGreg Kroah-Hartman struct device *dev; 9195b775f67SGreg Kroah-Hartman u8 *buffer; 9205b775f67SGreg Kroah-Hartman int rv; 9215b775f67SGreg Kroah-Hartman 9225b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 9235b775f67SGreg Kroah-Hartman 9245b775f67SGreg Kroah-Hartman buffer = kmalloc(2, GFP_KERNEL); 9255b775f67SGreg Kroah-Hartman if (!buffer) 9265b775f67SGreg Kroah-Hartman return -ENOMEM; 9275b775f67SGreg Kroah-Hartman 9285b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 9295b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 9305b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INDICATOR_PULSE, 9315b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 9325b775f67SGreg Kroah-Hartman 0, 0, buffer, 0x01, USBTMC_TIMEOUT); 9335b775f67SGreg Kroah-Hartman 9345b775f67SGreg Kroah-Hartman if (rv < 0) { 9355b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 9365b775f67SGreg Kroah-Hartman goto exit; 9375b775f67SGreg Kroah-Hartman } 9385b775f67SGreg Kroah-Hartman 9395b775f67SGreg Kroah-Hartman dev_dbg(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); 9405b775f67SGreg Kroah-Hartman 9415b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 9425b775f67SGreg Kroah-Hartman dev_err(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); 9435b775f67SGreg Kroah-Hartman rv = -EPERM; 9445b775f67SGreg Kroah-Hartman goto exit; 9455b775f67SGreg Kroah-Hartman } 9465b775f67SGreg Kroah-Hartman rv = 0; 9475b775f67SGreg Kroah-Hartman 9485b775f67SGreg Kroah-Hartman exit: 9495b775f67SGreg Kroah-Hartman kfree(buffer); 9505b775f67SGreg Kroah-Hartman return rv; 9515b775f67SGreg Kroah-Hartman } 9525b775f67SGreg Kroah-Hartman 9535b775f67SGreg Kroah-Hartman static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 9545b775f67SGreg Kroah-Hartman { 9555b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 9565b775f67SGreg Kroah-Hartman int retval = -EBADRQC; 9575b775f67SGreg Kroah-Hartman 9585b775f67SGreg Kroah-Hartman data = file->private_data; 9595b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 96086286883SOliver Neukum if (data->zombie) { 96186286883SOliver Neukum retval = -ENODEV; 96286286883SOliver Neukum goto skip_io_on_zombie; 96386286883SOliver Neukum } 9645b775f67SGreg Kroah-Hartman 9655b775f67SGreg Kroah-Hartman switch (cmd) { 9665b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR_OUT_HALT: 9675b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear_out_halt(data); 968a92b63e7SGreg Kroah-Hartman break; 9695b775f67SGreg Kroah-Hartman 9705b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR_IN_HALT: 9715b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear_in_halt(data); 972a92b63e7SGreg Kroah-Hartman break; 9735b775f67SGreg Kroah-Hartman 9745b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_INDICATOR_PULSE: 9755b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_indicator_pulse(data); 976a92b63e7SGreg Kroah-Hartman break; 9775b775f67SGreg Kroah-Hartman 9785b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR: 9795b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear(data); 980a92b63e7SGreg Kroah-Hartman break; 9815b775f67SGreg Kroah-Hartman 9825b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_ABORT_BULK_OUT: 9835b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_abort_bulk_out(data); 984a92b63e7SGreg Kroah-Hartman break; 9855b775f67SGreg Kroah-Hartman 9865b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_ABORT_BULK_IN: 9875b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_abort_bulk_in(data); 988a92b63e7SGreg Kroah-Hartman break; 9895b775f67SGreg Kroah-Hartman } 9905b775f67SGreg Kroah-Hartman 99186286883SOliver Neukum skip_io_on_zombie: 9925b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 9935b775f67SGreg Kroah-Hartman return retval; 9945b775f67SGreg Kroah-Hartman } 9955b775f67SGreg Kroah-Hartman 996828c0950SAlexey Dobriyan static const struct file_operations fops = { 9975b775f67SGreg Kroah-Hartman .owner = THIS_MODULE, 9985b775f67SGreg Kroah-Hartman .read = usbtmc_read, 9995b775f67SGreg Kroah-Hartman .write = usbtmc_write, 10005b775f67SGreg Kroah-Hartman .open = usbtmc_open, 10015b775f67SGreg Kroah-Hartman .release = usbtmc_release, 10025b775f67SGreg Kroah-Hartman .unlocked_ioctl = usbtmc_ioctl, 10035b775f67SGreg Kroah-Hartman }; 10045b775f67SGreg Kroah-Hartman 10055b775f67SGreg Kroah-Hartman static struct usb_class_driver usbtmc_class = { 10065b775f67SGreg Kroah-Hartman .name = "usbtmc%d", 10075b775f67SGreg Kroah-Hartman .fops = &fops, 10085b775f67SGreg Kroah-Hartman .minor_base = USBTMC_MINOR_BASE, 10095b775f67SGreg Kroah-Hartman }; 10105b775f67SGreg Kroah-Hartman 10115b775f67SGreg Kroah-Hartman 10125b775f67SGreg Kroah-Hartman static int usbtmc_probe(struct usb_interface *intf, 10135b775f67SGreg Kroah-Hartman const struct usb_device_id *id) 10145b775f67SGreg Kroah-Hartman { 10155b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 10165b775f67SGreg Kroah-Hartman struct usb_host_interface *iface_desc; 10175b775f67SGreg Kroah-Hartman struct usb_endpoint_descriptor *endpoint; 10185b775f67SGreg Kroah-Hartman int n; 10195b775f67SGreg Kroah-Hartman int retcode; 10205b775f67SGreg Kroah-Hartman 10215b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "%s called\n", __func__); 10225b775f67SGreg Kroah-Hartman 10235b775f67SGreg Kroah-Hartman data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL); 10245b775f67SGreg Kroah-Hartman if (!data) { 10255b775f67SGreg Kroah-Hartman dev_err(&intf->dev, "Unable to allocate kernel memory\n"); 10265b775f67SGreg Kroah-Hartman return -ENOMEM; 10275b775f67SGreg Kroah-Hartman } 10285b775f67SGreg Kroah-Hartman 10295b775f67SGreg Kroah-Hartman data->intf = intf; 10305b775f67SGreg Kroah-Hartman data->id = id; 10315b775f67SGreg Kroah-Hartman data->usb_dev = usb_get_dev(interface_to_usbdev(intf)); 10325b775f67SGreg Kroah-Hartman usb_set_intfdata(intf, data); 10335b775f67SGreg Kroah-Hartman kref_init(&data->kref); 10345b775f67SGreg Kroah-Hartman mutex_init(&data->io_mutex); 103586286883SOliver Neukum data->zombie = 0; 10365b775f67SGreg Kroah-Hartman 10375b775f67SGreg Kroah-Hartman /* Initialize USBTMC bTag and other fields */ 10385b775f67SGreg Kroah-Hartman data->bTag = 1; 10395b775f67SGreg Kroah-Hartman data->TermCharEnabled = 0; 10405b775f67SGreg Kroah-Hartman data->TermChar = '\n'; 10415b775f67SGreg Kroah-Hartman 10425b775f67SGreg Kroah-Hartman /* USBTMC devices have only one setting, so use that */ 10435b775f67SGreg Kroah-Hartman iface_desc = data->intf->cur_altsetting; 10445b775f67SGreg Kroah-Hartman 10455b775f67SGreg Kroah-Hartman /* Find bulk in endpoint */ 10465b775f67SGreg Kroah-Hartman for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) { 10475b775f67SGreg Kroah-Hartman endpoint = &iface_desc->endpoint[n].desc; 10485b775f67SGreg Kroah-Hartman 10495b775f67SGreg Kroah-Hartman if (usb_endpoint_is_bulk_in(endpoint)) { 10505b775f67SGreg Kroah-Hartman data->bulk_in = endpoint->bEndpointAddress; 10515b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", 10525b775f67SGreg Kroah-Hartman data->bulk_in); 10535b775f67SGreg Kroah-Hartman break; 10545b775f67SGreg Kroah-Hartman } 10555b775f67SGreg Kroah-Hartman } 10565b775f67SGreg Kroah-Hartman 10575b775f67SGreg Kroah-Hartman /* Find bulk out endpoint */ 10585b775f67SGreg Kroah-Hartman for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) { 10595b775f67SGreg Kroah-Hartman endpoint = &iface_desc->endpoint[n].desc; 10605b775f67SGreg Kroah-Hartman 10615b775f67SGreg Kroah-Hartman if (usb_endpoint_is_bulk_out(endpoint)) { 10625b775f67SGreg Kroah-Hartman data->bulk_out = endpoint->bEndpointAddress; 10635b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", 10645b775f67SGreg Kroah-Hartman data->bulk_out); 10655b775f67SGreg Kroah-Hartman break; 10665b775f67SGreg Kroah-Hartman } 10675b775f67SGreg Kroah-Hartman } 10685b775f67SGreg Kroah-Hartman 10695b775f67SGreg Kroah-Hartman retcode = get_capabilities(data); 10705b775f67SGreg Kroah-Hartman if (retcode) 10715b775f67SGreg Kroah-Hartman dev_err(&intf->dev, "can't read capabilities\n"); 10725b775f67SGreg Kroah-Hartman else 10735b775f67SGreg Kroah-Hartman retcode = sysfs_create_group(&intf->dev.kobj, 10745b775f67SGreg Kroah-Hartman &capability_attr_grp); 10755b775f67SGreg Kroah-Hartman 10765b775f67SGreg Kroah-Hartman retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp); 10775b775f67SGreg Kroah-Hartman 10785b775f67SGreg Kroah-Hartman retcode = usb_register_dev(intf, &usbtmc_class); 10795b775f67SGreg Kroah-Hartman if (retcode) { 10805b775f67SGreg Kroah-Hartman dev_err(&intf->dev, "Not able to get a minor" 10815b775f67SGreg Kroah-Hartman " (base %u, slice default): %d\n", USBTMC_MINOR_BASE, 10825b775f67SGreg Kroah-Hartman retcode); 10835b775f67SGreg Kroah-Hartman goto error_register; 10845b775f67SGreg Kroah-Hartman } 10855b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "Using minor number %d\n", intf->minor); 10865b775f67SGreg Kroah-Hartman 10875b775f67SGreg Kroah-Hartman return 0; 10885b775f67SGreg Kroah-Hartman 10895b775f67SGreg Kroah-Hartman error_register: 10905b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); 10915b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); 10925b775f67SGreg Kroah-Hartman kref_put(&data->kref, usbtmc_delete); 10935b775f67SGreg Kroah-Hartman return retcode; 10945b775f67SGreg Kroah-Hartman } 10955b775f67SGreg Kroah-Hartman 10965b775f67SGreg Kroah-Hartman static void usbtmc_disconnect(struct usb_interface *intf) 10975b775f67SGreg Kroah-Hartman { 10985b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 10995b775f67SGreg Kroah-Hartman 11005b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "usbtmc_disconnect called\n"); 11015b775f67SGreg Kroah-Hartman 11025b775f67SGreg Kroah-Hartman data = usb_get_intfdata(intf); 11035b775f67SGreg Kroah-Hartman usb_deregister_dev(intf, &usbtmc_class); 11045b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); 11055b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); 110686286883SOliver Neukum mutex_lock(&data->io_mutex); 110786286883SOliver Neukum data->zombie = 1; 110886286883SOliver Neukum mutex_unlock(&data->io_mutex); 11095b775f67SGreg Kroah-Hartman kref_put(&data->kref, usbtmc_delete); 11105b775f67SGreg Kroah-Hartman } 11115b775f67SGreg Kroah-Hartman 1112a4708103SOliver Neukum static int usbtmc_suspend (struct usb_interface *intf, pm_message_t message) 1113a4708103SOliver Neukum { 1114a4708103SOliver Neukum /* this driver does not have pending URBs */ 1115a4708103SOliver Neukum return 0; 1116a4708103SOliver Neukum } 1117a4708103SOliver Neukum 1118a4708103SOliver Neukum static int usbtmc_resume (struct usb_interface *intf) 1119a4708103SOliver Neukum { 1120a4708103SOliver Neukum return 0; 1121a4708103SOliver Neukum } 1122a4708103SOliver Neukum 11235b775f67SGreg Kroah-Hartman static struct usb_driver usbtmc_driver = { 11245b775f67SGreg Kroah-Hartman .name = "usbtmc", 11255b775f67SGreg Kroah-Hartman .id_table = usbtmc_devices, 11265b775f67SGreg Kroah-Hartman .probe = usbtmc_probe, 1127a4708103SOliver Neukum .disconnect = usbtmc_disconnect, 1128a4708103SOliver Neukum .suspend = usbtmc_suspend, 1129a4708103SOliver Neukum .resume = usbtmc_resume, 11305b775f67SGreg Kroah-Hartman }; 11315b775f67SGreg Kroah-Hartman 11325b775f67SGreg Kroah-Hartman static int __init usbtmc_init(void) 11335b775f67SGreg Kroah-Hartman { 11345b775f67SGreg Kroah-Hartman int retcode; 11355b775f67SGreg Kroah-Hartman 11365b775f67SGreg Kroah-Hartman retcode = usb_register(&usbtmc_driver); 11375b775f67SGreg Kroah-Hartman if (retcode) 11385b775f67SGreg Kroah-Hartman printk(KERN_ERR KBUILD_MODNAME": Unable to register driver\n"); 11395b775f67SGreg Kroah-Hartman return retcode; 11405b775f67SGreg Kroah-Hartman } 11415b775f67SGreg Kroah-Hartman module_init(usbtmc_init); 11425b775f67SGreg Kroah-Hartman 11435b775f67SGreg Kroah-Hartman static void __exit usbtmc_exit(void) 11445b775f67SGreg Kroah-Hartman { 11455b775f67SGreg Kroah-Hartman usb_deregister(&usbtmc_driver); 11465b775f67SGreg Kroah-Hartman } 11475b775f67SGreg Kroah-Hartman module_exit(usbtmc_exit); 11485b775f67SGreg Kroah-Hartman 11495b775f67SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 1150