usbsevseg.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * USB 7 Segment Driver
  4. *
  5. * Copyright (C) 2008 Harrison Metzger <[email protected]>
  6. * Based on usbled.c by Greg Kroah-Hartman ([email protected])
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/errno.h>
  10. #include <linux/slab.h>
  11. #include <linux/module.h>
  12. #include <linux/string.h>
  13. #include <linux/usb.h>
  14. #define DRIVER_AUTHOR "Harrison Metzger <[email protected]>"
  15. #define DRIVER_DESC "USB 7 Segment Driver"
  16. #define VENDOR_ID 0x0fc5
  17. #define PRODUCT_ID 0x1227
  18. #define MAXLEN 8
  19. /* table of devices that work with this driver */
  20. static const struct usb_device_id id_table[] = {
  21. { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
  22. { },
  23. };
  24. MODULE_DEVICE_TABLE(usb, id_table);
  25. /* the different text display modes the device is capable of */
  26. static const char *display_textmodes[] = {"raw", "hex", "ascii"};
  27. struct usb_sevsegdev {
  28. struct usb_device *udev;
  29. struct usb_interface *intf;
  30. u8 powered;
  31. u8 mode_msb;
  32. u8 mode_lsb;
  33. u8 decimals[MAXLEN];
  34. u8 textmode;
  35. u8 text[MAXLEN];
  36. u16 textlength;
  37. u8 shadow_power; /* for PM */
  38. u8 has_interface_pm;
  39. };
  40. /* sysfs_streq can't replace this completely
  41. * If the device was in hex mode, and the user wanted a 0,
  42. * if str commands are used, we would assume the end of string
  43. * so mem commands are used.
  44. */
  45. static inline size_t my_memlen(const char *buf, size_t count)
  46. {
  47. if (count > 0 && buf[count-1] == '\n')
  48. return count - 1;
  49. else
  50. return count;
  51. }
  52. static void update_display_powered(struct usb_sevsegdev *mydev)
  53. {
  54. int rc;
  55. if (mydev->powered && !mydev->has_interface_pm) {
  56. rc = usb_autopm_get_interface(mydev->intf);
  57. if (rc < 0)
  58. return;
  59. mydev->has_interface_pm = 1;
  60. }
  61. if (mydev->shadow_power != 1)
  62. return;
  63. rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48,
  64. (80 * 0x100) + 10, /* (power mode) */
  65. (0x00 * 0x100) + (mydev->powered ? 1 : 0),
  66. NULL, 0, 2000, GFP_KERNEL);
  67. if (rc < 0)
  68. dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc);
  69. if (!mydev->powered && mydev->has_interface_pm) {
  70. usb_autopm_put_interface(mydev->intf);
  71. mydev->has_interface_pm = 0;
  72. }
  73. }
  74. static void update_display_mode(struct usb_sevsegdev *mydev)
  75. {
  76. int rc;
  77. if(mydev->shadow_power != 1)
  78. return;
  79. rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48,
  80. (82 * 0x100) + 10, /* (set mode) */
  81. (mydev->mode_msb * 0x100) + mydev->mode_lsb,
  82. NULL, 0, 2000, GFP_NOIO);
  83. if (rc < 0)
  84. dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc);
  85. }
  86. static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf)
  87. {
  88. int rc;
  89. int i;
  90. unsigned char buffer[MAXLEN] = {0};
  91. u8 decimals = 0;
  92. if(mydev->shadow_power != 1)
  93. return;
  94. /* The device is right to left, where as you write left to right */
  95. for (i = 0; i < mydev->textlength; i++)
  96. buffer[i] = mydev->text[mydev->textlength-1-i];
  97. rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48,
  98. (85 * 0x100) + 10, /* (write text) */
  99. (0 * 0x100) + mydev->textmode, /* mode */
  100. &buffer, mydev->textlength, 2000, mf);
  101. if (rc < 0)
  102. dev_dbg(&mydev->udev->dev, "write retval = %d\n", rc);
  103. /* The device is right to left, where as you write left to right */
  104. for (i = 0; i < sizeof(mydev->decimals); i++)
  105. decimals |= mydev->decimals[i] << i;
  106. rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48,
  107. (86 * 0x100) + 10, /* (set decimal) */
  108. (0 * 0x100) + decimals, /* decimals */
  109. NULL, 0, 2000, mf);
  110. if (rc < 0)
  111. dev_dbg(&mydev->udev->dev, "decimal retval = %d\n", rc);
  112. }
  113. #define MYDEV_ATTR_SIMPLE_UNSIGNED(name, update_fcn) \
  114. static ssize_t name##_show(struct device *dev, \
  115. struct device_attribute *attr, char *buf) \
  116. { \
  117. struct usb_interface *intf = to_usb_interface(dev); \
  118. struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \
  119. \
  120. return sprintf(buf, "%u\n", mydev->name); \
  121. } \
  122. \
  123. static ssize_t name##_store(struct device *dev, \
  124. struct device_attribute *attr, const char *buf, size_t count) \
  125. { \
  126. struct usb_interface *intf = to_usb_interface(dev); \
  127. struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \
  128. \
  129. mydev->name = simple_strtoul(buf, NULL, 10); \
  130. update_fcn(mydev); \
  131. \
  132. return count; \
  133. } \
  134. static DEVICE_ATTR_RW(name);
  135. static ssize_t text_show(struct device *dev,
  136. struct device_attribute *attr, char *buf)
  137. {
  138. struct usb_interface *intf = to_usb_interface(dev);
  139. struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
  140. return sysfs_emit(buf, "%s\n", mydev->text);
  141. }
  142. static ssize_t text_store(struct device *dev,
  143. struct device_attribute *attr, const char *buf, size_t count)
  144. {
  145. struct usb_interface *intf = to_usb_interface(dev);
  146. struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
  147. size_t end = my_memlen(buf, count);
  148. if (end > sizeof(mydev->text))
  149. return -EINVAL;
  150. memset(mydev->text, 0, sizeof(mydev->text));
  151. mydev->textlength = end;
  152. if (end > 0)
  153. memcpy(mydev->text, buf, end);
  154. update_display_visual(mydev, GFP_KERNEL);
  155. return count;
  156. }
  157. static DEVICE_ATTR_RW(text);
  158. static ssize_t decimals_show(struct device *dev,
  159. struct device_attribute *attr, char *buf)
  160. {
  161. struct usb_interface *intf = to_usb_interface(dev);
  162. struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
  163. int i;
  164. int pos;
  165. for (i = 0; i < sizeof(mydev->decimals); i++) {
  166. pos = sizeof(mydev->decimals) - 1 - i;
  167. if (mydev->decimals[i] == 0)
  168. buf[pos] = '0';
  169. else if (mydev->decimals[i] == 1)
  170. buf[pos] = '1';
  171. else
  172. buf[pos] = 'x';
  173. }
  174. buf[sizeof(mydev->decimals)] = '\n';
  175. return sizeof(mydev->decimals) + 1;
  176. }
  177. static ssize_t decimals_store(struct device *dev,
  178. struct device_attribute *attr, const char *buf, size_t count)
  179. {
  180. struct usb_interface *intf = to_usb_interface(dev);
  181. struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
  182. size_t end = my_memlen(buf, count);
  183. int i;
  184. if (end > sizeof(mydev->decimals))
  185. return -EINVAL;
  186. for (i = 0; i < end; i++)
  187. if (buf[i] != '0' && buf[i] != '1')
  188. return -EINVAL;
  189. memset(mydev->decimals, 0, sizeof(mydev->decimals));
  190. for (i = 0; i < end; i++)
  191. if (buf[i] == '1')
  192. mydev->decimals[end-1-i] = 1;
  193. update_display_visual(mydev, GFP_KERNEL);
  194. return count;
  195. }
  196. static DEVICE_ATTR_RW(decimals);
  197. static ssize_t textmode_show(struct device *dev,
  198. struct device_attribute *attr, char *buf)
  199. {
  200. struct usb_interface *intf = to_usb_interface(dev);
  201. struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
  202. int i;
  203. buf[0] = 0;
  204. for (i = 0; i < ARRAY_SIZE(display_textmodes); i++) {
  205. if (mydev->textmode == i) {
  206. strcat(buf, " [");
  207. strcat(buf, display_textmodes[i]);
  208. strcat(buf, "] ");
  209. } else {
  210. strcat(buf, " ");
  211. strcat(buf, display_textmodes[i]);
  212. strcat(buf, " ");
  213. }
  214. }
  215. strcat(buf, "\n");
  216. return strlen(buf);
  217. }
  218. static ssize_t textmode_store(struct device *dev,
  219. struct device_attribute *attr, const char *buf, size_t count)
  220. {
  221. struct usb_interface *intf = to_usb_interface(dev);
  222. struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
  223. int i;
  224. i = sysfs_match_string(display_textmodes, buf);
  225. if (i < 0)
  226. return i;
  227. mydev->textmode = i;
  228. update_display_visual(mydev, GFP_KERNEL);
  229. return count;
  230. }
  231. static DEVICE_ATTR_RW(textmode);
  232. MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered);
  233. MYDEV_ATTR_SIMPLE_UNSIGNED(mode_msb, update_display_mode);
  234. MYDEV_ATTR_SIMPLE_UNSIGNED(mode_lsb, update_display_mode);
  235. static struct attribute *sevseg_attrs[] = {
  236. &dev_attr_powered.attr,
  237. &dev_attr_text.attr,
  238. &dev_attr_textmode.attr,
  239. &dev_attr_decimals.attr,
  240. &dev_attr_mode_msb.attr,
  241. &dev_attr_mode_lsb.attr,
  242. NULL
  243. };
  244. ATTRIBUTE_GROUPS(sevseg);
  245. static int sevseg_probe(struct usb_interface *interface,
  246. const struct usb_device_id *id)
  247. {
  248. struct usb_device *udev = interface_to_usbdev(interface);
  249. struct usb_sevsegdev *mydev = NULL;
  250. int rc = -ENOMEM;
  251. mydev = kzalloc(sizeof(struct usb_sevsegdev), GFP_KERNEL);
  252. if (!mydev)
  253. goto error_mem;
  254. mydev->udev = usb_get_dev(udev);
  255. mydev->intf = interface;
  256. usb_set_intfdata(interface, mydev);
  257. /* PM */
  258. mydev->shadow_power = 1; /* currently active */
  259. mydev->has_interface_pm = 0; /* have not issued autopm_get */
  260. /*set defaults */
  261. mydev->textmode = 0x02; /* ascii mode */
  262. mydev->mode_msb = 0x06; /* 6 characters */
  263. mydev->mode_lsb = 0x3f; /* scanmode for 6 chars */
  264. dev_info(&interface->dev, "USB 7 Segment device now attached\n");
  265. return 0;
  266. error_mem:
  267. return rc;
  268. }
  269. static void sevseg_disconnect(struct usb_interface *interface)
  270. {
  271. struct usb_sevsegdev *mydev;
  272. mydev = usb_get_intfdata(interface);
  273. usb_set_intfdata(interface, NULL);
  274. usb_put_dev(mydev->udev);
  275. kfree(mydev);
  276. dev_info(&interface->dev, "USB 7 Segment now disconnected\n");
  277. }
  278. static int sevseg_suspend(struct usb_interface *intf, pm_message_t message)
  279. {
  280. struct usb_sevsegdev *mydev;
  281. mydev = usb_get_intfdata(intf);
  282. mydev->shadow_power = 0;
  283. return 0;
  284. }
  285. static int sevseg_resume(struct usb_interface *intf)
  286. {
  287. struct usb_sevsegdev *mydev;
  288. mydev = usb_get_intfdata(intf);
  289. mydev->shadow_power = 1;
  290. update_display_mode(mydev);
  291. update_display_visual(mydev, GFP_NOIO);
  292. return 0;
  293. }
  294. static int sevseg_reset_resume(struct usb_interface *intf)
  295. {
  296. struct usb_sevsegdev *mydev;
  297. mydev = usb_get_intfdata(intf);
  298. mydev->shadow_power = 1;
  299. update_display_mode(mydev);
  300. update_display_visual(mydev, GFP_NOIO);
  301. return 0;
  302. }
  303. static struct usb_driver sevseg_driver = {
  304. .name = "usbsevseg",
  305. .probe = sevseg_probe,
  306. .disconnect = sevseg_disconnect,
  307. .suspend = sevseg_suspend,
  308. .resume = sevseg_resume,
  309. .reset_resume = sevseg_reset_resume,
  310. .id_table = id_table,
  311. .dev_groups = sevseg_groups,
  312. .supports_autosuspend = 1,
  313. };
  314. module_usb_driver(sevseg_driver);
  315. MODULE_AUTHOR(DRIVER_AUTHOR);
  316. MODULE_DESCRIPTION(DRIVER_DESC);
  317. MODULE_LICENSE("GPL");