diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/ni_usb6501.c')
-rw-r--r-- | drivers/staging/comedi/drivers/ni_usb6501.c | 602 |
1 files changed, 0 insertions, 602 deletions
diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/staging/comedi/drivers/ni_usb6501.c deleted file mode 100644 index 5b6d9d783b2f..000000000000 --- a/drivers/staging/comedi/drivers/ni_usb6501.c +++ /dev/null @@ -1,602 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * comedi/drivers/ni_usb6501.c - * Comedi driver for National Instruments USB-6501 - * - * COMEDI - Linux Control and Measurement Device Interface - * Copyright (C) 2014 Luca Ellero <luca.ellero@brickedbrain.com> - */ - -/* - * Driver: ni_usb6501 - * Description: National Instruments USB-6501 module - * Devices: [National Instruments] USB-6501 (ni_usb6501) - * Author: Luca Ellero <luca.ellero@brickedbrain.com> - * Updated: 8 Sep 2014 - * Status: works - * - * - * Configuration Options: - * none - */ - -/* - * NI-6501 - USB PROTOCOL DESCRIPTION - * - * Every command is composed by two USB packets: - * - request (out) - * - response (in) - * - * Every packet is at least 12 bytes long, here is the meaning of - * every field (all values are hex): - * - * byte 0 is always 00 - * byte 1 is always 01 - * byte 2 is always 00 - * byte 3 is the total packet length - * - * byte 4 is always 00 - * byte 5 is the total packet length - 4 - * byte 6 is always 01 - * byte 7 is the command - * - * byte 8 is 02 (request) or 00 (response) - * byte 9 is 00 (response) or 10 (port request) or 20 (counter request) - * byte 10 is always 00 - * byte 11 is 00 (request) or 02 (response) - * - * PORT PACKETS - * - * CMD: 0xE READ_PORT - * REQ: 00 01 00 10 00 0C 01 0E 02 10 00 00 00 03 <PORT> 00 - * RES: 00 01 00 10 00 0C 01 00 00 00 00 02 00 03 <BMAP> 00 - * - * CMD: 0xF WRITE_PORT - * REQ: 00 01 00 14 00 10 01 0F 02 10 00 00 00 03 <PORT> 00 03 <BMAP> 00 00 - * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 - * - * CMD: 0x12 SET_PORT_DIR (0 = input, 1 = output) - * REQ: 00 01 00 18 00 14 01 12 02 10 00 00 - * 00 05 <PORT 0> <PORT 1> <PORT 2> 00 05 00 00 00 00 00 - * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 - * - * COUNTER PACKETS - * - * CMD 0x9: START_COUNTER - * REQ: 00 01 00 0C 00 08 01 09 02 20 00 00 - * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 - * - * CMD 0xC: STOP_COUNTER - * REQ: 00 01 00 0C 00 08 01 0C 02 20 00 00 - * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 - * - * CMD 0xE: READ_COUNTER - * REQ: 00 01 00 0C 00 08 01 0E 02 20 00 00 - * RES: 00 01 00 10 00 0C 01 00 00 00 00 02 <u32 counter value, Big Endian> - * - * CMD 0xF: WRITE_COUNTER - * REQ: 00 01 00 10 00 0C 01 0F 02 20 00 00 <u32 counter value, Big Endian> - * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 - * - * - * Please visit https://www.brickedbrain.com if you need - * additional information or have any questions. - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> - -#include "../comedi_usb.h" - -#define NI6501_TIMEOUT 1000 - -/* Port request packets */ -static const u8 READ_PORT_REQUEST[] = {0x00, 0x01, 0x00, 0x10, - 0x00, 0x0C, 0x01, 0x0E, - 0x02, 0x10, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00}; - -static const u8 WRITE_PORT_REQUEST[] = {0x00, 0x01, 0x00, 0x14, - 0x00, 0x10, 0x01, 0x0F, - 0x02, 0x10, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00}; - -static const u8 SET_PORT_DIR_REQUEST[] = {0x00, 0x01, 0x00, 0x18, - 0x00, 0x14, 0x01, 0x12, - 0x02, 0x10, 0x00, 0x00, - 0x00, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00}; - -/* Counter request packets */ -static const u8 START_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C, - 0x00, 0x08, 0x01, 0x09, - 0x02, 0x20, 0x00, 0x00}; - -static const u8 STOP_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C, - 0x00, 0x08, 0x01, 0x0C, - 0x02, 0x20, 0x00, 0x00}; - -static const u8 READ_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C, - 0x00, 0x08, 0x01, 0x0E, - 0x02, 0x20, 0x00, 0x00}; - -static const u8 WRITE_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x10, - 0x00, 0x0C, 0x01, 0x0F, - 0x02, 0x20, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - -/* Response packets */ -static const u8 GENERIC_RESPONSE[] = {0x00, 0x01, 0x00, 0x0C, - 0x00, 0x08, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x02}; - -static const u8 READ_PORT_RESPONSE[] = {0x00, 0x01, 0x00, 0x10, - 0x00, 0x0C, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x02, - 0x00, 0x03, 0x00, 0x00}; - -static const u8 READ_COUNTER_RESPONSE[] = {0x00, 0x01, 0x00, 0x10, - 0x00, 0x0C, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00}; - -enum commands { - READ_PORT, - WRITE_PORT, - SET_PORT_DIR, - START_COUNTER, - STOP_COUNTER, - READ_COUNTER, - WRITE_COUNTER -}; - -struct ni6501_private { - struct usb_endpoint_descriptor *ep_rx; - struct usb_endpoint_descriptor *ep_tx; - struct mutex mut; - u8 *usb_rx_buf; - u8 *usb_tx_buf; -}; - -static int ni6501_port_command(struct comedi_device *dev, int command, - unsigned int val, u8 *bitmap) -{ - struct usb_device *usb = comedi_to_usb_dev(dev); - struct ni6501_private *devpriv = dev->private; - int request_size, response_size; - u8 *tx = devpriv->usb_tx_buf; - int ret; - - if (command != SET_PORT_DIR && !bitmap) - return -EINVAL; - - mutex_lock(&devpriv->mut); - - switch (command) { - case READ_PORT: - request_size = sizeof(READ_PORT_REQUEST); - response_size = sizeof(READ_PORT_RESPONSE); - memcpy(tx, READ_PORT_REQUEST, request_size); - tx[14] = val & 0xff; - break; - case WRITE_PORT: - request_size = sizeof(WRITE_PORT_REQUEST); - response_size = sizeof(GENERIC_RESPONSE); - memcpy(tx, WRITE_PORT_REQUEST, request_size); - tx[14] = val & 0xff; - tx[17] = *bitmap; - break; - case SET_PORT_DIR: - request_size = sizeof(SET_PORT_DIR_REQUEST); - response_size = sizeof(GENERIC_RESPONSE); - memcpy(tx, SET_PORT_DIR_REQUEST, request_size); - tx[14] = val & 0xff; - tx[15] = (val >> 8) & 0xff; - tx[16] = (val >> 16) & 0xff; - break; - default: - ret = -EINVAL; - goto end; - } - - ret = usb_bulk_msg(usb, - usb_sndbulkpipe(usb, - devpriv->ep_tx->bEndpointAddress), - devpriv->usb_tx_buf, - request_size, - NULL, - NI6501_TIMEOUT); - if (ret) - goto end; - - ret = usb_bulk_msg(usb, - usb_rcvbulkpipe(usb, - devpriv->ep_rx->bEndpointAddress), - devpriv->usb_rx_buf, - response_size, - NULL, - NI6501_TIMEOUT); - if (ret) - goto end; - - /* Check if results are valid */ - - if (command == READ_PORT) { - *bitmap = devpriv->usb_rx_buf[14]; - /* mask bitmap for comparing */ - devpriv->usb_rx_buf[14] = 0x00; - - if (memcmp(devpriv->usb_rx_buf, READ_PORT_RESPONSE, - sizeof(READ_PORT_RESPONSE))) { - ret = -EINVAL; - } - } else if (memcmp(devpriv->usb_rx_buf, GENERIC_RESPONSE, - sizeof(GENERIC_RESPONSE))) { - ret = -EINVAL; - } -end: - mutex_unlock(&devpriv->mut); - - return ret; -} - -static int ni6501_counter_command(struct comedi_device *dev, int command, - u32 *val) -{ - struct usb_device *usb = comedi_to_usb_dev(dev); - struct ni6501_private *devpriv = dev->private; - int request_size, response_size; - u8 *tx = devpriv->usb_tx_buf; - int ret; - - if ((command == READ_COUNTER || command == WRITE_COUNTER) && !val) - return -EINVAL; - - mutex_lock(&devpriv->mut); - - switch (command) { - case START_COUNTER: - request_size = sizeof(START_COUNTER_REQUEST); - response_size = sizeof(GENERIC_RESPONSE); - memcpy(tx, START_COUNTER_REQUEST, request_size); - break; - case STOP_COUNTER: - request_size = sizeof(STOP_COUNTER_REQUEST); - response_size = sizeof(GENERIC_RESPONSE); - memcpy(tx, STOP_COUNTER_REQUEST, request_size); - break; - case READ_COUNTER: - request_size = sizeof(READ_COUNTER_REQUEST); - response_size = sizeof(READ_COUNTER_RESPONSE); - memcpy(tx, READ_COUNTER_REQUEST, request_size); - break; - case WRITE_COUNTER: - request_size = sizeof(WRITE_COUNTER_REQUEST); - response_size = sizeof(GENERIC_RESPONSE); - memcpy(tx, WRITE_COUNTER_REQUEST, request_size); - /* Setup tx packet: bytes 12,13,14,15 hold the */ - /* u32 counter value (Big Endian) */ - *((__be32 *)&tx[12]) = cpu_to_be32(*val); - break; - default: - ret = -EINVAL; - goto end; - } - - ret = usb_bulk_msg(usb, - usb_sndbulkpipe(usb, - devpriv->ep_tx->bEndpointAddress), - devpriv->usb_tx_buf, - request_size, - NULL, - NI6501_TIMEOUT); - if (ret) - goto end; - - ret = usb_bulk_msg(usb, - usb_rcvbulkpipe(usb, - devpriv->ep_rx->bEndpointAddress), - devpriv->usb_rx_buf, - response_size, - NULL, - NI6501_TIMEOUT); - if (ret) - goto end; - - /* Check if results are valid */ - - if (command == READ_COUNTER) { - int i; - - /* Read counter value: bytes 12,13,14,15 of rx packet */ - /* hold the u32 counter value (Big Endian) */ - *val = be32_to_cpu(*((__be32 *)&devpriv->usb_rx_buf[12])); - - /* mask counter value for comparing */ - for (i = 12; i < sizeof(READ_COUNTER_RESPONSE); ++i) - devpriv->usb_rx_buf[i] = 0x00; - - if (memcmp(devpriv->usb_rx_buf, READ_COUNTER_RESPONSE, - sizeof(READ_COUNTER_RESPONSE))) { - ret = -EINVAL; - } - } else if (memcmp(devpriv->usb_rx_buf, GENERIC_RESPONSE, - sizeof(GENERIC_RESPONSE))) { - ret = -EINVAL; - } -end: - mutex_unlock(&devpriv->mut); - - return ret; -} - -static int ni6501_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int ret; - - ret = comedi_dio_insn_config(dev, s, insn, data, 0); - if (ret) - return ret; - - ret = ni6501_port_command(dev, SET_PORT_DIR, s->io_bits, NULL); - if (ret) - return ret; - - return insn->n; -} - -static int ni6501_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned int mask; - int ret; - u8 port; - u8 bitmap; - - mask = comedi_dio_update_state(s, data); - - for (port = 0; port < 3; port++) { - if (mask & (0xFF << port * 8)) { - bitmap = (s->state >> port * 8) & 0xFF; - ret = ni6501_port_command(dev, WRITE_PORT, - port, &bitmap); - if (ret) - return ret; - } - } - - data[1] = 0; - - for (port = 0; port < 3; port++) { - ret = ni6501_port_command(dev, READ_PORT, port, &bitmap); - if (ret) - return ret; - data[1] |= bitmap << port * 8; - } - - return insn->n; -} - -static int ni6501_cnt_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int ret; - u32 val = 0; - - switch (data[0]) { - case INSN_CONFIG_ARM: - ret = ni6501_counter_command(dev, START_COUNTER, NULL); - break; - case INSN_CONFIG_DISARM: - ret = ni6501_counter_command(dev, STOP_COUNTER, NULL); - break; - case INSN_CONFIG_RESET: - ret = ni6501_counter_command(dev, STOP_COUNTER, NULL); - if (ret) - break; - ret = ni6501_counter_command(dev, WRITE_COUNTER, &val); - break; - default: - return -EINVAL; - } - - return ret ? ret : insn->n; -} - -static int ni6501_cnt_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int ret; - u32 val; - unsigned int i; - - for (i = 0; i < insn->n; i++) { - ret = ni6501_counter_command(dev, READ_COUNTER, &val); - if (ret) - return ret; - data[i] = val; - } - - return insn->n; -} - -static int ni6501_cnt_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int ret; - - if (insn->n) { - u32 val = data[insn->n - 1]; - - ret = ni6501_counter_command(dev, WRITE_COUNTER, &val); - if (ret) - return ret; - } - - return insn->n; -} - -static int ni6501_alloc_usb_buffers(struct comedi_device *dev) -{ - struct ni6501_private *devpriv = dev->private; - size_t size; - - size = usb_endpoint_maxp(devpriv->ep_rx); - devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL); - if (!devpriv->usb_rx_buf) - return -ENOMEM; - - size = usb_endpoint_maxp(devpriv->ep_tx); - devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL); - if (!devpriv->usb_tx_buf) - return -ENOMEM; - - return 0; -} - -static int ni6501_find_endpoints(struct comedi_device *dev) -{ - struct usb_interface *intf = comedi_to_usb_interface(dev); - struct ni6501_private *devpriv = dev->private; - struct usb_host_interface *iface_desc = intf->cur_altsetting; - struct usb_endpoint_descriptor *ep_desc; - int i; - - if (iface_desc->desc.bNumEndpoints != 2) { - dev_err(dev->class_dev, "Wrong number of endpoints\n"); - return -ENODEV; - } - - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - ep_desc = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(ep_desc)) { - if (!devpriv->ep_rx) - devpriv->ep_rx = ep_desc; - continue; - } - - if (usb_endpoint_is_bulk_out(ep_desc)) { - if (!devpriv->ep_tx) - devpriv->ep_tx = ep_desc; - continue; - } - } - - if (!devpriv->ep_rx || !devpriv->ep_tx) - return -ENODEV; - - return 0; -} - -static int ni6501_auto_attach(struct comedi_device *dev, - unsigned long context) -{ - struct usb_interface *intf = comedi_to_usb_interface(dev); - struct ni6501_private *devpriv; - struct comedi_subdevice *s; - int ret; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - mutex_init(&devpriv->mut); - usb_set_intfdata(intf, devpriv); - - ret = ni6501_find_endpoints(dev); - if (ret) - return ret; - - ret = ni6501_alloc_usb_buffers(dev); - if (ret) - return ret; - - ret = comedi_alloc_subdevices(dev, 2); - if (ret) - return ret; - - /* Digital Input/Output subdevice */ - s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 24; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = ni6501_dio_insn_bits; - s->insn_config = ni6501_dio_insn_config; - - /* Counter subdevice */ - s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; - s->n_chan = 1; - s->maxdata = 0xffffffff; - s->insn_read = ni6501_cnt_insn_read; - s->insn_write = ni6501_cnt_insn_write; - s->insn_config = ni6501_cnt_insn_config; - - return 0; -} - -static void ni6501_detach(struct comedi_device *dev) -{ - struct usb_interface *intf = comedi_to_usb_interface(dev); - struct ni6501_private *devpriv = dev->private; - - if (!devpriv) - return; - - mutex_destroy(&devpriv->mut); - - usb_set_intfdata(intf, NULL); - - kfree(devpriv->usb_rx_buf); - kfree(devpriv->usb_tx_buf); -} - -static struct comedi_driver ni6501_driver = { - .module = THIS_MODULE, - .driver_name = "ni6501", - .auto_attach = ni6501_auto_attach, - .detach = ni6501_detach, -}; - -static int ni6501_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return comedi_usb_auto_config(intf, &ni6501_driver, id->driver_info); -} - -static const struct usb_device_id ni6501_usb_table[] = { - { USB_DEVICE(0x3923, 0x718a) }, - { } -}; -MODULE_DEVICE_TABLE(usb, ni6501_usb_table); - -static struct usb_driver ni6501_usb_driver = { - .name = "ni6501", - .id_table = ni6501_usb_table, - .probe = ni6501_usb_probe, - .disconnect = comedi_usb_auto_unconfig, -}; -module_comedi_usb_driver(ni6501_driver, ni6501_usb_driver); - -MODULE_AUTHOR("Luca Ellero"); -MODULE_DESCRIPTION("Comedi driver for National Instruments USB-6501"); -MODULE_LICENSE("GPL"); |