Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* -*- linux-c -*-
0003  * Cypress USB Thermometer driver 
0004  * 
0005  * Copyright (c) 2004 Erik Rigtorp <erkki@linux.nu> <erik@rigtorp.com>
0006  * 
0007  * This driver works with Elektor magazine USB Interface as published in 
0008  * issue #291. It should also work with the original starter kit/demo board
0009  * from Cypress.
0010  */
0011 
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/errno.h>
0015 #include <linux/slab.h>
0016 #include <linux/module.h>
0017 #include <linux/usb.h>
0018 
0019 #define DRIVER_AUTHOR "Erik Rigtorp"
0020 #define DRIVER_DESC "Cypress USB Thermometer driver"
0021 
0022 #define USB_SKEL_VENDOR_ID  0x04b4
0023 #define USB_SKEL_PRODUCT_ID 0x0002
0024 
0025 static const struct usb_device_id id_table[] = {
0026     { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
0027     { }
0028 };
0029 MODULE_DEVICE_TABLE (usb, id_table);
0030 
0031 /* Structure to hold all of our device specific stuff */
0032 struct usb_cytherm {
0033     struct usb_device    *udev;  /* save off the usb device pointer */
0034     struct usb_interface *interface; /* the interface for this device */
0035     int brightness;
0036 };
0037 
0038 
0039 /* Vendor requests */
0040 /* They all operate on one byte at a time */
0041 #define PING       0x00
0042 #define READ_ROM   0x01 /* Reads form ROM, value = address */
0043 #define READ_RAM   0x02 /* Reads form RAM, value = address */
0044 #define WRITE_RAM  0x03 /* Write to RAM, value = address, index = data */
0045 #define READ_PORT  0x04 /* Reads from port, value = address */
0046 #define WRITE_PORT 0x05 /* Write to port, value = address, index = data */ 
0047 
0048 
0049 /* Send a vendor command to device */
0050 static int vendor_command(struct usb_device *dev, unsigned char request, 
0051               unsigned char value, unsigned char index,
0052               void *buf, int size)
0053 {
0054     return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0055                    request, 
0056                    USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
0057                    value, 
0058                    index, buf, size,
0059                    USB_CTRL_GET_TIMEOUT);
0060 }
0061 
0062 
0063 
0064 #define BRIGHTNESS 0x2c     /* RAM location for brightness value */
0065 #define BRIGHTNESS_SEM 0x2b /* RAM location for brightness semaphore */
0066 
0067 static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf)
0068 {
0069     struct usb_interface *intf = to_usb_interface(dev);    
0070     struct usb_cytherm *cytherm = usb_get_intfdata(intf);     
0071 
0072     return sprintf(buf, "%i", cytherm->brightness);
0073 }
0074 
0075 static ssize_t brightness_store(struct device *dev, struct device_attribute *attr, const char *buf,
0076                   size_t count)
0077 {
0078     struct usb_interface *intf = to_usb_interface(dev);
0079     struct usb_cytherm *cytherm = usb_get_intfdata(intf);
0080 
0081     unsigned char *buffer;
0082     int retval;
0083    
0084     buffer = kmalloc(8, GFP_KERNEL);
0085     if (!buffer)
0086         return 0;
0087 
0088     cytherm->brightness = simple_strtoul(buf, NULL, 10);
0089    
0090     if (cytherm->brightness > 0xFF)
0091         cytherm->brightness = 0xFF;
0092     else if (cytherm->brightness < 0)
0093         cytherm->brightness = 0;
0094    
0095     /* Set brightness */
0096     retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS, 
0097                 cytherm->brightness, buffer, 8);
0098     if (retval)
0099         dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
0100     /* Inform µC that we have changed the brightness setting */
0101     retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS_SEM,
0102                 0x01, buffer, 8);
0103     if (retval)
0104         dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
0105    
0106     kfree(buffer);
0107    
0108     return count;
0109 }
0110 static DEVICE_ATTR_RW(brightness);
0111 
0112 
0113 #define TEMP 0x33 /* RAM location for temperature */
0114 #define SIGN 0x34 /* RAM location for temperature sign */
0115 
0116 static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf)
0117 {
0118 
0119     struct usb_interface *intf = to_usb_interface(dev);
0120     struct usb_cytherm *cytherm = usb_get_intfdata(intf);
0121 
0122     int retval;
0123     unsigned char *buffer;
0124 
0125     int temp, sign;
0126    
0127     buffer = kmalloc(8, GFP_KERNEL);
0128     if (!buffer)
0129         return 0;
0130 
0131     /* read temperature */
0132     retval = vendor_command(cytherm->udev, READ_RAM, TEMP, 0, buffer, 8);
0133     if (retval)
0134         dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
0135     temp = buffer[1];
0136    
0137     /* read sign */
0138     retval = vendor_command(cytherm->udev, READ_RAM, SIGN, 0, buffer, 8);
0139     if (retval)
0140         dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
0141     sign = buffer[1];
0142 
0143     kfree(buffer);
0144    
0145     return sprintf(buf, "%c%i.%i", sign ? '-' : '+', temp >> 1,
0146                5*(temp - ((temp >> 1) << 1)));
0147 }
0148 static DEVICE_ATTR_RO(temp);
0149 
0150 
0151 #define BUTTON 0x7a
0152 
0153 static ssize_t button_show(struct device *dev, struct device_attribute *attr, char *buf)
0154 {
0155 
0156     struct usb_interface *intf = to_usb_interface(dev);
0157     struct usb_cytherm *cytherm = usb_get_intfdata(intf);
0158 
0159     int retval;
0160     unsigned char *buffer;
0161 
0162     buffer = kmalloc(8, GFP_KERNEL);
0163     if (!buffer)
0164         return 0;
0165 
0166     /* check button */
0167     retval = vendor_command(cytherm->udev, READ_RAM, BUTTON, 0, buffer, 8);
0168     if (retval)
0169         dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
0170    
0171     retval = buffer[1];
0172 
0173     kfree(buffer);
0174 
0175     if (retval)
0176         return sprintf(buf, "1");
0177     else
0178         return sprintf(buf, "0");
0179 }
0180 static DEVICE_ATTR_RO(button);
0181 
0182 
0183 static ssize_t port0_show(struct device *dev, struct device_attribute *attr, char *buf)
0184 {
0185     struct usb_interface *intf = to_usb_interface(dev);
0186     struct usb_cytherm *cytherm = usb_get_intfdata(intf);
0187 
0188     int retval;
0189     unsigned char *buffer;
0190 
0191     buffer = kmalloc(8, GFP_KERNEL);
0192     if (!buffer)
0193         return 0;
0194 
0195     retval = vendor_command(cytherm->udev, READ_PORT, 0, 0, buffer, 8);
0196     if (retval)
0197         dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
0198 
0199     retval = buffer[1];
0200 
0201     kfree(buffer);
0202 
0203     return sprintf(buf, "%d", retval);
0204 }
0205 
0206 
0207 static ssize_t port0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
0208 {
0209     struct usb_interface *intf = to_usb_interface(dev);
0210     struct usb_cytherm *cytherm = usb_get_intfdata(intf);
0211 
0212     unsigned char *buffer;
0213     int retval;
0214     int tmp;
0215    
0216     buffer = kmalloc(8, GFP_KERNEL);
0217     if (!buffer)
0218         return 0;
0219 
0220     tmp = simple_strtoul(buf, NULL, 10);
0221    
0222     if (tmp > 0xFF)
0223         tmp = 0xFF;
0224     else if (tmp < 0)
0225         tmp = 0;
0226    
0227     retval = vendor_command(cytherm->udev, WRITE_PORT, 0,
0228                 tmp, buffer, 8);
0229     if (retval)
0230         dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
0231 
0232     kfree(buffer);
0233 
0234     return count;
0235 }
0236 static DEVICE_ATTR_RW(port0);
0237 
0238 static ssize_t port1_show(struct device *dev, struct device_attribute *attr, char *buf)
0239 {
0240     struct usb_interface *intf = to_usb_interface(dev);
0241     struct usb_cytherm *cytherm = usb_get_intfdata(intf);
0242 
0243     int retval;
0244     unsigned char *buffer;
0245 
0246     buffer = kmalloc(8, GFP_KERNEL);
0247     if (!buffer)
0248         return 0;
0249 
0250     retval = vendor_command(cytherm->udev, READ_PORT, 1, 0, buffer, 8);
0251     if (retval)
0252         dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
0253    
0254     retval = buffer[1];
0255 
0256     kfree(buffer);
0257 
0258     return sprintf(buf, "%d", retval);
0259 }
0260 
0261 
0262 static ssize_t port1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
0263 {
0264     struct usb_interface *intf = to_usb_interface(dev);
0265     struct usb_cytherm *cytherm = usb_get_intfdata(intf);
0266 
0267     unsigned char *buffer;
0268     int retval;
0269     int tmp;
0270    
0271     buffer = kmalloc(8, GFP_KERNEL);
0272     if (!buffer)
0273         return 0;
0274 
0275     tmp = simple_strtoul(buf, NULL, 10);
0276    
0277     if (tmp > 0xFF)
0278         tmp = 0xFF;
0279     else if (tmp < 0)
0280         tmp = 0;
0281    
0282     retval = vendor_command(cytherm->udev, WRITE_PORT, 1,
0283                 tmp, buffer, 8);
0284     if (retval)
0285         dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
0286 
0287     kfree(buffer);
0288 
0289     return count;
0290 }
0291 static DEVICE_ATTR_RW(port1);
0292 
0293 static struct attribute *cytherm_attrs[] = {
0294     &dev_attr_brightness.attr,
0295     &dev_attr_temp.attr,
0296     &dev_attr_button.attr,
0297     &dev_attr_port0.attr,
0298     &dev_attr_port1.attr,
0299     NULL,
0300 };
0301 ATTRIBUTE_GROUPS(cytherm);
0302 
0303 static int cytherm_probe(struct usb_interface *interface, 
0304              const struct usb_device_id *id)
0305 {
0306     struct usb_device *udev = interface_to_usbdev(interface);
0307     struct usb_cytherm *dev = NULL;
0308     int retval = -ENOMEM;
0309 
0310     dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
0311     if (!dev)
0312         goto error_mem;
0313 
0314     dev->udev = usb_get_dev(udev);
0315 
0316     usb_set_intfdata (interface, dev);
0317 
0318     dev->brightness = 0xFF;
0319 
0320     dev_info (&interface->dev,
0321           "Cypress thermometer device now attached\n");
0322     return 0;
0323 
0324 error_mem:
0325     return retval;
0326 }
0327 
0328 static void cytherm_disconnect(struct usb_interface *interface)
0329 {
0330     struct usb_cytherm *dev;
0331 
0332     dev = usb_get_intfdata (interface);
0333 
0334     /* first remove the files, then NULL the pointer */
0335     usb_set_intfdata (interface, NULL);
0336 
0337     usb_put_dev(dev->udev);
0338 
0339     kfree(dev);
0340 
0341     dev_info(&interface->dev, "Cypress thermometer now disconnected\n");
0342 }
0343 
0344 /* usb specific object needed to register this driver with the usb subsystem */
0345 static struct usb_driver cytherm_driver = {
0346     .name =     "cytherm",
0347     .probe =    cytherm_probe,
0348     .disconnect =   cytherm_disconnect,
0349     .id_table = id_table,
0350     .dev_groups =   cytherm_groups,
0351 };
0352 
0353 module_usb_driver(cytherm_driver);
0354 
0355 MODULE_AUTHOR(DRIVER_AUTHOR);
0356 MODULE_DESCRIPTION(DRIVER_DESC);
0357 MODULE_LICENSE("GPL");