root/drivers/usb/misc/cypress_cy7c63.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vendor_command
  2. write_port
  3. port0_store
  4. port1_store
  5. read_port
  6. port0_show
  7. port1_show
  8. cypress_probe
  9. cypress_disconnect

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3 * cypress_cy7c63.c
   4 *
   5 * Copyright (c) 2006-2007 Oliver Bock (bock@tfh-berlin.de)
   6 *
   7 *       This driver is based on the Cypress USB Driver by Marcus Maul
   8 *       (cyport) and the 2.0 version of Greg Kroah-Hartman's
   9 *       USB Skeleton driver.
  10 *
  11 *       This is a generic driver for the Cypress CY7C63xxx family.
  12 *       For the time being it enables you to read from and write to
  13 *       the single I/O ports of the device.
  14 *
  15 *       Supported vendors:      AK Modul-Bus Computer GmbH
  16 *                               (Firmware "Port-Chip")
  17 *
  18 *       Supported devices:      CY7C63001A-PC
  19 *                               CY7C63001C-PXC
  20 *                               CY7C63001C-SXC
  21 *
  22 *       Supported functions:    Read/Write Ports
  23 *
  24 *
  25 *       For up-to-date information please visit:
  26 *       http://www.obock.de/kernel/cypress
  27 */
  28 
  29 #include <linux/module.h>
  30 #include <linux/kernel.h>
  31 #include <linux/slab.h>
  32 #include <linux/usb.h>
  33 
  34 #define DRIVER_AUTHOR           "Oliver Bock (bock@tfh-berlin.de)"
  35 #define DRIVER_DESC             "Cypress CY7C63xxx USB driver"
  36 
  37 #define CYPRESS_VENDOR_ID       0xa2c
  38 #define CYPRESS_PRODUCT_ID      0x8
  39 
  40 #define CYPRESS_READ_PORT       0x4
  41 #define CYPRESS_WRITE_PORT      0x5
  42 
  43 #define CYPRESS_READ_RAM        0x2
  44 #define CYPRESS_WRITE_RAM       0x3
  45 #define CYPRESS_READ_ROM        0x1
  46 
  47 #define CYPRESS_READ_PORT_ID0   0
  48 #define CYPRESS_WRITE_PORT_ID0  0
  49 #define CYPRESS_READ_PORT_ID1   0x2
  50 #define CYPRESS_WRITE_PORT_ID1  1
  51 
  52 #define CYPRESS_MAX_REQSIZE     8
  53 
  54 
  55 /* table of devices that work with this driver */
  56 static const struct usb_device_id cypress_table[] = {
  57         { USB_DEVICE(CYPRESS_VENDOR_ID, CYPRESS_PRODUCT_ID) },
  58         { }
  59 };
  60 MODULE_DEVICE_TABLE(usb, cypress_table);
  61 
  62 /* structure to hold all of our device specific stuff */
  63 struct cypress {
  64         struct usb_device *     udev;
  65         unsigned char           port[2];
  66 };
  67 
  68 /* used to send usb control messages to device */
  69 static int vendor_command(struct cypress *dev, unsigned char request,
  70                           unsigned char address, unsigned char data)
  71 {
  72         int retval = 0;
  73         unsigned int pipe;
  74         unsigned char *iobuf;
  75 
  76         /* allocate some memory for the i/o buffer*/
  77         iobuf = kzalloc(CYPRESS_MAX_REQSIZE, GFP_KERNEL);
  78         if (!iobuf) {
  79                 retval = -ENOMEM;
  80                 goto error;
  81         }
  82 
  83         dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data);
  84 
  85         /* prepare usb control message and send it upstream */
  86         pipe = usb_rcvctrlpipe(dev->udev, 0);
  87         retval = usb_control_msg(dev->udev, pipe, request,
  88                                  USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
  89                                  address, data, iobuf, CYPRESS_MAX_REQSIZE,
  90                                  USB_CTRL_GET_TIMEOUT);
  91 
  92         /* store returned data (more READs to be added) */
  93         switch (request) {
  94                 case CYPRESS_READ_PORT:
  95                         if (address == CYPRESS_READ_PORT_ID0) {
  96                                 dev->port[0] = iobuf[1];
  97                                 dev_dbg(&dev->udev->dev,
  98                                         "READ_PORT0 returned: %d\n",
  99                                         dev->port[0]);
 100                         }
 101                         else if (address == CYPRESS_READ_PORT_ID1) {
 102                                 dev->port[1] = iobuf[1];
 103                                 dev_dbg(&dev->udev->dev,
 104                                         "READ_PORT1 returned: %d\n",
 105                                         dev->port[1]);
 106                         }
 107                         break;
 108         }
 109 
 110         kfree(iobuf);
 111 error:
 112         return retval;
 113 }
 114 
 115 /* write port value */
 116 static ssize_t write_port(struct device *dev, struct device_attribute *attr,
 117                           const char *buf, size_t count,
 118                           int port_num, int write_id)
 119 {
 120         int value = -1;
 121         int result = 0;
 122 
 123         struct usb_interface *intf = to_usb_interface(dev);
 124         struct cypress *cyp = usb_get_intfdata(intf);
 125 
 126         dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", port_num);
 127 
 128         /* validate input data */
 129         if (sscanf(buf, "%d", &value) < 1) {
 130                 result = -EINVAL;
 131                 goto error;
 132         }
 133         if (value < 0 || value > 255) {
 134                 result = -EINVAL;
 135                 goto error;
 136         }
 137 
 138         result = vendor_command(cyp, CYPRESS_WRITE_PORT, write_id,
 139                                 (unsigned char)value);
 140 
 141         dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
 142 error:
 143         return result < 0 ? result : count;
 144 }
 145 
 146 /* attribute callback handler (write) */
 147 static ssize_t port0_store(struct device *dev,
 148                                  struct device_attribute *attr,
 149                                  const char *buf, size_t count)
 150 {
 151         return write_port(dev, attr, buf, count, 0, CYPRESS_WRITE_PORT_ID0);
 152 }
 153 
 154 /* attribute callback handler (write) */
 155 static ssize_t port1_store(struct device *dev,
 156                                  struct device_attribute *attr,
 157                                  const char *buf, size_t count)
 158 {
 159         return write_port(dev, attr, buf, count, 1, CYPRESS_WRITE_PORT_ID1);
 160 }
 161 
 162 /* read port value */
 163 static ssize_t read_port(struct device *dev, struct device_attribute *attr,
 164                          char *buf, int port_num, int read_id)
 165 {
 166         int result = 0;
 167 
 168         struct usb_interface *intf = to_usb_interface(dev);
 169         struct cypress *cyp = usb_get_intfdata(intf);
 170 
 171         dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", port_num);
 172 
 173         result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0);
 174 
 175         dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
 176 
 177         return sprintf(buf, "%d", cyp->port[port_num]);
 178 }
 179 
 180 /* attribute callback handler (read) */
 181 static ssize_t port0_show(struct device *dev,
 182                                  struct device_attribute *attr, char *buf)
 183 {
 184         return read_port(dev, attr, buf, 0, CYPRESS_READ_PORT_ID0);
 185 }
 186 static DEVICE_ATTR_RW(port0);
 187 
 188 /* attribute callback handler (read) */
 189 static ssize_t port1_show(struct device *dev,
 190                                  struct device_attribute *attr, char *buf)
 191 {
 192         return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1);
 193 }
 194 static DEVICE_ATTR_RW(port1);
 195 
 196 static struct attribute *cypress_attrs[] = {
 197         &dev_attr_port0.attr,
 198         &dev_attr_port1.attr,
 199         NULL,
 200 };
 201 ATTRIBUTE_GROUPS(cypress);
 202 
 203 static int cypress_probe(struct usb_interface *interface,
 204                          const struct usb_device_id *id)
 205 {
 206         struct cypress *dev = NULL;
 207         int retval = -ENOMEM;
 208 
 209         /* allocate memory for our device state and initialize it */
 210         dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 211         if (!dev)
 212                 goto error_mem;
 213 
 214         dev->udev = usb_get_dev(interface_to_usbdev(interface));
 215 
 216         /* save our data pointer in this interface device */
 217         usb_set_intfdata(interface, dev);
 218 
 219         /* let the user know that the device is now attached */
 220         dev_info(&interface->dev,
 221                  "Cypress CY7C63xxx device now attached\n");
 222         return 0;
 223 
 224 error_mem:
 225         return retval;
 226 }
 227 
 228 static void cypress_disconnect(struct usb_interface *interface)
 229 {
 230         struct cypress *dev;
 231 
 232         dev = usb_get_intfdata(interface);
 233 
 234         /* the intfdata can be set to NULL only after the
 235          * device files have been removed */
 236         usb_set_intfdata(interface, NULL);
 237 
 238         usb_put_dev(dev->udev);
 239 
 240         dev_info(&interface->dev,
 241                  "Cypress CY7C63xxx device now disconnected\n");
 242 
 243         kfree(dev);
 244 }
 245 
 246 static struct usb_driver cypress_driver = {
 247         .name = "cypress_cy7c63",
 248         .probe = cypress_probe,
 249         .disconnect = cypress_disconnect,
 250         .id_table = cypress_table,
 251         .dev_groups = cypress_groups,
 252 };
 253 
 254 module_usb_driver(cypress_driver);
 255 
 256 MODULE_AUTHOR(DRIVER_AUTHOR);
 257 MODULE_DESCRIPTION(DRIVER_DESC);
 258 
 259 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */