15b775f67SGreg Kroah-Hartman /** 25b775f67SGreg Kroah-Hartman * drivers/usb/class/usbtmc.c - USB Test & Measurment 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) */ 425b775f67SGreg Kroah-Hartman #define USBTMC_TIMEOUT 10 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 605b775f67SGreg Kroah-Hartman * See section 4.2.1.8 of the USBTMC specification for details. 615b775f67SGreg Kroah-Hartman */ 625b775f67SGreg Kroah-Hartman struct usbtmc_dev_capabilities { 635b775f67SGreg Kroah-Hartman __u8 interface_capabilities; 645b775f67SGreg Kroah-Hartman __u8 device_capabilities; 655b775f67SGreg Kroah-Hartman __u8 usb488_interface_capabilities; 665b775f67SGreg Kroah-Hartman __u8 usb488_device_capabilities; 675b775f67SGreg Kroah-Hartman }; 685b775f67SGreg Kroah-Hartman 695b775f67SGreg Kroah-Hartman /* This structure holds private data for each USBTMC device. One copy is 705b775f67SGreg Kroah-Hartman * allocated for each USBTMC device in the driver's probe function. 715b775f67SGreg Kroah-Hartman */ 725b775f67SGreg Kroah-Hartman struct usbtmc_device_data { 735b775f67SGreg Kroah-Hartman const struct usb_device_id *id; 745b775f67SGreg Kroah-Hartman struct usb_device *usb_dev; 755b775f67SGreg Kroah-Hartman struct usb_interface *intf; 765b775f67SGreg Kroah-Hartman 775b775f67SGreg Kroah-Hartman unsigned int bulk_in; 785b775f67SGreg Kroah-Hartman unsigned int bulk_out; 795b775f67SGreg Kroah-Hartman 805b775f67SGreg Kroah-Hartman u8 bTag; 815b775f67SGreg Kroah-Hartman u8 bTag_last_write; /* needed for abort */ 825b775f67SGreg Kroah-Hartman u8 bTag_last_read; /* needed for abort */ 835b775f67SGreg Kroah-Hartman 845b775f67SGreg Kroah-Hartman /* attributes from the USB TMC spec for this device */ 855b775f67SGreg Kroah-Hartman u8 TermChar; 865b775f67SGreg Kroah-Hartman bool TermCharEnabled; 875b775f67SGreg Kroah-Hartman bool auto_abort; 885b775f67SGreg Kroah-Hartman 8986286883SOliver Neukum bool zombie; /* fd of disconnected device */ 9086286883SOliver Neukum 915b775f67SGreg Kroah-Hartman struct usbtmc_dev_capabilities capabilities; 925b775f67SGreg Kroah-Hartman struct kref kref; 935b775f67SGreg Kroah-Hartman struct mutex io_mutex; /* only one i/o function running at a time */ 945b775f67SGreg Kroah-Hartman }; 955b775f67SGreg Kroah-Hartman #define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref) 965b775f67SGreg Kroah-Hartman 975b775f67SGreg Kroah-Hartman /* Forward declarations */ 985b775f67SGreg Kroah-Hartman static struct usb_driver usbtmc_driver; 995b775f67SGreg Kroah-Hartman 1005b775f67SGreg Kroah-Hartman static void usbtmc_delete(struct kref *kref) 1015b775f67SGreg Kroah-Hartman { 1025b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = to_usbtmc_data(kref); 1035b775f67SGreg Kroah-Hartman 1045b775f67SGreg Kroah-Hartman usb_put_dev(data->usb_dev); 1055b775f67SGreg Kroah-Hartman kfree(data); 1065b775f67SGreg Kroah-Hartman } 1075b775f67SGreg Kroah-Hartman 1085b775f67SGreg Kroah-Hartman static int usbtmc_open(struct inode *inode, struct file *filp) 1095b775f67SGreg Kroah-Hartman { 1105b775f67SGreg Kroah-Hartman struct usb_interface *intf; 1115b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 1125b10916eSGreg Kroah-Hartman int retval = 0; 1135b775f67SGreg Kroah-Hartman 1145b775f67SGreg Kroah-Hartman intf = usb_find_interface(&usbtmc_driver, iminor(inode)); 1155b775f67SGreg Kroah-Hartman if (!intf) { 1165b775f67SGreg Kroah-Hartman printk(KERN_ERR KBUILD_MODNAME 1175b775f67SGreg Kroah-Hartman ": can not find device for minor %d", iminor(inode)); 1185b10916eSGreg Kroah-Hartman retval = -ENODEV; 1195b775f67SGreg Kroah-Hartman goto exit; 1205b775f67SGreg Kroah-Hartman } 1215b775f67SGreg Kroah-Hartman 1225b775f67SGreg Kroah-Hartman data = usb_get_intfdata(intf); 1235b775f67SGreg Kroah-Hartman kref_get(&data->kref); 1245b775f67SGreg Kroah-Hartman 1255b775f67SGreg Kroah-Hartman /* Store pointer in file structure's private data field */ 1265b775f67SGreg Kroah-Hartman filp->private_data = data; 1275b775f67SGreg Kroah-Hartman 1285b775f67SGreg Kroah-Hartman exit: 1295b775f67SGreg Kroah-Hartman return retval; 1305b775f67SGreg Kroah-Hartman } 1315b775f67SGreg Kroah-Hartman 1325b775f67SGreg Kroah-Hartman static int usbtmc_release(struct inode *inode, struct file *file) 1335b775f67SGreg Kroah-Hartman { 1345b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = file->private_data; 1355b775f67SGreg Kroah-Hartman 1365b775f67SGreg Kroah-Hartman kref_put(&data->kref, usbtmc_delete); 1375b775f67SGreg Kroah-Hartman return 0; 1385b775f67SGreg Kroah-Hartman } 1395b775f67SGreg Kroah-Hartman 1405b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) 1415b775f67SGreg Kroah-Hartman { 142b361a6e3SChris Malley u8 *buffer; 1435b775f67SGreg Kroah-Hartman struct device *dev; 1445b775f67SGreg Kroah-Hartman int rv; 1455b775f67SGreg Kroah-Hartman int n; 1465b775f67SGreg Kroah-Hartman int actual; 1475b775f67SGreg Kroah-Hartman struct usb_host_interface *current_setting; 1485b775f67SGreg Kroah-Hartman int max_size; 1495b775f67SGreg Kroah-Hartman 1505b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 1515b775f67SGreg Kroah-Hartman buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); 1525b775f67SGreg Kroah-Hartman if (!buffer) 1535b775f67SGreg Kroah-Hartman return -ENOMEM; 1545b775f67SGreg Kroah-Hartman 1555b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 1565b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 1575b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, 1585b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 1595b775f67SGreg Kroah-Hartman data->bTag_last_read, data->bulk_in, 1605b775f67SGreg Kroah-Hartman buffer, 2, USBTMC_TIMEOUT); 1615b775f67SGreg Kroah-Hartman 1625b775f67SGreg Kroah-Hartman if (rv < 0) { 1635b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 1645b775f67SGreg Kroah-Hartman goto exit; 1655b775f67SGreg Kroah-Hartman } 1665b775f67SGreg Kroah-Hartman 1675b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); 1685b775f67SGreg Kroah-Hartman 1695b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_FAILED) { 1705b775f67SGreg Kroah-Hartman rv = 0; 1715b775f67SGreg Kroah-Hartman goto exit; 1725b775f67SGreg Kroah-Hartman } 1735b775f67SGreg Kroah-Hartman 1745b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 1755b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", 1765b775f67SGreg Kroah-Hartman buffer[0]); 1775b775f67SGreg Kroah-Hartman rv = -EPERM; 1785b775f67SGreg Kroah-Hartman goto exit; 1795b775f67SGreg Kroah-Hartman } 1805b775f67SGreg Kroah-Hartman 1815b775f67SGreg Kroah-Hartman max_size = 0; 1825b775f67SGreg Kroah-Hartman current_setting = data->intf->cur_altsetting; 1835b775f67SGreg Kroah-Hartman for (n = 0; n < current_setting->desc.bNumEndpoints; n++) 1845b775f67SGreg Kroah-Hartman if (current_setting->endpoint[n].desc.bEndpointAddress == 1855b775f67SGreg Kroah-Hartman data->bulk_in) 1865b775f67SGreg Kroah-Hartman max_size = le16_to_cpu(current_setting->endpoint[n]. 1875b775f67SGreg Kroah-Hartman desc.wMaxPacketSize); 1885b775f67SGreg Kroah-Hartman 1895b775f67SGreg Kroah-Hartman if (max_size == 0) { 1905b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't get wMaxPacketSize\n"); 1915b775f67SGreg Kroah-Hartman rv = -EPERM; 1925b775f67SGreg Kroah-Hartman goto exit; 1935b775f67SGreg Kroah-Hartman } 1945b775f67SGreg Kroah-Hartman 1955b775f67SGreg Kroah-Hartman dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size); 1965b775f67SGreg Kroah-Hartman 1975b775f67SGreg Kroah-Hartman n = 0; 1985b775f67SGreg Kroah-Hartman 1995b775f67SGreg Kroah-Hartman do { 2005b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 2015b775f67SGreg Kroah-Hartman 2025b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 2035b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 2045b775f67SGreg Kroah-Hartman data->bulk_in), 2055b775f67SGreg Kroah-Hartman buffer, USBTMC_SIZE_IOBUFFER, 2065b775f67SGreg Kroah-Hartman &actual, USBTMC_TIMEOUT); 2075b775f67SGreg Kroah-Hartman 2085b775f67SGreg Kroah-Hartman n++; 2095b775f67SGreg Kroah-Hartman 2105b775f67SGreg Kroah-Hartman if (rv < 0) { 2115b775f67SGreg Kroah-Hartman dev_err(dev, "usb_bulk_msg returned %d\n", rv); 2125b775f67SGreg Kroah-Hartman goto exit; 2135b775f67SGreg Kroah-Hartman } 2145b775f67SGreg Kroah-Hartman } while ((actual == max_size) && 2155b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); 2165b775f67SGreg Kroah-Hartman 2175b775f67SGreg Kroah-Hartman if (actual == max_size) { 2185b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 2195b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 2205b775f67SGreg Kroah-Hartman rv = -EPERM; 2215b775f67SGreg Kroah-Hartman goto exit; 2225b775f67SGreg Kroah-Hartman } 2235b775f67SGreg Kroah-Hartman 2245b775f67SGreg Kroah-Hartman n = 0; 2255b775f67SGreg Kroah-Hartman 2265b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_in_status: 2275b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 2285b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 2295b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, 2305b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 2315b775f67SGreg Kroah-Hartman 0, data->bulk_in, buffer, 0x08, 2325b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 2335b775f67SGreg Kroah-Hartman 2345b775f67SGreg Kroah-Hartman if (rv < 0) { 2355b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 2365b775f67SGreg Kroah-Hartman goto exit; 2375b775f67SGreg Kroah-Hartman } 2385b775f67SGreg Kroah-Hartman 2395b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); 2405b775f67SGreg Kroah-Hartman 2415b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) { 2425b775f67SGreg Kroah-Hartman rv = 0; 2435b775f67SGreg Kroah-Hartman goto exit; 2445b775f67SGreg Kroah-Hartman } 2455b775f67SGreg Kroah-Hartman 2465b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_PENDING) { 2475b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); 2485b775f67SGreg Kroah-Hartman rv = -EPERM; 2495b775f67SGreg Kroah-Hartman goto exit; 2505b775f67SGreg Kroah-Hartman } 2515b775f67SGreg Kroah-Hartman 2525b775f67SGreg Kroah-Hartman if (buffer[1] == 1) 2535b775f67SGreg Kroah-Hartman do { 2545b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 2555b775f67SGreg Kroah-Hartman 2565b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 2575b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 2585b775f67SGreg Kroah-Hartman data->bulk_in), 2595b775f67SGreg Kroah-Hartman buffer, USBTMC_SIZE_IOBUFFER, 2605b775f67SGreg Kroah-Hartman &actual, USBTMC_TIMEOUT); 2615b775f67SGreg Kroah-Hartman 2625b775f67SGreg Kroah-Hartman n++; 2635b775f67SGreg Kroah-Hartman 2645b775f67SGreg Kroah-Hartman if (rv < 0) { 2655b775f67SGreg Kroah-Hartman dev_err(dev, "usb_bulk_msg returned %d\n", rv); 2665b775f67SGreg Kroah-Hartman goto exit; 2675b775f67SGreg Kroah-Hartman } 2685b775f67SGreg Kroah-Hartman } while ((actual = max_size) && 2695b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); 2705b775f67SGreg Kroah-Hartman 2715b775f67SGreg Kroah-Hartman if (actual == max_size) { 2725b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 2735b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 2745b775f67SGreg Kroah-Hartman rv = -EPERM; 2755b775f67SGreg Kroah-Hartman goto exit; 2765b775f67SGreg Kroah-Hartman } 2775b775f67SGreg Kroah-Hartman 2785b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_in_status; 2795b775f67SGreg Kroah-Hartman 2805b775f67SGreg Kroah-Hartman exit: 2815b775f67SGreg Kroah-Hartman kfree(buffer); 2825b775f67SGreg Kroah-Hartman return rv; 2835b775f67SGreg Kroah-Hartman 2845b775f67SGreg Kroah-Hartman } 2855b775f67SGreg Kroah-Hartman 2865b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) 2875b775f67SGreg Kroah-Hartman { 2885b775f67SGreg Kroah-Hartman struct device *dev; 2895b775f67SGreg Kroah-Hartman u8 *buffer; 2905b775f67SGreg Kroah-Hartman int rv; 2915b775f67SGreg Kroah-Hartman int n; 2925b775f67SGreg Kroah-Hartman 2935b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 2945b775f67SGreg Kroah-Hartman 2955b775f67SGreg Kroah-Hartman buffer = kmalloc(8, GFP_KERNEL); 2965b775f67SGreg Kroah-Hartman if (!buffer) 2975b775f67SGreg Kroah-Hartman return -ENOMEM; 2985b775f67SGreg Kroah-Hartman 2995b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 3005b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 3015b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, 3025b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 3035b775f67SGreg Kroah-Hartman data->bTag_last_write, data->bulk_out, 3045b775f67SGreg Kroah-Hartman buffer, 2, USBTMC_TIMEOUT); 3055b775f67SGreg Kroah-Hartman 3065b775f67SGreg Kroah-Hartman if (rv < 0) { 3075b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 3085b775f67SGreg Kroah-Hartman goto exit; 3095b775f67SGreg Kroah-Hartman } 3105b775f67SGreg Kroah-Hartman 3115b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", buffer[0]); 3125b775f67SGreg Kroah-Hartman 3135b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 3145b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", 3155b775f67SGreg Kroah-Hartman buffer[0]); 3165b775f67SGreg Kroah-Hartman rv = -EPERM; 3175b775f67SGreg Kroah-Hartman goto exit; 3185b775f67SGreg Kroah-Hartman } 3195b775f67SGreg Kroah-Hartman 3205b775f67SGreg Kroah-Hartman n = 0; 3215b775f67SGreg Kroah-Hartman 3225b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_check_status: 3235b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 3245b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 3255b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, 3265b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 3275b775f67SGreg Kroah-Hartman 0, data->bulk_out, buffer, 0x08, 3285b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 3295b775f67SGreg Kroah-Hartman n++; 3305b775f67SGreg Kroah-Hartman if (rv < 0) { 3315b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 3325b775f67SGreg Kroah-Hartman goto exit; 3335b775f67SGreg Kroah-Hartman } 3345b775f67SGreg Kroah-Hartman 3355b775f67SGreg Kroah-Hartman dev_dbg(dev, "CHECK_ABORT_BULK_OUT returned %x\n", buffer[0]); 3365b775f67SGreg Kroah-Hartman 3375b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) 3385b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_out_clear_halt; 3395b775f67SGreg Kroah-Hartman 3405b775f67SGreg Kroah-Hartman if ((buffer[0] == USBTMC_STATUS_PENDING) && 3415b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)) 3425b775f67SGreg Kroah-Hartman goto usbtmc_abort_bulk_out_check_status; 3435b775f67SGreg Kroah-Hartman 3445b775f67SGreg Kroah-Hartman rv = -EPERM; 3455b775f67SGreg Kroah-Hartman goto exit; 3465b775f67SGreg Kroah-Hartman 3475b775f67SGreg Kroah-Hartman usbtmc_abort_bulk_out_clear_halt: 3485b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 3495b775f67SGreg Kroah-Hartman usb_sndctrlpipe(data->usb_dev, 0), 3505b775f67SGreg Kroah-Hartman USB_REQ_CLEAR_FEATURE, 3515b775f67SGreg Kroah-Hartman USB_DIR_OUT | USB_TYPE_STANDARD | 3525b775f67SGreg Kroah-Hartman USB_RECIP_ENDPOINT, 3535b775f67SGreg Kroah-Hartman USB_ENDPOINT_HALT, data->bulk_out, buffer, 3545b775f67SGreg Kroah-Hartman 0, USBTMC_TIMEOUT); 3555b775f67SGreg Kroah-Hartman 3565b775f67SGreg Kroah-Hartman if (rv < 0) { 3575b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 3585b775f67SGreg Kroah-Hartman goto exit; 3595b775f67SGreg Kroah-Hartman } 3605b775f67SGreg Kroah-Hartman rv = 0; 3615b775f67SGreg Kroah-Hartman 3625b775f67SGreg Kroah-Hartman exit: 3635b775f67SGreg Kroah-Hartman kfree(buffer); 3645b775f67SGreg Kroah-Hartman return rv; 3655b775f67SGreg Kroah-Hartman } 3665b775f67SGreg Kroah-Hartman 3675b775f67SGreg Kroah-Hartman static ssize_t usbtmc_read(struct file *filp, char __user *buf, 3685b775f67SGreg Kroah-Hartman size_t count, loff_t *f_pos) 3695b775f67SGreg Kroah-Hartman { 3705b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 3715b775f67SGreg Kroah-Hartman struct device *dev; 372665d7662SGuus Sliepen u32 n_characters; 3735b775f67SGreg Kroah-Hartman u8 *buffer; 3745b775f67SGreg Kroah-Hartman int actual; 375665d7662SGuus Sliepen size_t done; 376665d7662SGuus Sliepen size_t remaining; 3775b775f67SGreg Kroah-Hartman int retval; 378665d7662SGuus Sliepen size_t this_part; 3795b775f67SGreg Kroah-Hartman 3805b775f67SGreg Kroah-Hartman /* Get pointer to private data structure */ 3815b775f67SGreg Kroah-Hartman data = filp->private_data; 3825b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 3835b775f67SGreg Kroah-Hartman 3845b775f67SGreg Kroah-Hartman buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); 3855b775f67SGreg Kroah-Hartman if (!buffer) 3865b775f67SGreg Kroah-Hartman return -ENOMEM; 3875b775f67SGreg Kroah-Hartman 3885b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 38986286883SOliver Neukum if (data->zombie) { 39086286883SOliver Neukum retval = -ENODEV; 39186286883SOliver Neukum goto exit; 39286286883SOliver Neukum } 3935b775f67SGreg Kroah-Hartman 3945b775f67SGreg Kroah-Hartman remaining = count; 3955b775f67SGreg Kroah-Hartman done = 0; 3965b775f67SGreg Kroah-Hartman 3975b775f67SGreg Kroah-Hartman while (remaining > 0) { 3985b775f67SGreg Kroah-Hartman if (remaining > USBTMC_SIZE_IOBUFFER - 12 - 3) 3995b775f67SGreg Kroah-Hartman this_part = USBTMC_SIZE_IOBUFFER - 12 - 3; 4005b775f67SGreg Kroah-Hartman else 4015b775f67SGreg Kroah-Hartman this_part = remaining; 4025b775f67SGreg Kroah-Hartman 4035b775f67SGreg Kroah-Hartman /* Setup IO buffer for DEV_DEP_MSG_IN message 4045b775f67SGreg Kroah-Hartman * Refer to class specs for details 4055b775f67SGreg Kroah-Hartman */ 4065b775f67SGreg Kroah-Hartman buffer[0] = 2; 4075b775f67SGreg Kroah-Hartman buffer[1] = data->bTag; 4085b775f67SGreg Kroah-Hartman buffer[2] = ~(data->bTag); 4095b775f67SGreg Kroah-Hartman buffer[3] = 0; /* Reserved */ 410c2cd26e1SSteve Holland buffer[4] = (this_part) & 255; 411c2cd26e1SSteve Holland buffer[5] = ((this_part) >> 8) & 255; 412c2cd26e1SSteve Holland buffer[6] = ((this_part) >> 16) & 255; 413c2cd26e1SSteve Holland buffer[7] = ((this_part) >> 24) & 255; 4145b775f67SGreg Kroah-Hartman buffer[8] = data->TermCharEnabled * 2; 4155b775f67SGreg Kroah-Hartman /* Use term character? */ 4165b775f67SGreg Kroah-Hartman buffer[9] = data->TermChar; 4175b775f67SGreg Kroah-Hartman buffer[10] = 0; /* Reserved */ 4185b775f67SGreg Kroah-Hartman buffer[11] = 0; /* Reserved */ 4195b775f67SGreg Kroah-Hartman 4205b775f67SGreg Kroah-Hartman /* Send bulk URB */ 4215b775f67SGreg Kroah-Hartman retval = usb_bulk_msg(data->usb_dev, 4225b775f67SGreg Kroah-Hartman usb_sndbulkpipe(data->usb_dev, 4235b775f67SGreg Kroah-Hartman data->bulk_out), 4245b775f67SGreg Kroah-Hartman buffer, 12, &actual, USBTMC_TIMEOUT); 4255b775f67SGreg Kroah-Hartman 4265b775f67SGreg Kroah-Hartman /* Store bTag (in case we need to abort) */ 4275b775f67SGreg Kroah-Hartman data->bTag_last_write = data->bTag; 4285b775f67SGreg Kroah-Hartman 4295b775f67SGreg Kroah-Hartman /* Increment bTag -- and increment again if zero */ 4305b775f67SGreg Kroah-Hartman data->bTag++; 4315b775f67SGreg Kroah-Hartman if (!data->bTag) 4325b775f67SGreg Kroah-Hartman (data->bTag)++; 4335b775f67SGreg Kroah-Hartman 4345b775f67SGreg Kroah-Hartman if (retval < 0) { 4355b775f67SGreg Kroah-Hartman dev_err(dev, "usb_bulk_msg returned %d\n", retval); 4365b775f67SGreg Kroah-Hartman if (data->auto_abort) 4375b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_out(data); 4385b775f67SGreg Kroah-Hartman goto exit; 4395b775f67SGreg Kroah-Hartman } 4405b775f67SGreg Kroah-Hartman 4415b775f67SGreg Kroah-Hartman /* Send bulk URB */ 4425b775f67SGreg Kroah-Hartman retval = usb_bulk_msg(data->usb_dev, 4435b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 4445b775f67SGreg Kroah-Hartman data->bulk_in), 4455b775f67SGreg Kroah-Hartman buffer, USBTMC_SIZE_IOBUFFER, &actual, 4465b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 4475b775f67SGreg Kroah-Hartman 4485b775f67SGreg Kroah-Hartman /* Store bTag (in case we need to abort) */ 4495b775f67SGreg Kroah-Hartman data->bTag_last_read = data->bTag; 4505b775f67SGreg Kroah-Hartman 4515b775f67SGreg Kroah-Hartman if (retval < 0) { 4525b775f67SGreg Kroah-Hartman dev_err(dev, "Unable to read data, error %d\n", retval); 4535b775f67SGreg Kroah-Hartman if (data->auto_abort) 4545b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_in(data); 4555b775f67SGreg Kroah-Hartman goto exit; 4565b775f67SGreg Kroah-Hartman } 4575b775f67SGreg Kroah-Hartman 4585b775f67SGreg Kroah-Hartman /* How many characters did the instrument send? */ 4595b775f67SGreg Kroah-Hartman n_characters = buffer[4] + 4605b775f67SGreg Kroah-Hartman (buffer[5] << 8) + 4615b775f67SGreg Kroah-Hartman (buffer[6] << 16) + 4625b775f67SGreg Kroah-Hartman (buffer[7] << 24); 4635b775f67SGreg Kroah-Hartman 464665d7662SGuus Sliepen /* Ensure the instrument doesn't lie about it */ 465665d7662SGuus Sliepen if(n_characters > actual - 12) { 466a2fbf10eSRandy Dunlap dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12); 467665d7662SGuus Sliepen n_characters = actual - 12; 468665d7662SGuus Sliepen } 469665d7662SGuus Sliepen 470665d7662SGuus Sliepen /* Ensure the instrument doesn't send more back than requested */ 471665d7662SGuus Sliepen if(n_characters > this_part) { 472665d7662SGuus Sliepen dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part); 473665d7662SGuus Sliepen n_characters = this_part; 474665d7662SGuus Sliepen } 475665d7662SGuus Sliepen 47692d07e42SSteve Holland /* Bound amount of data received by amount of data requested */ 47792d07e42SSteve Holland if (n_characters > this_part) 47892d07e42SSteve Holland n_characters = this_part; 47992d07e42SSteve Holland 4805b775f67SGreg Kroah-Hartman /* Copy buffer to user space */ 4815b775f67SGreg Kroah-Hartman if (copy_to_user(buf + done, &buffer[12], n_characters)) { 4825b775f67SGreg Kroah-Hartman /* There must have been an addressing problem */ 4835b775f67SGreg Kroah-Hartman retval = -EFAULT; 4845b775f67SGreg Kroah-Hartman goto exit; 4855b775f67SGreg Kroah-Hartman } 4865b775f67SGreg Kroah-Hartman 4875b775f67SGreg Kroah-Hartman done += n_characters; 4884143d178SSteve Holland /* Terminate if end-of-message bit recieved from device */ 4894143d178SSteve Holland if ((buffer[8] & 0x01) && (actual >= n_characters + 12)) 4905b775f67SGreg Kroah-Hartman remaining = 0; 491665d7662SGuus Sliepen else 492665d7662SGuus Sliepen remaining -= n_characters; 4935b775f67SGreg Kroah-Hartman } 4945b775f67SGreg Kroah-Hartman 4955b775f67SGreg Kroah-Hartman /* Update file position value */ 4965b775f67SGreg Kroah-Hartman *f_pos = *f_pos + done; 4975b775f67SGreg Kroah-Hartman retval = done; 4985b775f67SGreg Kroah-Hartman 4995b775f67SGreg Kroah-Hartman exit: 5005b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 5015b775f67SGreg Kroah-Hartman kfree(buffer); 5025b775f67SGreg Kroah-Hartman return retval; 5035b775f67SGreg Kroah-Hartman } 5045b775f67SGreg Kroah-Hartman 5055b775f67SGreg Kroah-Hartman static ssize_t usbtmc_write(struct file *filp, const char __user *buf, 5065b775f67SGreg Kroah-Hartman size_t count, loff_t *f_pos) 5075b775f67SGreg Kroah-Hartman { 5085b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 5095b775f67SGreg Kroah-Hartman u8 *buffer; 5105b775f67SGreg Kroah-Hartman int retval; 5115b775f67SGreg Kroah-Hartman int actual; 5125b775f67SGreg Kroah-Hartman unsigned long int n_bytes; 5135b775f67SGreg Kroah-Hartman int remaining; 5145b775f67SGreg Kroah-Hartman int done; 5155b775f67SGreg Kroah-Hartman int this_part; 5165b775f67SGreg Kroah-Hartman 5175b775f67SGreg Kroah-Hartman data = filp->private_data; 5185b775f67SGreg Kroah-Hartman 5195b775f67SGreg Kroah-Hartman buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); 5205b775f67SGreg Kroah-Hartman if (!buffer) 5215b775f67SGreg Kroah-Hartman return -ENOMEM; 5225b775f67SGreg Kroah-Hartman 5235b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 52486286883SOliver Neukum if (data->zombie) { 52586286883SOliver Neukum retval = -ENODEV; 52686286883SOliver Neukum goto exit; 52786286883SOliver Neukum } 5285b775f67SGreg Kroah-Hartman 5295b775f67SGreg Kroah-Hartman remaining = count; 5305b775f67SGreg Kroah-Hartman done = 0; 5315b775f67SGreg Kroah-Hartman 5325b775f67SGreg Kroah-Hartman while (remaining > 0) { 5335b775f67SGreg Kroah-Hartman if (remaining > USBTMC_SIZE_IOBUFFER - 12) { 5345b775f67SGreg Kroah-Hartman this_part = USBTMC_SIZE_IOBUFFER - 12; 5355b775f67SGreg Kroah-Hartman buffer[8] = 0; 5365b775f67SGreg Kroah-Hartman } else { 5375b775f67SGreg Kroah-Hartman this_part = remaining; 5385b775f67SGreg Kroah-Hartman buffer[8] = 1; 5395b775f67SGreg Kroah-Hartman } 5405b775f67SGreg Kroah-Hartman 5415b775f67SGreg Kroah-Hartman /* Setup IO buffer for DEV_DEP_MSG_OUT message */ 5425b775f67SGreg Kroah-Hartman buffer[0] = 1; 5435b775f67SGreg Kroah-Hartman buffer[1] = data->bTag; 5445b775f67SGreg Kroah-Hartman buffer[2] = ~(data->bTag); 5455b775f67SGreg Kroah-Hartman buffer[3] = 0; /* Reserved */ 5465b775f67SGreg Kroah-Hartman buffer[4] = this_part & 255; 5475b775f67SGreg Kroah-Hartman buffer[5] = (this_part >> 8) & 255; 5485b775f67SGreg Kroah-Hartman buffer[6] = (this_part >> 16) & 255; 5495b775f67SGreg Kroah-Hartman buffer[7] = (this_part >> 24) & 255; 5505b775f67SGreg Kroah-Hartman /* buffer[8] is set above... */ 5515b775f67SGreg Kroah-Hartman buffer[9] = 0; /* Reserved */ 5525b775f67SGreg Kroah-Hartman buffer[10] = 0; /* Reserved */ 5535b775f67SGreg Kroah-Hartman buffer[11] = 0; /* Reserved */ 5545b775f67SGreg Kroah-Hartman 5555b775f67SGreg Kroah-Hartman if (copy_from_user(&buffer[12], buf + done, this_part)) { 5565b775f67SGreg Kroah-Hartman retval = -EFAULT; 5575b775f67SGreg Kroah-Hartman goto exit; 5585b775f67SGreg Kroah-Hartman } 5595b775f67SGreg Kroah-Hartman 560857cc4dfSIlpo Järvinen n_bytes = roundup(12 + this_part, 4); 561857cc4dfSIlpo Järvinen memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part)); 5625b775f67SGreg Kroah-Hartman 5635b775f67SGreg Kroah-Hartman retval = usb_bulk_msg(data->usb_dev, 5645b775f67SGreg Kroah-Hartman usb_sndbulkpipe(data->usb_dev, 5655b775f67SGreg Kroah-Hartman data->bulk_out), 5665b775f67SGreg Kroah-Hartman buffer, n_bytes, &actual, USBTMC_TIMEOUT); 5675b775f67SGreg Kroah-Hartman 5685b775f67SGreg Kroah-Hartman data->bTag_last_write = data->bTag; 5695b775f67SGreg Kroah-Hartman data->bTag++; 5705b775f67SGreg Kroah-Hartman 5715b775f67SGreg Kroah-Hartman if (!data->bTag) 5725b775f67SGreg Kroah-Hartman data->bTag++; 5735b775f67SGreg Kroah-Hartman 5745b775f67SGreg Kroah-Hartman if (retval < 0) { 5755b775f67SGreg Kroah-Hartman dev_err(&data->intf->dev, 5765b775f67SGreg Kroah-Hartman "Unable to send data, error %d\n", retval); 5775b775f67SGreg Kroah-Hartman if (data->auto_abort) 5785b775f67SGreg Kroah-Hartman usbtmc_ioctl_abort_bulk_out(data); 5795b775f67SGreg Kroah-Hartman goto exit; 5805b775f67SGreg Kroah-Hartman } 5815b775f67SGreg Kroah-Hartman 5825b775f67SGreg Kroah-Hartman remaining -= this_part; 5835b775f67SGreg Kroah-Hartman done += this_part; 5845b775f67SGreg Kroah-Hartman } 5855b775f67SGreg Kroah-Hartman 5865b775f67SGreg Kroah-Hartman retval = count; 5875b775f67SGreg Kroah-Hartman exit: 5885b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 5895b775f67SGreg Kroah-Hartman kfree(buffer); 5905b775f67SGreg Kroah-Hartman return retval; 5915b775f67SGreg Kroah-Hartman } 5925b775f67SGreg Kroah-Hartman 5935b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) 5945b775f67SGreg Kroah-Hartman { 5955b775f67SGreg Kroah-Hartman struct usb_host_interface *current_setting; 5965b775f67SGreg Kroah-Hartman struct usb_endpoint_descriptor *desc; 5975b775f67SGreg Kroah-Hartman struct device *dev; 5985b775f67SGreg Kroah-Hartman u8 *buffer; 5995b775f67SGreg Kroah-Hartman int rv; 6005b775f67SGreg Kroah-Hartman int n; 6015b775f67SGreg Kroah-Hartman int actual; 6025b775f67SGreg Kroah-Hartman int max_size; 6035b775f67SGreg Kroah-Hartman 6045b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 6055b775f67SGreg Kroah-Hartman 6065b775f67SGreg Kroah-Hartman dev_dbg(dev, "Sending INITIATE_CLEAR request\n"); 6075b775f67SGreg Kroah-Hartman 6085b775f67SGreg Kroah-Hartman buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); 6095b775f67SGreg Kroah-Hartman if (!buffer) 6105b775f67SGreg Kroah-Hartman return -ENOMEM; 6115b775f67SGreg Kroah-Hartman 6125b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 6135b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 6145b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INITIATE_CLEAR, 6155b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 6165b775f67SGreg Kroah-Hartman 0, 0, buffer, 1, USBTMC_TIMEOUT); 6175b775f67SGreg Kroah-Hartman if (rv < 0) { 6185b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 6195b775f67SGreg Kroah-Hartman goto exit; 6205b775f67SGreg Kroah-Hartman } 6215b775f67SGreg Kroah-Hartman 6225b775f67SGreg Kroah-Hartman dev_dbg(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); 6235b775f67SGreg Kroah-Hartman 6245b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 6255b775f67SGreg Kroah-Hartman dev_err(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); 6265b775f67SGreg Kroah-Hartman rv = -EPERM; 6275b775f67SGreg Kroah-Hartman goto exit; 6285b775f67SGreg Kroah-Hartman } 6295b775f67SGreg Kroah-Hartman 6305b775f67SGreg Kroah-Hartman max_size = 0; 6315b775f67SGreg Kroah-Hartman current_setting = data->intf->cur_altsetting; 6325b775f67SGreg Kroah-Hartman for (n = 0; n < current_setting->desc.bNumEndpoints; n++) { 6335b775f67SGreg Kroah-Hartman desc = ¤t_setting->endpoint[n].desc; 6345b775f67SGreg Kroah-Hartman if (desc->bEndpointAddress == data->bulk_in) 6355b775f67SGreg Kroah-Hartman max_size = le16_to_cpu(desc->wMaxPacketSize); 6365b775f67SGreg Kroah-Hartman } 6375b775f67SGreg Kroah-Hartman 6385b775f67SGreg Kroah-Hartman if (max_size == 0) { 6395b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't get wMaxPacketSize\n"); 6405b775f67SGreg Kroah-Hartman rv = -EPERM; 6415b775f67SGreg Kroah-Hartman goto exit; 6425b775f67SGreg Kroah-Hartman } 6435b775f67SGreg Kroah-Hartman 6445b775f67SGreg Kroah-Hartman dev_dbg(dev, "wMaxPacketSize is %d\n", max_size); 6455b775f67SGreg Kroah-Hartman 6465b775f67SGreg Kroah-Hartman n = 0; 6475b775f67SGreg Kroah-Hartman 6485b775f67SGreg Kroah-Hartman usbtmc_clear_check_status: 6495b775f67SGreg Kroah-Hartman 6505b775f67SGreg Kroah-Hartman dev_dbg(dev, "Sending CHECK_CLEAR_STATUS request\n"); 6515b775f67SGreg Kroah-Hartman 6525b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 6535b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 6545b775f67SGreg Kroah-Hartman USBTMC_REQUEST_CHECK_CLEAR_STATUS, 6555b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 6565b775f67SGreg Kroah-Hartman 0, 0, buffer, 2, USBTMC_TIMEOUT); 6575b775f67SGreg Kroah-Hartman if (rv < 0) { 6585b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 6595b775f67SGreg Kroah-Hartman goto exit; 6605b775f67SGreg Kroah-Hartman } 6615b775f67SGreg Kroah-Hartman 6625b775f67SGreg Kroah-Hartman dev_dbg(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); 6635b775f67SGreg Kroah-Hartman 6645b775f67SGreg Kroah-Hartman if (buffer[0] == USBTMC_STATUS_SUCCESS) 6655b775f67SGreg Kroah-Hartman goto usbtmc_clear_bulk_out_halt; 6665b775f67SGreg Kroah-Hartman 6675b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_PENDING) { 6685b775f67SGreg Kroah-Hartman dev_err(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); 6695b775f67SGreg Kroah-Hartman rv = -EPERM; 6705b775f67SGreg Kroah-Hartman goto exit; 6715b775f67SGreg Kroah-Hartman } 6725b775f67SGreg Kroah-Hartman 6735b775f67SGreg Kroah-Hartman if (buffer[1] == 1) 6745b775f67SGreg Kroah-Hartman do { 6755b775f67SGreg Kroah-Hartman dev_dbg(dev, "Reading from bulk in EP\n"); 6765b775f67SGreg Kroah-Hartman 6775b775f67SGreg Kroah-Hartman rv = usb_bulk_msg(data->usb_dev, 6785b775f67SGreg Kroah-Hartman usb_rcvbulkpipe(data->usb_dev, 6795b775f67SGreg Kroah-Hartman data->bulk_in), 6805b775f67SGreg Kroah-Hartman buffer, USBTMC_SIZE_IOBUFFER, 6815b775f67SGreg Kroah-Hartman &actual, USBTMC_TIMEOUT); 6825b775f67SGreg Kroah-Hartman n++; 6835b775f67SGreg Kroah-Hartman 6845b775f67SGreg Kroah-Hartman if (rv < 0) { 6855b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", 6865b775f67SGreg Kroah-Hartman rv); 6875b775f67SGreg Kroah-Hartman goto exit; 6885b775f67SGreg Kroah-Hartman } 6895b775f67SGreg Kroah-Hartman } while ((actual == max_size) && 6905b775f67SGreg Kroah-Hartman (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); 6915b775f67SGreg Kroah-Hartman 6925b775f67SGreg Kroah-Hartman if (actual == max_size) { 6935b775f67SGreg Kroah-Hartman dev_err(dev, "Couldn't clear device buffer within %d cycles\n", 6945b775f67SGreg Kroah-Hartman USBTMC_MAX_READS_TO_CLEAR_BULK_IN); 6955b775f67SGreg Kroah-Hartman rv = -EPERM; 6965b775f67SGreg Kroah-Hartman goto exit; 6975b775f67SGreg Kroah-Hartman } 6985b775f67SGreg Kroah-Hartman 6995b775f67SGreg Kroah-Hartman goto usbtmc_clear_check_status; 7005b775f67SGreg Kroah-Hartman 7015b775f67SGreg Kroah-Hartman usbtmc_clear_bulk_out_halt: 7025b775f67SGreg Kroah-Hartman 7035b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 7045b775f67SGreg Kroah-Hartman usb_sndctrlpipe(data->usb_dev, 0), 7055b775f67SGreg Kroah-Hartman USB_REQ_CLEAR_FEATURE, 7065b775f67SGreg Kroah-Hartman USB_DIR_OUT | USB_TYPE_STANDARD | 7075b775f67SGreg Kroah-Hartman USB_RECIP_ENDPOINT, 7085b775f67SGreg Kroah-Hartman USB_ENDPOINT_HALT, 7095b775f67SGreg Kroah-Hartman data->bulk_out, buffer, 0, 7105b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 7115b775f67SGreg Kroah-Hartman if (rv < 0) { 7125b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 7135b775f67SGreg Kroah-Hartman goto exit; 7145b775f67SGreg Kroah-Hartman } 7155b775f67SGreg Kroah-Hartman rv = 0; 7165b775f67SGreg Kroah-Hartman 7175b775f67SGreg Kroah-Hartman exit: 7185b775f67SGreg Kroah-Hartman kfree(buffer); 7195b775f67SGreg Kroah-Hartman return rv; 7205b775f67SGreg Kroah-Hartman } 7215b775f67SGreg Kroah-Hartman 7225b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data) 7235b775f67SGreg Kroah-Hartman { 7245b775f67SGreg Kroah-Hartman u8 *buffer; 7255b775f67SGreg Kroah-Hartman int rv; 7265b775f67SGreg Kroah-Hartman 7275b775f67SGreg Kroah-Hartman buffer = kmalloc(2, GFP_KERNEL); 7285b775f67SGreg Kroah-Hartman if (!buffer) 7295b775f67SGreg Kroah-Hartman return -ENOMEM; 7305b775f67SGreg Kroah-Hartman 7315b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 7325b775f67SGreg Kroah-Hartman usb_sndctrlpipe(data->usb_dev, 0), 7335b775f67SGreg Kroah-Hartman USB_REQ_CLEAR_FEATURE, 7345b775f67SGreg Kroah-Hartman USB_DIR_OUT | USB_TYPE_STANDARD | 7355b775f67SGreg Kroah-Hartman USB_RECIP_ENDPOINT, 7365b775f67SGreg Kroah-Hartman USB_ENDPOINT_HALT, data->bulk_out, 7375b775f67SGreg Kroah-Hartman buffer, 0, USBTMC_TIMEOUT); 7385b775f67SGreg Kroah-Hartman 7395b775f67SGreg Kroah-Hartman if (rv < 0) { 7405b775f67SGreg Kroah-Hartman dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", 7415b775f67SGreg Kroah-Hartman rv); 7425b775f67SGreg Kroah-Hartman goto exit; 7435b775f67SGreg Kroah-Hartman } 7445b775f67SGreg Kroah-Hartman rv = 0; 7455b775f67SGreg Kroah-Hartman 7465b775f67SGreg Kroah-Hartman exit: 7475b775f67SGreg Kroah-Hartman kfree(buffer); 7485b775f67SGreg Kroah-Hartman return rv; 7495b775f67SGreg Kroah-Hartman } 7505b775f67SGreg Kroah-Hartman 7515b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) 7525b775f67SGreg Kroah-Hartman { 7535b775f67SGreg Kroah-Hartman u8 *buffer; 7545b775f67SGreg Kroah-Hartman int rv; 7555b775f67SGreg Kroah-Hartman 7565b775f67SGreg Kroah-Hartman buffer = kmalloc(2, GFP_KERNEL); 7575b775f67SGreg Kroah-Hartman if (!buffer) 7585b775f67SGreg Kroah-Hartman return -ENOMEM; 7595b775f67SGreg Kroah-Hartman 7605b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, usb_sndctrlpipe(data->usb_dev, 0), 7615b775f67SGreg Kroah-Hartman USB_REQ_CLEAR_FEATURE, 7625b775f67SGreg Kroah-Hartman USB_DIR_OUT | USB_TYPE_STANDARD | 7635b775f67SGreg Kroah-Hartman USB_RECIP_ENDPOINT, 7645b775f67SGreg Kroah-Hartman USB_ENDPOINT_HALT, data->bulk_in, buffer, 0, 7655b775f67SGreg Kroah-Hartman USBTMC_TIMEOUT); 7665b775f67SGreg Kroah-Hartman 7675b775f67SGreg Kroah-Hartman if (rv < 0) { 7685b775f67SGreg Kroah-Hartman dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", 7695b775f67SGreg Kroah-Hartman rv); 7705b775f67SGreg Kroah-Hartman goto exit; 7715b775f67SGreg Kroah-Hartman } 7725b775f67SGreg Kroah-Hartman rv = 0; 7735b775f67SGreg Kroah-Hartman 7745b775f67SGreg Kroah-Hartman exit: 7755b775f67SGreg Kroah-Hartman kfree(buffer); 7765b775f67SGreg Kroah-Hartman return rv; 7775b775f67SGreg Kroah-Hartman } 7785b775f67SGreg Kroah-Hartman 7795b775f67SGreg Kroah-Hartman static int get_capabilities(struct usbtmc_device_data *data) 7805b775f67SGreg Kroah-Hartman { 7815b775f67SGreg Kroah-Hartman struct device *dev = &data->usb_dev->dev; 7825b775f67SGreg Kroah-Hartman char *buffer; 783ca157c4aSOliver Neukum int rv = 0; 7845b775f67SGreg Kroah-Hartman 7855b775f67SGreg Kroah-Hartman buffer = kmalloc(0x18, GFP_KERNEL); 7865b775f67SGreg Kroah-Hartman if (!buffer) 7875b775f67SGreg Kroah-Hartman return -ENOMEM; 7885b775f67SGreg Kroah-Hartman 7895b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), 7905b775f67SGreg Kroah-Hartman USBTMC_REQUEST_GET_CAPABILITIES, 7915b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 7925b775f67SGreg Kroah-Hartman 0, 0, buffer, 0x18, USBTMC_TIMEOUT); 7935b775f67SGreg Kroah-Hartman if (rv < 0) { 7945b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 795ca157c4aSOliver Neukum goto err_out; 7965b775f67SGreg Kroah-Hartman } 7975b775f67SGreg Kroah-Hartman 7985b775f67SGreg Kroah-Hartman dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); 7995b775f67SGreg Kroah-Hartman dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]); 8005b775f67SGreg Kroah-Hartman dev_dbg(dev, "Device capabilities are %x\n", buffer[5]); 8015b775f67SGreg Kroah-Hartman dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]); 8025b775f67SGreg Kroah-Hartman dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]); 8035b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 8045b775f67SGreg Kroah-Hartman dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); 805ca157c4aSOliver Neukum rv = -EPERM; 806ca157c4aSOliver Neukum goto err_out; 8075b775f67SGreg Kroah-Hartman } 8085b775f67SGreg Kroah-Hartman 8095b775f67SGreg Kroah-Hartman data->capabilities.interface_capabilities = buffer[4]; 8105b775f67SGreg Kroah-Hartman data->capabilities.device_capabilities = buffer[5]; 8115b775f67SGreg Kroah-Hartman data->capabilities.usb488_interface_capabilities = buffer[14]; 8125b775f67SGreg Kroah-Hartman data->capabilities.usb488_device_capabilities = buffer[15]; 8135b775f67SGreg Kroah-Hartman 814ca157c4aSOliver Neukum err_out: 8155b775f67SGreg Kroah-Hartman kfree(buffer); 816ca157c4aSOliver Neukum return rv; 8175b775f67SGreg Kroah-Hartman } 8185b775f67SGreg Kroah-Hartman 8195b775f67SGreg Kroah-Hartman #define capability_attribute(name) \ 8205b775f67SGreg Kroah-Hartman static ssize_t show_##name(struct device *dev, \ 8215b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 8225b775f67SGreg Kroah-Hartman { \ 8235b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 8245b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 8255b775f67SGreg Kroah-Hartman \ 8265b775f67SGreg Kroah-Hartman return sprintf(buf, "%d\n", data->capabilities.name); \ 8275b775f67SGreg Kroah-Hartman } \ 8285b775f67SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) 8295b775f67SGreg Kroah-Hartman 8305b775f67SGreg Kroah-Hartman capability_attribute(interface_capabilities); 8315b775f67SGreg Kroah-Hartman capability_attribute(device_capabilities); 8325b775f67SGreg Kroah-Hartman capability_attribute(usb488_interface_capabilities); 8335b775f67SGreg Kroah-Hartman capability_attribute(usb488_device_capabilities); 8345b775f67SGreg Kroah-Hartman 8355b775f67SGreg Kroah-Hartman static struct attribute *capability_attrs[] = { 8365b775f67SGreg Kroah-Hartman &dev_attr_interface_capabilities.attr, 8375b775f67SGreg Kroah-Hartman &dev_attr_device_capabilities.attr, 8385b775f67SGreg Kroah-Hartman &dev_attr_usb488_interface_capabilities.attr, 8395b775f67SGreg Kroah-Hartman &dev_attr_usb488_device_capabilities.attr, 8405b775f67SGreg Kroah-Hartman NULL, 8415b775f67SGreg Kroah-Hartman }; 8425b775f67SGreg Kroah-Hartman 8435b775f67SGreg Kroah-Hartman static struct attribute_group capability_attr_grp = { 8445b775f67SGreg Kroah-Hartman .attrs = capability_attrs, 8455b775f67SGreg Kroah-Hartman }; 8465b775f67SGreg Kroah-Hartman 8475b775f67SGreg Kroah-Hartman static ssize_t show_TermChar(struct device *dev, 8485b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 8495b775f67SGreg Kroah-Hartman { 8505b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); 8515b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); 8525b775f67SGreg Kroah-Hartman 8535b775f67SGreg Kroah-Hartman return sprintf(buf, "%c\n", data->TermChar); 8545b775f67SGreg Kroah-Hartman } 8555b775f67SGreg Kroah-Hartman 8565b775f67SGreg Kroah-Hartman static ssize_t store_TermChar(struct device *dev, 8575b775f67SGreg Kroah-Hartman struct device_attribute *attr, 8585b775f67SGreg Kroah-Hartman const char *buf, size_t count) 8595b775f67SGreg Kroah-Hartman { 8605b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); 8615b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); 8625b775f67SGreg Kroah-Hartman 8635b775f67SGreg Kroah-Hartman if (count < 1) 8645b775f67SGreg Kroah-Hartman return -EINVAL; 8655b775f67SGreg Kroah-Hartman data->TermChar = buf[0]; 8665b775f67SGreg Kroah-Hartman return count; 8675b775f67SGreg Kroah-Hartman } 8685b775f67SGreg Kroah-Hartman static DEVICE_ATTR(TermChar, S_IRUGO, show_TermChar, store_TermChar); 8695b775f67SGreg Kroah-Hartman 8705b775f67SGreg Kroah-Hartman #define data_attribute(name) \ 8715b775f67SGreg Kroah-Hartman static ssize_t show_##name(struct device *dev, \ 8725b775f67SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 8735b775f67SGreg Kroah-Hartman { \ 8745b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 8755b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 8765b775f67SGreg Kroah-Hartman \ 8775b775f67SGreg Kroah-Hartman return sprintf(buf, "%d\n", data->name); \ 8785b775f67SGreg Kroah-Hartman } \ 8795b775f67SGreg Kroah-Hartman static ssize_t store_##name(struct device *dev, \ 8805b775f67SGreg Kroah-Hartman struct device_attribute *attr, \ 8815b775f67SGreg Kroah-Hartman const char *buf, size_t count) \ 8825b775f67SGreg Kroah-Hartman { \ 8835b775f67SGreg Kroah-Hartman struct usb_interface *intf = to_usb_interface(dev); \ 8845b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data = usb_get_intfdata(intf); \ 8855b775f67SGreg Kroah-Hartman ssize_t result; \ 8865b775f67SGreg Kroah-Hartman unsigned val; \ 8875b775f67SGreg Kroah-Hartman \ 8885b775f67SGreg Kroah-Hartman result = sscanf(buf, "%u\n", &val); \ 8895b775f67SGreg Kroah-Hartman if (result != 1) \ 8905b775f67SGreg Kroah-Hartman result = -EINVAL; \ 8915b775f67SGreg Kroah-Hartman data->name = val; \ 8925b775f67SGreg Kroah-Hartman if (result < 0) \ 8935b775f67SGreg Kroah-Hartman return result; \ 8945b775f67SGreg Kroah-Hartman else \ 8955b775f67SGreg Kroah-Hartman return count; \ 8965b775f67SGreg Kroah-Hartman } \ 8975b775f67SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_##name, store_##name) 8985b775f67SGreg Kroah-Hartman 8995b775f67SGreg Kroah-Hartman data_attribute(TermCharEnabled); 9005b775f67SGreg Kroah-Hartman data_attribute(auto_abort); 9015b775f67SGreg Kroah-Hartman 9025b775f67SGreg Kroah-Hartman static struct attribute *data_attrs[] = { 9035b775f67SGreg Kroah-Hartman &dev_attr_TermChar.attr, 9045b775f67SGreg Kroah-Hartman &dev_attr_TermCharEnabled.attr, 9055b775f67SGreg Kroah-Hartman &dev_attr_auto_abort.attr, 9065b775f67SGreg Kroah-Hartman NULL, 9075b775f67SGreg Kroah-Hartman }; 9085b775f67SGreg Kroah-Hartman 9095b775f67SGreg Kroah-Hartman static struct attribute_group data_attr_grp = { 9105b775f67SGreg Kroah-Hartman .attrs = data_attrs, 9115b775f67SGreg Kroah-Hartman }; 9125b775f67SGreg Kroah-Hartman 9135b775f67SGreg Kroah-Hartman static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) 9145b775f67SGreg Kroah-Hartman { 9155b775f67SGreg Kroah-Hartman struct device *dev; 9165b775f67SGreg Kroah-Hartman u8 *buffer; 9175b775f67SGreg Kroah-Hartman int rv; 9185b775f67SGreg Kroah-Hartman 9195b775f67SGreg Kroah-Hartman dev = &data->intf->dev; 9205b775f67SGreg Kroah-Hartman 9215b775f67SGreg Kroah-Hartman buffer = kmalloc(2, GFP_KERNEL); 9225b775f67SGreg Kroah-Hartman if (!buffer) 9235b775f67SGreg Kroah-Hartman return -ENOMEM; 9245b775f67SGreg Kroah-Hartman 9255b775f67SGreg Kroah-Hartman rv = usb_control_msg(data->usb_dev, 9265b775f67SGreg Kroah-Hartman usb_rcvctrlpipe(data->usb_dev, 0), 9275b775f67SGreg Kroah-Hartman USBTMC_REQUEST_INDICATOR_PULSE, 9285b775f67SGreg Kroah-Hartman USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 9295b775f67SGreg Kroah-Hartman 0, 0, buffer, 0x01, USBTMC_TIMEOUT); 9305b775f67SGreg Kroah-Hartman 9315b775f67SGreg Kroah-Hartman if (rv < 0) { 9325b775f67SGreg Kroah-Hartman dev_err(dev, "usb_control_msg returned %d\n", rv); 9335b775f67SGreg Kroah-Hartman goto exit; 9345b775f67SGreg Kroah-Hartman } 9355b775f67SGreg Kroah-Hartman 9365b775f67SGreg Kroah-Hartman dev_dbg(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); 9375b775f67SGreg Kroah-Hartman 9385b775f67SGreg Kroah-Hartman if (buffer[0] != USBTMC_STATUS_SUCCESS) { 9395b775f67SGreg Kroah-Hartman dev_err(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); 9405b775f67SGreg Kroah-Hartman rv = -EPERM; 9415b775f67SGreg Kroah-Hartman goto exit; 9425b775f67SGreg Kroah-Hartman } 9435b775f67SGreg Kroah-Hartman rv = 0; 9445b775f67SGreg Kroah-Hartman 9455b775f67SGreg Kroah-Hartman exit: 9465b775f67SGreg Kroah-Hartman kfree(buffer); 9475b775f67SGreg Kroah-Hartman return rv; 9485b775f67SGreg Kroah-Hartman } 9495b775f67SGreg Kroah-Hartman 9505b775f67SGreg Kroah-Hartman static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 9515b775f67SGreg Kroah-Hartman { 9525b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 9535b775f67SGreg Kroah-Hartman int retval = -EBADRQC; 9545b775f67SGreg Kroah-Hartman 9555b775f67SGreg Kroah-Hartman data = file->private_data; 9565b775f67SGreg Kroah-Hartman mutex_lock(&data->io_mutex); 95786286883SOliver Neukum if (data->zombie) { 95886286883SOliver Neukum retval = -ENODEV; 95986286883SOliver Neukum goto skip_io_on_zombie; 96086286883SOliver Neukum } 9615b775f67SGreg Kroah-Hartman 9625b775f67SGreg Kroah-Hartman switch (cmd) { 9635b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR_OUT_HALT: 9645b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear_out_halt(data); 965a92b63e7SGreg Kroah-Hartman break; 9665b775f67SGreg Kroah-Hartman 9675b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR_IN_HALT: 9685b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear_in_halt(data); 969a92b63e7SGreg Kroah-Hartman break; 9705b775f67SGreg Kroah-Hartman 9715b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_INDICATOR_PULSE: 9725b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_indicator_pulse(data); 973a92b63e7SGreg Kroah-Hartman break; 9745b775f67SGreg Kroah-Hartman 9755b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_CLEAR: 9765b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_clear(data); 977a92b63e7SGreg Kroah-Hartman break; 9785b775f67SGreg Kroah-Hartman 9795b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_ABORT_BULK_OUT: 9805b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_abort_bulk_out(data); 981a92b63e7SGreg Kroah-Hartman break; 9825b775f67SGreg Kroah-Hartman 9835b775f67SGreg Kroah-Hartman case USBTMC_IOCTL_ABORT_BULK_IN: 9845b775f67SGreg Kroah-Hartman retval = usbtmc_ioctl_abort_bulk_in(data); 985a92b63e7SGreg Kroah-Hartman break; 9865b775f67SGreg Kroah-Hartman } 9875b775f67SGreg Kroah-Hartman 98886286883SOliver Neukum skip_io_on_zombie: 9895b775f67SGreg Kroah-Hartman mutex_unlock(&data->io_mutex); 9905b775f67SGreg Kroah-Hartman return retval; 9915b775f67SGreg Kroah-Hartman } 9925b775f67SGreg Kroah-Hartman 9935b775f67SGreg Kroah-Hartman static struct file_operations fops = { 9945b775f67SGreg Kroah-Hartman .owner = THIS_MODULE, 9955b775f67SGreg Kroah-Hartman .read = usbtmc_read, 9965b775f67SGreg Kroah-Hartman .write = usbtmc_write, 9975b775f67SGreg Kroah-Hartman .open = usbtmc_open, 9985b775f67SGreg Kroah-Hartman .release = usbtmc_release, 9995b775f67SGreg Kroah-Hartman .unlocked_ioctl = usbtmc_ioctl, 10005b775f67SGreg Kroah-Hartman }; 10015b775f67SGreg Kroah-Hartman 10025b775f67SGreg Kroah-Hartman static struct usb_class_driver usbtmc_class = { 10035b775f67SGreg Kroah-Hartman .name = "usbtmc%d", 10045b775f67SGreg Kroah-Hartman .fops = &fops, 10055b775f67SGreg Kroah-Hartman .minor_base = USBTMC_MINOR_BASE, 10065b775f67SGreg Kroah-Hartman }; 10075b775f67SGreg Kroah-Hartman 10085b775f67SGreg Kroah-Hartman 10095b775f67SGreg Kroah-Hartman static int usbtmc_probe(struct usb_interface *intf, 10105b775f67SGreg Kroah-Hartman const struct usb_device_id *id) 10115b775f67SGreg Kroah-Hartman { 10125b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 10135b775f67SGreg Kroah-Hartman struct usb_host_interface *iface_desc; 10145b775f67SGreg Kroah-Hartman struct usb_endpoint_descriptor *endpoint; 10155b775f67SGreg Kroah-Hartman int n; 10165b775f67SGreg Kroah-Hartman int retcode; 10175b775f67SGreg Kroah-Hartman 10185b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "%s called\n", __func__); 10195b775f67SGreg Kroah-Hartman 10205b775f67SGreg Kroah-Hartman data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL); 10215b775f67SGreg Kroah-Hartman if (!data) { 10225b775f67SGreg Kroah-Hartman dev_err(&intf->dev, "Unable to allocate kernel memory\n"); 10235b775f67SGreg Kroah-Hartman return -ENOMEM; 10245b775f67SGreg Kroah-Hartman } 10255b775f67SGreg Kroah-Hartman 10265b775f67SGreg Kroah-Hartman data->intf = intf; 10275b775f67SGreg Kroah-Hartman data->id = id; 10285b775f67SGreg Kroah-Hartman data->usb_dev = usb_get_dev(interface_to_usbdev(intf)); 10295b775f67SGreg Kroah-Hartman usb_set_intfdata(intf, data); 10305b775f67SGreg Kroah-Hartman kref_init(&data->kref); 10315b775f67SGreg Kroah-Hartman mutex_init(&data->io_mutex); 103286286883SOliver Neukum data->zombie = 0; 10335b775f67SGreg Kroah-Hartman 10345b775f67SGreg Kroah-Hartman /* Initialize USBTMC bTag and other fields */ 10355b775f67SGreg Kroah-Hartman data->bTag = 1; 10365b775f67SGreg Kroah-Hartman data->TermCharEnabled = 0; 10375b775f67SGreg Kroah-Hartman data->TermChar = '\n'; 10385b775f67SGreg Kroah-Hartman 10395b775f67SGreg Kroah-Hartman /* USBTMC devices have only one setting, so use that */ 10405b775f67SGreg Kroah-Hartman iface_desc = data->intf->cur_altsetting; 10415b775f67SGreg Kroah-Hartman 10425b775f67SGreg Kroah-Hartman /* Find bulk in endpoint */ 10435b775f67SGreg Kroah-Hartman for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) { 10445b775f67SGreg Kroah-Hartman endpoint = &iface_desc->endpoint[n].desc; 10455b775f67SGreg Kroah-Hartman 10465b775f67SGreg Kroah-Hartman if (usb_endpoint_is_bulk_in(endpoint)) { 10475b775f67SGreg Kroah-Hartman data->bulk_in = endpoint->bEndpointAddress; 10485b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", 10495b775f67SGreg Kroah-Hartman data->bulk_in); 10505b775f67SGreg Kroah-Hartman break; 10515b775f67SGreg Kroah-Hartman } 10525b775f67SGreg Kroah-Hartman } 10535b775f67SGreg Kroah-Hartman 10545b775f67SGreg Kroah-Hartman /* Find bulk out endpoint */ 10555b775f67SGreg Kroah-Hartman for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) { 10565b775f67SGreg Kroah-Hartman endpoint = &iface_desc->endpoint[n].desc; 10575b775f67SGreg Kroah-Hartman 10585b775f67SGreg Kroah-Hartman if (usb_endpoint_is_bulk_out(endpoint)) { 10595b775f67SGreg Kroah-Hartman data->bulk_out = endpoint->bEndpointAddress; 10605b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", 10615b775f67SGreg Kroah-Hartman data->bulk_out); 10625b775f67SGreg Kroah-Hartman break; 10635b775f67SGreg Kroah-Hartman } 10645b775f67SGreg Kroah-Hartman } 10655b775f67SGreg Kroah-Hartman 10665b775f67SGreg Kroah-Hartman retcode = get_capabilities(data); 10675b775f67SGreg Kroah-Hartman if (retcode) 10685b775f67SGreg Kroah-Hartman dev_err(&intf->dev, "can't read capabilities\n"); 10695b775f67SGreg Kroah-Hartman else 10705b775f67SGreg Kroah-Hartman retcode = sysfs_create_group(&intf->dev.kobj, 10715b775f67SGreg Kroah-Hartman &capability_attr_grp); 10725b775f67SGreg Kroah-Hartman 10735b775f67SGreg Kroah-Hartman retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp); 10745b775f67SGreg Kroah-Hartman 10755b775f67SGreg Kroah-Hartman retcode = usb_register_dev(intf, &usbtmc_class); 10765b775f67SGreg Kroah-Hartman if (retcode) { 10775b775f67SGreg Kroah-Hartman dev_err(&intf->dev, "Not able to get a minor" 10785b775f67SGreg Kroah-Hartman " (base %u, slice default): %d\n", USBTMC_MINOR_BASE, 10795b775f67SGreg Kroah-Hartman retcode); 10805b775f67SGreg Kroah-Hartman goto error_register; 10815b775f67SGreg Kroah-Hartman } 10825b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "Using minor number %d\n", intf->minor); 10835b775f67SGreg Kroah-Hartman 10845b775f67SGreg Kroah-Hartman return 0; 10855b775f67SGreg Kroah-Hartman 10865b775f67SGreg Kroah-Hartman error_register: 10875b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); 10885b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); 10895b775f67SGreg Kroah-Hartman kref_put(&data->kref, usbtmc_delete); 10905b775f67SGreg Kroah-Hartman return retcode; 10915b775f67SGreg Kroah-Hartman } 10925b775f67SGreg Kroah-Hartman 10935b775f67SGreg Kroah-Hartman static void usbtmc_disconnect(struct usb_interface *intf) 10945b775f67SGreg Kroah-Hartman { 10955b775f67SGreg Kroah-Hartman struct usbtmc_device_data *data; 10965b775f67SGreg Kroah-Hartman 10975b775f67SGreg Kroah-Hartman dev_dbg(&intf->dev, "usbtmc_disconnect called\n"); 10985b775f67SGreg Kroah-Hartman 10995b775f67SGreg Kroah-Hartman data = usb_get_intfdata(intf); 11005b775f67SGreg Kroah-Hartman usb_deregister_dev(intf, &usbtmc_class); 11015b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); 11025b775f67SGreg Kroah-Hartman sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); 110386286883SOliver Neukum mutex_lock(&data->io_mutex); 110486286883SOliver Neukum data->zombie = 1; 110586286883SOliver Neukum mutex_unlock(&data->io_mutex); 11065b775f67SGreg Kroah-Hartman kref_put(&data->kref, usbtmc_delete); 11075b775f67SGreg Kroah-Hartman } 11085b775f67SGreg Kroah-Hartman 1109a4708103SOliver Neukum static int usbtmc_suspend (struct usb_interface *intf, pm_message_t message) 1110a4708103SOliver Neukum { 1111a4708103SOliver Neukum /* this driver does not have pending URBs */ 1112a4708103SOliver Neukum return 0; 1113a4708103SOliver Neukum } 1114a4708103SOliver Neukum 1115a4708103SOliver Neukum static int usbtmc_resume (struct usb_interface *intf) 1116a4708103SOliver Neukum { 1117a4708103SOliver Neukum return 0; 1118a4708103SOliver Neukum } 1119a4708103SOliver Neukum 11205b775f67SGreg Kroah-Hartman static struct usb_driver usbtmc_driver = { 11215b775f67SGreg Kroah-Hartman .name = "usbtmc", 11225b775f67SGreg Kroah-Hartman .id_table = usbtmc_devices, 11235b775f67SGreg Kroah-Hartman .probe = usbtmc_probe, 1124a4708103SOliver Neukum .disconnect = usbtmc_disconnect, 1125a4708103SOliver Neukum .suspend = usbtmc_suspend, 1126a4708103SOliver Neukum .resume = usbtmc_resume, 11275b775f67SGreg Kroah-Hartman }; 11285b775f67SGreg Kroah-Hartman 11295b775f67SGreg Kroah-Hartman static int __init usbtmc_init(void) 11305b775f67SGreg Kroah-Hartman { 11315b775f67SGreg Kroah-Hartman int retcode; 11325b775f67SGreg Kroah-Hartman 11335b775f67SGreg Kroah-Hartman retcode = usb_register(&usbtmc_driver); 11345b775f67SGreg Kroah-Hartman if (retcode) 11355b775f67SGreg Kroah-Hartman printk(KERN_ERR KBUILD_MODNAME": Unable to register driver\n"); 11365b775f67SGreg Kroah-Hartman return retcode; 11375b775f67SGreg Kroah-Hartman } 11385b775f67SGreg Kroah-Hartman module_init(usbtmc_init); 11395b775f67SGreg Kroah-Hartman 11405b775f67SGreg Kroah-Hartman static void __exit usbtmc_exit(void) 11415b775f67SGreg Kroah-Hartman { 11425b775f67SGreg Kroah-Hartman usb_deregister(&usbtmc_driver); 11435b775f67SGreg Kroah-Hartman } 11445b775f67SGreg Kroah-Hartman module_exit(usbtmc_exit); 11455b775f67SGreg Kroah-Hartman 11465b775f67SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 1147