18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * USB 7 Segment Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Harrison Metzger <harrisonmetz@gmail.com> 68c2ecf20Sopenharmony_ci * Based on usbled.c by Greg Kroah-Hartman (greg@kroah.com) 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci#include <linux/usb.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "Harrison Metzger <harrisonmetz@gmail.com>" 188c2ecf20Sopenharmony_ci#define DRIVER_DESC "USB 7 Segment Driver" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define VENDOR_ID 0x0fc5 218c2ecf20Sopenharmony_ci#define PRODUCT_ID 0x1227 228c2ecf20Sopenharmony_ci#define MAXLEN 8 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* table of devices that work with this driver */ 258c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table[] = { 268c2ecf20Sopenharmony_ci { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, 278c2ecf20Sopenharmony_ci { }, 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* the different text display modes the device is capable of */ 328c2ecf20Sopenharmony_cistatic const char *display_textmodes[] = {"raw", "hex", "ascii"}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct usb_sevsegdev { 358c2ecf20Sopenharmony_ci struct usb_device *udev; 368c2ecf20Sopenharmony_ci struct usb_interface *intf; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci u8 powered; 398c2ecf20Sopenharmony_ci u8 mode_msb; 408c2ecf20Sopenharmony_ci u8 mode_lsb; 418c2ecf20Sopenharmony_ci u8 decimals[MAXLEN]; 428c2ecf20Sopenharmony_ci u8 textmode; 438c2ecf20Sopenharmony_ci u8 text[MAXLEN]; 448c2ecf20Sopenharmony_ci u16 textlength; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci u8 shadow_power; /* for PM */ 478c2ecf20Sopenharmony_ci u8 has_interface_pm; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* sysfs_streq can't replace this completely 518c2ecf20Sopenharmony_ci * If the device was in hex mode, and the user wanted a 0, 528c2ecf20Sopenharmony_ci * if str commands are used, we would assume the end of string 538c2ecf20Sopenharmony_ci * so mem commands are used. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistatic inline size_t my_memlen(const char *buf, size_t count) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci if (count > 0 && buf[count-1] == '\n') 588c2ecf20Sopenharmony_ci return count - 1; 598c2ecf20Sopenharmony_ci else 608c2ecf20Sopenharmony_ci return count; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void update_display_powered(struct usb_sevsegdev *mydev) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci int rc; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (mydev->powered && !mydev->has_interface_pm) { 688c2ecf20Sopenharmony_ci rc = usb_autopm_get_interface(mydev->intf); 698c2ecf20Sopenharmony_ci if (rc < 0) 708c2ecf20Sopenharmony_ci return; 718c2ecf20Sopenharmony_ci mydev->has_interface_pm = 1; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (mydev->shadow_power != 1) 758c2ecf20Sopenharmony_ci return; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci rc = usb_control_msg(mydev->udev, 788c2ecf20Sopenharmony_ci usb_sndctrlpipe(mydev->udev, 0), 798c2ecf20Sopenharmony_ci 0x12, 808c2ecf20Sopenharmony_ci 0x48, 818c2ecf20Sopenharmony_ci (80 * 0x100) + 10, /* (power mode) */ 828c2ecf20Sopenharmony_ci (0x00 * 0x100) + (mydev->powered ? 1 : 0), 838c2ecf20Sopenharmony_ci NULL, 848c2ecf20Sopenharmony_ci 0, 858c2ecf20Sopenharmony_ci 2000); 868c2ecf20Sopenharmony_ci if (rc < 0) 878c2ecf20Sopenharmony_ci dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (!mydev->powered && mydev->has_interface_pm) { 908c2ecf20Sopenharmony_ci usb_autopm_put_interface(mydev->intf); 918c2ecf20Sopenharmony_ci mydev->has_interface_pm = 0; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void update_display_mode(struct usb_sevsegdev *mydev) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci int rc; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if(mydev->shadow_power != 1) 1008c2ecf20Sopenharmony_ci return; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci rc = usb_control_msg(mydev->udev, 1038c2ecf20Sopenharmony_ci usb_sndctrlpipe(mydev->udev, 0), 1048c2ecf20Sopenharmony_ci 0x12, 1058c2ecf20Sopenharmony_ci 0x48, 1068c2ecf20Sopenharmony_ci (82 * 0x100) + 10, /* (set mode) */ 1078c2ecf20Sopenharmony_ci (mydev->mode_msb * 0x100) + mydev->mode_lsb, 1088c2ecf20Sopenharmony_ci NULL, 1098c2ecf20Sopenharmony_ci 0, 1108c2ecf20Sopenharmony_ci 2000); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (rc < 0) 1138c2ecf20Sopenharmony_ci dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int rc; 1198c2ecf20Sopenharmony_ci int i; 1208c2ecf20Sopenharmony_ci unsigned char *buffer; 1218c2ecf20Sopenharmony_ci u8 decimals = 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if(mydev->shadow_power != 1) 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci buffer = kzalloc(MAXLEN, mf); 1278c2ecf20Sopenharmony_ci if (!buffer) 1288c2ecf20Sopenharmony_ci return; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* The device is right to left, where as you write left to right */ 1318c2ecf20Sopenharmony_ci for (i = 0; i < mydev->textlength; i++) 1328c2ecf20Sopenharmony_ci buffer[i] = mydev->text[mydev->textlength-1-i]; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci rc = usb_control_msg(mydev->udev, 1358c2ecf20Sopenharmony_ci usb_sndctrlpipe(mydev->udev, 0), 1368c2ecf20Sopenharmony_ci 0x12, 1378c2ecf20Sopenharmony_ci 0x48, 1388c2ecf20Sopenharmony_ci (85 * 0x100) + 10, /* (write text) */ 1398c2ecf20Sopenharmony_ci (0 * 0x100) + mydev->textmode, /* mode */ 1408c2ecf20Sopenharmony_ci buffer, 1418c2ecf20Sopenharmony_ci mydev->textlength, 1428c2ecf20Sopenharmony_ci 2000); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (rc < 0) 1458c2ecf20Sopenharmony_ci dev_dbg(&mydev->udev->dev, "write retval = %d\n", rc); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci kfree(buffer); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* The device is right to left, where as you write left to right */ 1508c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(mydev->decimals); i++) 1518c2ecf20Sopenharmony_ci decimals |= mydev->decimals[i] << i; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci rc = usb_control_msg(mydev->udev, 1548c2ecf20Sopenharmony_ci usb_sndctrlpipe(mydev->udev, 0), 1558c2ecf20Sopenharmony_ci 0x12, 1568c2ecf20Sopenharmony_ci 0x48, 1578c2ecf20Sopenharmony_ci (86 * 0x100) + 10, /* (set decimal) */ 1588c2ecf20Sopenharmony_ci (0 * 0x100) + decimals, /* decimals */ 1598c2ecf20Sopenharmony_ci NULL, 1608c2ecf20Sopenharmony_ci 0, 1618c2ecf20Sopenharmony_ci 2000); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (rc < 0) 1648c2ecf20Sopenharmony_ci dev_dbg(&mydev->udev->dev, "decimal retval = %d\n", rc); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci#define MYDEV_ATTR_SIMPLE_UNSIGNED(name, update_fcn) \ 1688c2ecf20Sopenharmony_cistatic ssize_t name##_show(struct device *dev, \ 1698c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) \ 1708c2ecf20Sopenharmony_ci{ \ 1718c2ecf20Sopenharmony_ci struct usb_interface *intf = to_usb_interface(dev); \ 1728c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ 1738c2ecf20Sopenharmony_ci \ 1748c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", mydev->name); \ 1758c2ecf20Sopenharmony_ci} \ 1768c2ecf20Sopenharmony_ci \ 1778c2ecf20Sopenharmony_cistatic ssize_t name##_store(struct device *dev, \ 1788c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) \ 1798c2ecf20Sopenharmony_ci{ \ 1808c2ecf20Sopenharmony_ci struct usb_interface *intf = to_usb_interface(dev); \ 1818c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ 1828c2ecf20Sopenharmony_ci \ 1838c2ecf20Sopenharmony_ci mydev->name = simple_strtoul(buf, NULL, 10); \ 1848c2ecf20Sopenharmony_ci update_fcn(mydev); \ 1858c2ecf20Sopenharmony_ci \ 1868c2ecf20Sopenharmony_ci return count; \ 1878c2ecf20Sopenharmony_ci} \ 1888c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(name); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic ssize_t text_show(struct device *dev, 1918c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct usb_interface *intf = to_usb_interface(dev); 1948c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return snprintf(buf, mydev->textlength, "%s\n", mydev->text); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic ssize_t text_store(struct device *dev, 2008c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct usb_interface *intf = to_usb_interface(dev); 2038c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 2048c2ecf20Sopenharmony_ci size_t end = my_memlen(buf, count); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (end > sizeof(mydev->text)) 2078c2ecf20Sopenharmony_ci return -EINVAL; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci memset(mydev->text, 0, sizeof(mydev->text)); 2108c2ecf20Sopenharmony_ci mydev->textlength = end; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (end > 0) 2138c2ecf20Sopenharmony_ci memcpy(mydev->text, buf, end); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci update_display_visual(mydev, GFP_KERNEL); 2168c2ecf20Sopenharmony_ci return count; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(text); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic ssize_t decimals_show(struct device *dev, 2228c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct usb_interface *intf = to_usb_interface(dev); 2258c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 2268c2ecf20Sopenharmony_ci int i; 2278c2ecf20Sopenharmony_ci int pos; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(mydev->decimals); i++) { 2308c2ecf20Sopenharmony_ci pos = sizeof(mydev->decimals) - 1 - i; 2318c2ecf20Sopenharmony_ci if (mydev->decimals[i] == 0) 2328c2ecf20Sopenharmony_ci buf[pos] = '0'; 2338c2ecf20Sopenharmony_ci else if (mydev->decimals[i] == 1) 2348c2ecf20Sopenharmony_ci buf[pos] = '1'; 2358c2ecf20Sopenharmony_ci else 2368c2ecf20Sopenharmony_ci buf[pos] = 'x'; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci buf[sizeof(mydev->decimals)] = '\n'; 2408c2ecf20Sopenharmony_ci return sizeof(mydev->decimals) + 1; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic ssize_t decimals_store(struct device *dev, 2448c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct usb_interface *intf = to_usb_interface(dev); 2478c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 2488c2ecf20Sopenharmony_ci size_t end = my_memlen(buf, count); 2498c2ecf20Sopenharmony_ci int i; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (end > sizeof(mydev->decimals)) 2528c2ecf20Sopenharmony_ci return -EINVAL; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci for (i = 0; i < end; i++) 2558c2ecf20Sopenharmony_ci if (buf[i] != '0' && buf[i] != '1') 2568c2ecf20Sopenharmony_ci return -EINVAL; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci memset(mydev->decimals, 0, sizeof(mydev->decimals)); 2598c2ecf20Sopenharmony_ci for (i = 0; i < end; i++) 2608c2ecf20Sopenharmony_ci if (buf[i] == '1') 2618c2ecf20Sopenharmony_ci mydev->decimals[end-1-i] = 1; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci update_display_visual(mydev, GFP_KERNEL); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return count; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(decimals); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic ssize_t textmode_show(struct device *dev, 2718c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct usb_interface *intf = to_usb_interface(dev); 2748c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 2758c2ecf20Sopenharmony_ci int i; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci buf[0] = 0; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(display_textmodes); i++) { 2808c2ecf20Sopenharmony_ci if (mydev->textmode == i) { 2818c2ecf20Sopenharmony_ci strcat(buf, " ["); 2828c2ecf20Sopenharmony_ci strcat(buf, display_textmodes[i]); 2838c2ecf20Sopenharmony_ci strcat(buf, "] "); 2848c2ecf20Sopenharmony_ci } else { 2858c2ecf20Sopenharmony_ci strcat(buf, " "); 2868c2ecf20Sopenharmony_ci strcat(buf, display_textmodes[i]); 2878c2ecf20Sopenharmony_ci strcat(buf, " "); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci strcat(buf, "\n"); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return strlen(buf); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic ssize_t textmode_store(struct device *dev, 2978c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct usb_interface *intf = to_usb_interface(dev); 3008c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 3018c2ecf20Sopenharmony_ci int i; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci i = sysfs_match_string(display_textmodes, buf); 3048c2ecf20Sopenharmony_ci if (i < 0) 3058c2ecf20Sopenharmony_ci return i; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci mydev->textmode = i; 3088c2ecf20Sopenharmony_ci update_display_visual(mydev, GFP_KERNEL); 3098c2ecf20Sopenharmony_ci return count; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(textmode); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ciMYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered); 3168c2ecf20Sopenharmony_ciMYDEV_ATTR_SIMPLE_UNSIGNED(mode_msb, update_display_mode); 3178c2ecf20Sopenharmony_ciMYDEV_ATTR_SIMPLE_UNSIGNED(mode_lsb, update_display_mode); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic struct attribute *sevseg_attrs[] = { 3208c2ecf20Sopenharmony_ci &dev_attr_powered.attr, 3218c2ecf20Sopenharmony_ci &dev_attr_text.attr, 3228c2ecf20Sopenharmony_ci &dev_attr_textmode.attr, 3238c2ecf20Sopenharmony_ci &dev_attr_decimals.attr, 3248c2ecf20Sopenharmony_ci &dev_attr_mode_msb.attr, 3258c2ecf20Sopenharmony_ci &dev_attr_mode_lsb.attr, 3268c2ecf20Sopenharmony_ci NULL 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(sevseg); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int sevseg_probe(struct usb_interface *interface, 3318c2ecf20Sopenharmony_ci const struct usb_device_id *id) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(interface); 3348c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev = NULL; 3358c2ecf20Sopenharmony_ci int rc = -ENOMEM; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci mydev = kzalloc(sizeof(struct usb_sevsegdev), GFP_KERNEL); 3388c2ecf20Sopenharmony_ci if (!mydev) 3398c2ecf20Sopenharmony_ci goto error_mem; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci mydev->udev = usb_get_dev(udev); 3428c2ecf20Sopenharmony_ci mydev->intf = interface; 3438c2ecf20Sopenharmony_ci usb_set_intfdata(interface, mydev); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* PM */ 3468c2ecf20Sopenharmony_ci mydev->shadow_power = 1; /* currently active */ 3478c2ecf20Sopenharmony_ci mydev->has_interface_pm = 0; /* have not issued autopm_get */ 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /*set defaults */ 3508c2ecf20Sopenharmony_ci mydev->textmode = 0x02; /* ascii mode */ 3518c2ecf20Sopenharmony_ci mydev->mode_msb = 0x06; /* 6 characters */ 3528c2ecf20Sopenharmony_ci mydev->mode_lsb = 0x3f; /* scanmode for 6 chars */ 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci dev_info(&interface->dev, "USB 7 Segment device now attached\n"); 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cierror_mem: 3588c2ecf20Sopenharmony_ci return rc; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic void sevseg_disconnect(struct usb_interface *interface) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci mydev = usb_get_intfdata(interface); 3668c2ecf20Sopenharmony_ci usb_set_intfdata(interface, NULL); 3678c2ecf20Sopenharmony_ci usb_put_dev(mydev->udev); 3688c2ecf20Sopenharmony_ci kfree(mydev); 3698c2ecf20Sopenharmony_ci dev_info(&interface->dev, "USB 7 Segment now disconnected\n"); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int sevseg_suspend(struct usb_interface *intf, pm_message_t message) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci mydev = usb_get_intfdata(intf); 3778c2ecf20Sopenharmony_ci mydev->shadow_power = 0; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic int sevseg_resume(struct usb_interface *intf) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci mydev = usb_get_intfdata(intf); 3878c2ecf20Sopenharmony_ci mydev->shadow_power = 1; 3888c2ecf20Sopenharmony_ci update_display_mode(mydev); 3898c2ecf20Sopenharmony_ci update_display_visual(mydev, GFP_NOIO); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic int sevseg_reset_resume(struct usb_interface *intf) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct usb_sevsegdev *mydev; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci mydev = usb_get_intfdata(intf); 3998c2ecf20Sopenharmony_ci mydev->shadow_power = 1; 4008c2ecf20Sopenharmony_ci update_display_mode(mydev); 4018c2ecf20Sopenharmony_ci update_display_visual(mydev, GFP_NOIO); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic struct usb_driver sevseg_driver = { 4078c2ecf20Sopenharmony_ci .name = "usbsevseg", 4088c2ecf20Sopenharmony_ci .probe = sevseg_probe, 4098c2ecf20Sopenharmony_ci .disconnect = sevseg_disconnect, 4108c2ecf20Sopenharmony_ci .suspend = sevseg_suspend, 4118c2ecf20Sopenharmony_ci .resume = sevseg_resume, 4128c2ecf20Sopenharmony_ci .reset_resume = sevseg_reset_resume, 4138c2ecf20Sopenharmony_ci .id_table = id_table, 4148c2ecf20Sopenharmony_ci .dev_groups = sevseg_groups, 4158c2ecf20Sopenharmony_ci .supports_autosuspend = 1, 4168c2ecf20Sopenharmony_ci}; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cimodule_usb_driver(sevseg_driver); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 4218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 4228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 423