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