Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003 * cypress_cy7c63.c
0004 *
0005 * Copyright (c) 2006-2007 Oliver Bock (bock@tfh-berlin.de)
0006 *
0007 *   This driver is based on the Cypress USB Driver by Marcus Maul
0008 *   (cyport) and the 2.0 version of Greg Kroah-Hartman's
0009 *   USB Skeleton driver.
0010 *
0011 *   This is a generic driver for the Cypress CY7C63xxx family.
0012 *   For the time being it enables you to read from and write to
0013 *   the single I/O ports of the device.
0014 *
0015 *   Supported vendors:  AK Modul-Bus Computer GmbH
0016 *               (Firmware "Port-Chip")
0017 *
0018 *   Supported devices:  CY7C63001A-PC
0019 *               CY7C63001C-PXC
0020 *               CY7C63001C-SXC
0021 *
0022 *   Supported functions:    Read/Write Ports
0023 *
0024 *
0025 *   For up-to-date information please visit:
0026 *   http://www.obock.de/kernel/cypress
0027 */
0028 
0029 #include <linux/module.h>
0030 #include <linux/kernel.h>
0031 #include <linux/slab.h>
0032 #include <linux/usb.h>
0033 
0034 #define DRIVER_AUTHOR       "Oliver Bock (bock@tfh-berlin.de)"
0035 #define DRIVER_DESC     "Cypress CY7C63xxx USB driver"
0036 
0037 #define CYPRESS_VENDOR_ID   0xa2c
0038 #define CYPRESS_PRODUCT_ID  0x8
0039 
0040 #define CYPRESS_READ_PORT   0x4
0041 #define CYPRESS_WRITE_PORT  0x5
0042 
0043 #define CYPRESS_READ_RAM    0x2
0044 #define CYPRESS_WRITE_RAM   0x3
0045 #define CYPRESS_READ_ROM    0x1
0046 
0047 #define CYPRESS_READ_PORT_ID0   0
0048 #define CYPRESS_WRITE_PORT_ID0  0
0049 #define CYPRESS_READ_PORT_ID1   0x2
0050 #define CYPRESS_WRITE_PORT_ID1  1
0051 
0052 #define CYPRESS_MAX_REQSIZE 8
0053 
0054 
0055 /* table of devices that work with this driver */
0056 static const struct usb_device_id cypress_table[] = {
0057     { USB_DEVICE(CYPRESS_VENDOR_ID, CYPRESS_PRODUCT_ID) },
0058     { }
0059 };
0060 MODULE_DEVICE_TABLE(usb, cypress_table);
0061 
0062 /* structure to hold all of our device specific stuff */
0063 struct cypress {
0064     struct usb_device * udev;
0065     unsigned char       port[2];
0066 };
0067 
0068 /* used to send usb control messages to device */
0069 static int vendor_command(struct cypress *dev, unsigned char request,
0070               unsigned char address, unsigned char data)
0071 {
0072     int retval = 0;
0073     unsigned int pipe;
0074     unsigned char *iobuf;
0075 
0076     /* allocate some memory for the i/o buffer*/
0077     iobuf = kzalloc(CYPRESS_MAX_REQSIZE, GFP_KERNEL);
0078     if (!iobuf) {
0079         retval = -ENOMEM;
0080         goto error;
0081     }
0082 
0083     dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data);
0084 
0085     /* prepare usb control message and send it upstream */
0086     pipe = usb_rcvctrlpipe(dev->udev, 0);
0087     retval = usb_control_msg(dev->udev, pipe, request,
0088                  USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
0089                  address, data, iobuf, CYPRESS_MAX_REQSIZE,
0090                  USB_CTRL_GET_TIMEOUT);
0091 
0092     /* store returned data (more READs to be added) */
0093     switch (request) {
0094         case CYPRESS_READ_PORT:
0095             if (address == CYPRESS_READ_PORT_ID0) {
0096                 dev->port[0] = iobuf[1];
0097                 dev_dbg(&dev->udev->dev,
0098                     "READ_PORT0 returned: %d\n",
0099                     dev->port[0]);
0100             }
0101             else if (address == CYPRESS_READ_PORT_ID1) {
0102                 dev->port[1] = iobuf[1];
0103                 dev_dbg(&dev->udev->dev,
0104                     "READ_PORT1 returned: %d\n",
0105                     dev->port[1]);
0106             }
0107             break;
0108     }
0109 
0110     kfree(iobuf);
0111 error:
0112     return retval;
0113 }
0114 
0115 /* write port value */
0116 static ssize_t write_port(struct device *dev, struct device_attribute *attr,
0117               const char *buf, size_t count,
0118               int port_num, int write_id)
0119 {
0120     int value = -1;
0121     int result = 0;
0122 
0123     struct usb_interface *intf = to_usb_interface(dev);
0124     struct cypress *cyp = usb_get_intfdata(intf);
0125 
0126     dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", port_num);
0127 
0128     /* validate input data */
0129     if (sscanf(buf, "%d", &value) < 1) {
0130         result = -EINVAL;
0131         goto error;
0132     }
0133     if (value < 0 || value > 255) {
0134         result = -EINVAL;
0135         goto error;
0136     }
0137 
0138     result = vendor_command(cyp, CYPRESS_WRITE_PORT, write_id,
0139                 (unsigned char)value);
0140 
0141     dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
0142 error:
0143     return result < 0 ? result : count;
0144 }
0145 
0146 /* attribute callback handler (write) */
0147 static ssize_t port0_store(struct device *dev,
0148                  struct device_attribute *attr,
0149                  const char *buf, size_t count)
0150 {
0151     return write_port(dev, attr, buf, count, 0, CYPRESS_WRITE_PORT_ID0);
0152 }
0153 
0154 /* attribute callback handler (write) */
0155 static ssize_t port1_store(struct device *dev,
0156                  struct device_attribute *attr,
0157                  const char *buf, size_t count)
0158 {
0159     return write_port(dev, attr, buf, count, 1, CYPRESS_WRITE_PORT_ID1);
0160 }
0161 
0162 /* read port value */
0163 static ssize_t read_port(struct device *dev, struct device_attribute *attr,
0164              char *buf, int port_num, int read_id)
0165 {
0166     int result = 0;
0167 
0168     struct usb_interface *intf = to_usb_interface(dev);
0169     struct cypress *cyp = usb_get_intfdata(intf);
0170 
0171     dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", port_num);
0172 
0173     result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0);
0174 
0175     dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
0176 
0177     return sprintf(buf, "%d", cyp->port[port_num]);
0178 }
0179 
0180 /* attribute callback handler (read) */
0181 static ssize_t port0_show(struct device *dev,
0182                  struct device_attribute *attr, char *buf)
0183 {
0184     return read_port(dev, attr, buf, 0, CYPRESS_READ_PORT_ID0);
0185 }
0186 static DEVICE_ATTR_RW(port0);
0187 
0188 /* attribute callback handler (read) */
0189 static ssize_t port1_show(struct device *dev,
0190                  struct device_attribute *attr, char *buf)
0191 {
0192     return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1);
0193 }
0194 static DEVICE_ATTR_RW(port1);
0195 
0196 static struct attribute *cypress_attrs[] = {
0197     &dev_attr_port0.attr,
0198     &dev_attr_port1.attr,
0199     NULL,
0200 };
0201 ATTRIBUTE_GROUPS(cypress);
0202 
0203 static int cypress_probe(struct usb_interface *interface,
0204              const struct usb_device_id *id)
0205 {
0206     struct cypress *dev = NULL;
0207     int retval = -ENOMEM;
0208 
0209     /* allocate memory for our device state and initialize it */
0210     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0211     if (!dev)
0212         goto error_mem;
0213 
0214     dev->udev = usb_get_dev(interface_to_usbdev(interface));
0215 
0216     /* save our data pointer in this interface device */
0217     usb_set_intfdata(interface, dev);
0218 
0219     /* let the user know that the device is now attached */
0220     dev_info(&interface->dev,
0221          "Cypress CY7C63xxx device now attached\n");
0222     return 0;
0223 
0224 error_mem:
0225     return retval;
0226 }
0227 
0228 static void cypress_disconnect(struct usb_interface *interface)
0229 {
0230     struct cypress *dev;
0231 
0232     dev = usb_get_intfdata(interface);
0233 
0234     /* the intfdata can be set to NULL only after the
0235      * device files have been removed */
0236     usb_set_intfdata(interface, NULL);
0237 
0238     usb_put_dev(dev->udev);
0239 
0240     dev_info(&interface->dev,
0241          "Cypress CY7C63xxx device now disconnected\n");
0242 
0243     kfree(dev);
0244 }
0245 
0246 static struct usb_driver cypress_driver = {
0247     .name = "cypress_cy7c63",
0248     .probe = cypress_probe,
0249     .disconnect = cypress_disconnect,
0250     .id_table = cypress_table,
0251     .dev_groups = cypress_groups,
0252 };
0253 
0254 module_usb_driver(cypress_driver);
0255 
0256 MODULE_AUTHOR(DRIVER_AUTHOR);
0257 MODULE_DESCRIPTION(DRIVER_DESC);
0258 
0259 MODULE_LICENSE("GPL");