lirc_sasem.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. /*
  2. * lirc_sasem.c - USB remote support for LIRC
  3. * Version 0.5
  4. *
  5. * Copyright (C) 2004-2005 Oliver Stabel <oliver.stabel@gmx.de>
  6. * Tim Davies <tim@opensystems.net.au>
  7. *
  8. * This driver was derived from:
  9. * Venky Raju <dev@venky.ws>
  10. * "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD"
  11. * Paul Miller <pmiller9@users.sourceforge.net>'s 2003-2004
  12. * "lirc_atiusb - USB remote support for LIRC"
  13. * Culver Consulting Services <henry@culcon.com>'s 2003
  14. * "Sasem OnAir VFD/IR USB driver"
  15. *
  16. *
  17. * NOTE - The LCDproc iMon driver should work with this module. More info at
  18. * http://www.frogstorm.info/sasem
  19. */
  20. /*
  21. * This program is free software; you can redistribute it and/or modify
  22. * it under the terms of the GNU General Public License as published by
  23. * the Free Software Foundation; either version 2 of the License, or
  24. * (at your option) any later version.
  25. *
  26. * This program is distributed in the hope that it will be useful,
  27. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29. * GNU General Public License for more details.
  30. *
  31. * You should have received a copy of the GNU General Public License
  32. * along with this program; if not, write to the Free Software
  33. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  34. */
  35. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  36. #include <linux/errno.h>
  37. #include <linux/kernel.h>
  38. #include <linux/module.h>
  39. #include <linux/slab.h>
  40. #include <linux/uaccess.h>
  41. #include <linux/usb.h>
  42. #include <media/lirc.h>
  43. #include <media/lirc_dev.h>
  44. #define MOD_AUTHOR "Oliver Stabel <oliver.stabel@gmx.de>, " \
  45. "Tim Davies <tim@opensystems.net.au>"
  46. #define MOD_DESC "USB Driver for Sasem Remote Controller V1.1"
  47. #define MOD_NAME "lirc_sasem"
  48. #define MOD_VERSION "0.5"
  49. #define VFD_MINOR_BASE 144 /* Same as LCD */
  50. #define DEVICE_NAME "lcd%d"
  51. #define BUF_CHUNK_SIZE 8
  52. #define BUF_SIZE 128
  53. #define IOCTL_LCD_CONTRAST 1
  54. /*** P R O T O T Y P E S ***/
  55. /* USB Callback prototypes */
  56. static int sasem_probe(struct usb_interface *interface,
  57. const struct usb_device_id *id);
  58. static void sasem_disconnect(struct usb_interface *interface);
  59. static void usb_rx_callback(struct urb *urb);
  60. static void usb_tx_callback(struct urb *urb);
  61. /* VFD file_operations function prototypes */
  62. static int vfd_open(struct inode *inode, struct file *file);
  63. static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg);
  64. static int vfd_close(struct inode *inode, struct file *file);
  65. static ssize_t vfd_write(struct file *file, const char __user *buf,
  66. size_t n_bytes, loff_t *pos);
  67. /* LIRC driver function prototypes */
  68. static int ir_open(void *data);
  69. static void ir_close(void *data);
  70. /*** G L O B A L S ***/
  71. #define SASEM_DATA_BUF_SZ 32
  72. struct sasem_context {
  73. struct usb_device *dev;
  74. int vfd_isopen; /* VFD port has been opened */
  75. unsigned int vfd_contrast; /* VFD contrast */
  76. int ir_isopen; /* IR port has been opened */
  77. int dev_present; /* USB device presence */
  78. struct mutex ctx_lock; /* to lock this object */
  79. wait_queue_head_t remove_ok; /* For unexpected USB disconnects */
  80. struct lirc_driver *driver;
  81. struct usb_endpoint_descriptor *rx_endpoint;
  82. struct usb_endpoint_descriptor *tx_endpoint;
  83. struct urb *rx_urb;
  84. struct urb *tx_urb;
  85. unsigned char usb_rx_buf[8];
  86. unsigned char usb_tx_buf[8];
  87. struct tx_t {
  88. unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data
  89. * buffer */
  90. struct completion finished; /* wait for write to finish */
  91. atomic_t busy; /* write in progress */
  92. int status; /* status of tx completion */
  93. } tx;
  94. /* for dealing with repeat codes (wish there was a toggle bit!) */
  95. struct timeval presstime;
  96. char lastcode[8];
  97. int codesaved;
  98. };
  99. /* VFD file operations */
  100. static const struct file_operations vfd_fops = {
  101. .owner = THIS_MODULE,
  102. .open = &vfd_open,
  103. .write = vfd_write,
  104. .unlocked_ioctl = &vfd_ioctl,
  105. .release = &vfd_close,
  106. .llseek = noop_llseek,
  107. };
  108. /* USB Device ID for Sasem USB Control Board */
  109. static struct usb_device_id sasem_usb_id_table[] = {
  110. /* Sasem USB Control Board */
  111. { USB_DEVICE(0x11ba, 0x0101) },
  112. /* Terminating entry */
  113. {}
  114. };
  115. /* USB Device data */
  116. static struct usb_driver sasem_driver = {
  117. .name = MOD_NAME,
  118. .probe = sasem_probe,
  119. .disconnect = sasem_disconnect,
  120. .id_table = sasem_usb_id_table,
  121. };
  122. static struct usb_class_driver sasem_class = {
  123. .name = DEVICE_NAME,
  124. .fops = &vfd_fops,
  125. .minor_base = VFD_MINOR_BASE,
  126. };
  127. /* to prevent races between open() and disconnect() */
  128. static DEFINE_MUTEX(disconnect_lock);
  129. static int debug;
  130. /*** M O D U L E C O D E ***/
  131. MODULE_AUTHOR(MOD_AUTHOR);
  132. MODULE_DESCRIPTION(MOD_DESC);
  133. MODULE_LICENSE("GPL");
  134. module_param(debug, int, S_IRUGO | S_IWUSR);
  135. MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
  136. static void delete_context(struct sasem_context *context)
  137. {
  138. usb_free_urb(context->tx_urb); /* VFD */
  139. usb_free_urb(context->rx_urb); /* IR */
  140. lirc_buffer_free(context->driver->rbuf);
  141. kfree(context->driver->rbuf);
  142. kfree(context->driver);
  143. kfree(context);
  144. }
  145. static void deregister_from_lirc(struct sasem_context *context)
  146. {
  147. int retval;
  148. int minor = context->driver->minor;
  149. retval = lirc_unregister_driver(minor);
  150. if (retval)
  151. dev_err(&context->dev->dev,
  152. "%s: unable to deregister from lirc (%d)\n",
  153. __func__, retval);
  154. else
  155. dev_info(&context->dev->dev,
  156. "Deregistered Sasem driver (minor:%d)\n", minor);
  157. }
  158. /**
  159. * Called when the VFD device (e.g. /dev/usb/lcd)
  160. * is opened by the application.
  161. */
  162. static int vfd_open(struct inode *inode, struct file *file)
  163. {
  164. struct usb_interface *interface;
  165. struct sasem_context *context = NULL;
  166. int subminor;
  167. int retval = 0;
  168. /* prevent races with disconnect */
  169. mutex_lock(&disconnect_lock);
  170. subminor = iminor(inode);
  171. interface = usb_find_interface(&sasem_driver, subminor);
  172. if (!interface) {
  173. pr_err("%s: could not find interface for minor %d\n",
  174. __func__, subminor);
  175. retval = -ENODEV;
  176. goto exit;
  177. }
  178. context = usb_get_intfdata(interface);
  179. if (!context) {
  180. dev_err(&interface->dev, "no context found for minor %d\n",
  181. subminor);
  182. retval = -ENODEV;
  183. goto exit;
  184. }
  185. mutex_lock(&context->ctx_lock);
  186. if (context->vfd_isopen) {
  187. dev_err(&interface->dev,
  188. "%s: VFD port is already open", __func__);
  189. retval = -EBUSY;
  190. } else {
  191. context->vfd_isopen = 1;
  192. file->private_data = context;
  193. dev_info(&interface->dev, "VFD port opened\n");
  194. }
  195. mutex_unlock(&context->ctx_lock);
  196. exit:
  197. mutex_unlock(&disconnect_lock);
  198. return retval;
  199. }
  200. /**
  201. * Called when the VFD device (e.g. /dev/usb/lcd)
  202. * is closed by the application.
  203. */
  204. static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg)
  205. {
  206. struct sasem_context *context;
  207. context = (struct sasem_context *) file->private_data;
  208. if (!context) {
  209. pr_err("%s: no context for device\n", __func__);
  210. return -ENODEV;
  211. }
  212. mutex_lock(&context->ctx_lock);
  213. switch (cmd) {
  214. case IOCTL_LCD_CONTRAST:
  215. if (arg > 1000)
  216. arg = 1000;
  217. context->vfd_contrast = (unsigned int)arg;
  218. break;
  219. default:
  220. pr_info("Unknown IOCTL command\n");
  221. mutex_unlock(&context->ctx_lock);
  222. return -ENOIOCTLCMD; /* not supported */
  223. }
  224. mutex_unlock(&context->ctx_lock);
  225. return 0;
  226. }
  227. /**
  228. * Called when the VFD device (e.g. /dev/usb/lcd)
  229. * is closed by the application.
  230. */
  231. static int vfd_close(struct inode *inode, struct file *file)
  232. {
  233. struct sasem_context *context = NULL;
  234. int retval = 0;
  235. context = (struct sasem_context *) file->private_data;
  236. if (!context) {
  237. pr_err("%s: no context for device\n", __func__);
  238. return -ENODEV;
  239. }
  240. mutex_lock(&context->ctx_lock);
  241. if (!context->vfd_isopen) {
  242. dev_err(&context->dev->dev, "%s: VFD is not open\n", __func__);
  243. retval = -EIO;
  244. } else {
  245. context->vfd_isopen = 0;
  246. dev_info(&context->dev->dev, "VFD port closed\n");
  247. if (!context->dev_present && !context->ir_isopen) {
  248. /* Device disconnected before close and IR port is
  249. * not open. If IR port is open, context will be
  250. * deleted by ir_close. */
  251. mutex_unlock(&context->ctx_lock);
  252. delete_context(context);
  253. return retval;
  254. }
  255. }
  256. mutex_unlock(&context->ctx_lock);
  257. return retval;
  258. }
  259. /**
  260. * Sends a packet to the VFD.
  261. */
  262. static int send_packet(struct sasem_context *context)
  263. {
  264. unsigned int pipe;
  265. int interval = 0;
  266. int retval = 0;
  267. pipe = usb_sndintpipe(context->dev,
  268. context->tx_endpoint->bEndpointAddress);
  269. interval = context->tx_endpoint->bInterval;
  270. usb_fill_int_urb(context->tx_urb, context->dev, pipe,
  271. context->usb_tx_buf, sizeof(context->usb_tx_buf),
  272. usb_tx_callback, context, interval);
  273. context->tx_urb->actual_length = 0;
  274. init_completion(&context->tx.finished);
  275. atomic_set(&context->tx.busy, 1);
  276. retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
  277. if (retval) {
  278. atomic_set(&context->tx.busy, 0);
  279. dev_err(&context->dev->dev, "error submitting urb (%d)\n",
  280. retval);
  281. } else {
  282. /* Wait for transmission to complete (or abort) */
  283. mutex_unlock(&context->ctx_lock);
  284. wait_for_completion(&context->tx.finished);
  285. mutex_lock(&context->ctx_lock);
  286. retval = context->tx.status;
  287. if (retval)
  288. dev_err(&context->dev->dev,
  289. "packet tx failed (%d)\n", retval);
  290. }
  291. return retval;
  292. }
  293. /**
  294. * Writes data to the VFD. The Sasem VFD is 2x16 characters
  295. * and requires data in 9 consecutive USB interrupt packets,
  296. * each packet carrying 8 bytes.
  297. */
  298. static ssize_t vfd_write(struct file *file, const char __user *buf,
  299. size_t n_bytes, loff_t *pos)
  300. {
  301. int i;
  302. int retval = 0;
  303. struct sasem_context *context;
  304. int *data_buf = NULL;
  305. context = (struct sasem_context *) file->private_data;
  306. if (!context) {
  307. pr_err("%s: no context for device\n", __func__);
  308. return -ENODEV;
  309. }
  310. mutex_lock(&context->ctx_lock);
  311. if (!context->dev_present) {
  312. pr_err("%s: no Sasem device present\n", __func__);
  313. retval = -ENODEV;
  314. goto exit;
  315. }
  316. if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
  317. dev_err(&context->dev->dev, "%s: invalid payload size\n",
  318. __func__);
  319. retval = -EINVAL;
  320. goto exit;
  321. }
  322. data_buf = memdup_user(buf, n_bytes);
  323. if (IS_ERR(data_buf)) {
  324. retval = PTR_ERR(data_buf);
  325. data_buf = NULL;
  326. goto exit;
  327. }
  328. memcpy(context->tx.data_buf, data_buf, n_bytes);
  329. /* Pad with spaces */
  330. for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i)
  331. context->tx.data_buf[i] = ' ';
  332. /* Nine 8 byte packets to be sent */
  333. /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0"
  334. * will clear the VFD */
  335. for (i = 0; i < 9; i++) {
  336. switch (i) {
  337. case 0:
  338. memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8);
  339. context->usb_tx_buf[1] = (context->vfd_contrast) ?
  340. (0x2B - (context->vfd_contrast - 1) / 250)
  341. : 0x2B;
  342. break;
  343. case 1:
  344. memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
  345. break;
  346. case 2:
  347. memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8);
  348. break;
  349. case 3:
  350. memcpy(context->usb_tx_buf, context->tx.data_buf, 8);
  351. break;
  352. case 4:
  353. memcpy(context->usb_tx_buf,
  354. context->tx.data_buf + 8, 8);
  355. break;
  356. case 5:
  357. memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
  358. break;
  359. case 6:
  360. memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8);
  361. break;
  362. case 7:
  363. memcpy(context->usb_tx_buf,
  364. context->tx.data_buf + 16, 8);
  365. break;
  366. case 8:
  367. memcpy(context->usb_tx_buf,
  368. context->tx.data_buf + 24, 8);
  369. break;
  370. }
  371. retval = send_packet(context);
  372. if (retval) {
  373. dev_err(&context->dev->dev,
  374. "send packet failed for packet #%d\n", i);
  375. goto exit;
  376. }
  377. }
  378. exit:
  379. mutex_unlock(&context->ctx_lock);
  380. kfree(data_buf);
  381. return (!retval) ? n_bytes : retval;
  382. }
  383. /**
  384. * Callback function for USB core API: transmit data
  385. */
  386. static void usb_tx_callback(struct urb *urb)
  387. {
  388. struct sasem_context *context;
  389. if (!urb)
  390. return;
  391. context = (struct sasem_context *) urb->context;
  392. if (!context)
  393. return;
  394. context->tx.status = urb->status;
  395. /* notify waiters that write has finished */
  396. atomic_set(&context->tx.busy, 0);
  397. complete(&context->tx.finished);
  398. }
  399. /**
  400. * Called by lirc_dev when the application opens /dev/lirc
  401. */
  402. static int ir_open(void *data)
  403. {
  404. int retval = 0;
  405. struct sasem_context *context;
  406. /* prevent races with disconnect */
  407. mutex_lock(&disconnect_lock);
  408. context = data;
  409. mutex_lock(&context->ctx_lock);
  410. if (context->ir_isopen) {
  411. dev_err(&context->dev->dev, "%s: IR port is already open\n",
  412. __func__);
  413. retval = -EBUSY;
  414. goto exit;
  415. }
  416. usb_fill_int_urb(context->rx_urb, context->dev,
  417. usb_rcvintpipe(context->dev,
  418. context->rx_endpoint->bEndpointAddress),
  419. context->usb_rx_buf, sizeof(context->usb_rx_buf),
  420. usb_rx_callback, context, context->rx_endpoint->bInterval);
  421. retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
  422. if (retval)
  423. dev_err(&context->dev->dev,
  424. "usb_submit_urb failed for ir_open (%d)\n", retval);
  425. else {
  426. context->ir_isopen = 1;
  427. dev_info(&context->dev->dev, "IR port opened\n");
  428. }
  429. exit:
  430. mutex_unlock(&context->ctx_lock);
  431. mutex_unlock(&disconnect_lock);
  432. return retval;
  433. }
  434. /**
  435. * Called by lirc_dev when the application closes /dev/lirc
  436. */
  437. static void ir_close(void *data)
  438. {
  439. struct sasem_context *context;
  440. context = data;
  441. if (!context) {
  442. pr_err("%s: no context for device\n", __func__);
  443. return;
  444. }
  445. mutex_lock(&context->ctx_lock);
  446. usb_kill_urb(context->rx_urb);
  447. context->ir_isopen = 0;
  448. pr_info("IR port closed\n");
  449. if (!context->dev_present) {
  450. /*
  451. * Device disconnected while IR port was
  452. * still open. Driver was not deregistered
  453. * at disconnect time, so do it now.
  454. */
  455. deregister_from_lirc(context);
  456. if (!context->vfd_isopen) {
  457. mutex_unlock(&context->ctx_lock);
  458. delete_context(context);
  459. return;
  460. }
  461. /* If VFD port is open, context will be deleted by vfd_close */
  462. }
  463. mutex_unlock(&context->ctx_lock);
  464. }
  465. /**
  466. * Process the incoming packet
  467. */
  468. static void incoming_packet(struct sasem_context *context,
  469. struct urb *urb)
  470. {
  471. int len = urb->actual_length;
  472. unsigned char *buf = urb->transfer_buffer;
  473. long ms;
  474. struct timeval tv;
  475. if (len != 8) {
  476. dev_warn(&context->dev->dev,
  477. "%s: invalid incoming packet size (%d)\n",
  478. __func__, len);
  479. return;
  480. }
  481. if (debug)
  482. dev_info(&context->dev->dev, "Incoming data: %*ph\n", len, buf);
  483. /*
  484. * Lirc could deal with the repeat code, but we really need to block it
  485. * if it arrives too late. Otherwise we could repeat the wrong code.
  486. */
  487. /* get the time since the last button press */
  488. do_gettimeofday(&tv);
  489. ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 +
  490. (tv.tv_usec - context->presstime.tv_usec) / 1000;
  491. if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) {
  492. /*
  493. * the repeat code is being sent, so we copy
  494. * the old code to LIRC
  495. */
  496. /*
  497. * NOTE: Only if the last code was less than 250ms ago
  498. * - no one should be able to push another (undetected) button
  499. * in that time and then get a false repeat of the previous
  500. * press but it is long enough for a genuine repeat
  501. */
  502. if ((ms < 250) && (context->codesaved != 0)) {
  503. memcpy(buf, &context->lastcode, 8);
  504. context->presstime.tv_sec = tv.tv_sec;
  505. context->presstime.tv_usec = tv.tv_usec;
  506. }
  507. } else {
  508. /* save the current valid code for repeats */
  509. memcpy(&context->lastcode, buf, 8);
  510. /*
  511. * set flag to signal a valid code was save;
  512. * just for safety reasons
  513. */
  514. context->codesaved = 1;
  515. context->presstime.tv_sec = tv.tv_sec;
  516. context->presstime.tv_usec = tv.tv_usec;
  517. }
  518. lirc_buffer_write(context->driver->rbuf, buf);
  519. wake_up(&context->driver->rbuf->wait_poll);
  520. }
  521. /**
  522. * Callback function for USB core API: receive data
  523. */
  524. static void usb_rx_callback(struct urb *urb)
  525. {
  526. struct sasem_context *context;
  527. if (!urb)
  528. return;
  529. context = (struct sasem_context *) urb->context;
  530. if (!context)
  531. return;
  532. switch (urb->status) {
  533. case -ENOENT: /* usbcore unlink successful! */
  534. return;
  535. case 0:
  536. if (context->ir_isopen)
  537. incoming_packet(context, urb);
  538. break;
  539. default:
  540. dev_warn(&urb->dev->dev, "%s: status (%d): ignored",
  541. __func__, urb->status);
  542. break;
  543. }
  544. usb_submit_urb(context->rx_urb, GFP_ATOMIC);
  545. }
  546. /**
  547. * Callback function for USB core API: Probe
  548. */
  549. static int sasem_probe(struct usb_interface *interface,
  550. const struct usb_device_id *id)
  551. {
  552. struct usb_device *dev = NULL;
  553. struct usb_host_interface *iface_desc = NULL;
  554. struct usb_endpoint_descriptor *rx_endpoint = NULL;
  555. struct usb_endpoint_descriptor *tx_endpoint = NULL;
  556. struct urb *rx_urb = NULL;
  557. struct urb *tx_urb = NULL;
  558. struct lirc_driver *driver = NULL;
  559. struct lirc_buffer *rbuf = NULL;
  560. int lirc_minor = 0;
  561. int num_endpoints;
  562. int retval = 0;
  563. int vfd_ep_found;
  564. int ir_ep_found;
  565. int alloc_status;
  566. struct sasem_context *context = NULL;
  567. int i;
  568. dev_info(&interface->dev, "%s: found Sasem device\n", __func__);
  569. dev = usb_get_dev(interface_to_usbdev(interface));
  570. iface_desc = interface->cur_altsetting;
  571. num_endpoints = iface_desc->desc.bNumEndpoints;
  572. /*
  573. * Scan the endpoint list and set:
  574. * first input endpoint = IR endpoint
  575. * first output endpoint = VFD endpoint
  576. */
  577. ir_ep_found = 0;
  578. vfd_ep_found = 0;
  579. for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) {
  580. struct usb_endpoint_descriptor *ep;
  581. ep = &iface_desc->endpoint [i].desc;
  582. if (!ir_ep_found &&
  583. usb_endpoint_is_int_in(ep)) {
  584. rx_endpoint = ep;
  585. ir_ep_found = 1;
  586. if (debug)
  587. dev_info(&interface->dev,
  588. "%s: found IR endpoint\n", __func__);
  589. } else if (!vfd_ep_found &&
  590. usb_endpoint_is_int_out(ep)) {
  591. tx_endpoint = ep;
  592. vfd_ep_found = 1;
  593. if (debug)
  594. dev_info(&interface->dev,
  595. "%s: found VFD endpoint\n", __func__);
  596. }
  597. }
  598. /* Input endpoint is mandatory */
  599. if (!ir_ep_found) {
  600. dev_err(&interface->dev,
  601. "%s: no valid input (IR) endpoint found.\n", __func__);
  602. retval = -ENODEV;
  603. goto exit;
  604. }
  605. if (!vfd_ep_found)
  606. dev_info(&interface->dev,
  607. "%s: no valid output (VFD) endpoint found.\n",
  608. __func__);
  609. /* Allocate memory */
  610. alloc_status = 0;
  611. context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
  612. if (!context) {
  613. alloc_status = 1;
  614. goto alloc_status_switch;
  615. }
  616. driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
  617. if (!driver) {
  618. alloc_status = 2;
  619. goto alloc_status_switch;
  620. }
  621. rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
  622. if (!rbuf) {
  623. alloc_status = 3;
  624. goto alloc_status_switch;
  625. }
  626. if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
  627. dev_err(&interface->dev,
  628. "%s: lirc_buffer_init failed\n", __func__);
  629. alloc_status = 4;
  630. goto alloc_status_switch;
  631. }
  632. rx_urb = usb_alloc_urb(0, GFP_KERNEL);
  633. if (!rx_urb) {
  634. dev_err(&interface->dev,
  635. "%s: usb_alloc_urb failed for IR urb\n", __func__);
  636. alloc_status = 5;
  637. goto alloc_status_switch;
  638. }
  639. if (vfd_ep_found) {
  640. tx_urb = usb_alloc_urb(0, GFP_KERNEL);
  641. if (!tx_urb) {
  642. dev_err(&interface->dev,
  643. "%s: usb_alloc_urb failed for VFD urb",
  644. __func__);
  645. alloc_status = 6;
  646. goto alloc_status_switch;
  647. }
  648. }
  649. mutex_init(&context->ctx_lock);
  650. strcpy(driver->name, MOD_NAME);
  651. driver->minor = -1;
  652. driver->code_length = 64;
  653. driver->sample_rate = 0;
  654. driver->features = LIRC_CAN_REC_LIRCCODE;
  655. driver->data = context;
  656. driver->rbuf = rbuf;
  657. driver->set_use_inc = ir_open;
  658. driver->set_use_dec = ir_close;
  659. driver->dev = &interface->dev;
  660. driver->owner = THIS_MODULE;
  661. mutex_lock(&context->ctx_lock);
  662. lirc_minor = lirc_register_driver(driver);
  663. if (lirc_minor < 0) {
  664. dev_err(&interface->dev,
  665. "%s: lirc_register_driver failed\n", __func__);
  666. alloc_status = 7;
  667. retval = lirc_minor;
  668. goto unlock;
  669. } else
  670. dev_info(&interface->dev,
  671. "%s: Registered Sasem driver (minor:%d)\n",
  672. __func__, lirc_minor);
  673. /* Needed while unregistering! */
  674. driver->minor = lirc_minor;
  675. context->dev = dev;
  676. context->dev_present = 1;
  677. context->rx_endpoint = rx_endpoint;
  678. context->rx_urb = rx_urb;
  679. if (vfd_ep_found) {
  680. context->tx_endpoint = tx_endpoint;
  681. context->tx_urb = tx_urb;
  682. context->vfd_contrast = 1000; /* range 0 - 1000 */
  683. }
  684. context->driver = driver;
  685. usb_set_intfdata(interface, context);
  686. if (vfd_ep_found) {
  687. if (debug)
  688. dev_info(&interface->dev,
  689. "Registering VFD with sysfs\n");
  690. if (usb_register_dev(interface, &sasem_class))
  691. /* Not a fatal error, so ignore */
  692. dev_info(&interface->dev,
  693. "%s: could not get a minor number for VFD\n",
  694. __func__);
  695. }
  696. dev_info(&interface->dev,
  697. "%s: Sasem device on usb<%d:%d> initialized\n",
  698. __func__, dev->bus->busnum, dev->devnum);
  699. unlock:
  700. mutex_unlock(&context->ctx_lock);
  701. alloc_status_switch:
  702. switch (alloc_status) {
  703. case 7:
  704. if (vfd_ep_found)
  705. usb_free_urb(tx_urb);
  706. case 6:
  707. usb_free_urb(rx_urb);
  708. /* fall-through */
  709. case 5:
  710. lirc_buffer_free(rbuf);
  711. /* fall-through */
  712. case 4:
  713. kfree(rbuf);
  714. /* fall-through */
  715. case 3:
  716. kfree(driver);
  717. /* fall-through */
  718. case 2:
  719. kfree(context);
  720. context = NULL;
  721. /* fall-through */
  722. case 1:
  723. if (retval == 0)
  724. retval = -ENOMEM;
  725. }
  726. exit:
  727. return retval;
  728. }
  729. /**
  730. * Callback function for USB core API: disconnect
  731. */
  732. static void sasem_disconnect(struct usb_interface *interface)
  733. {
  734. struct sasem_context *context;
  735. /* prevent races with ir_open()/vfd_open() */
  736. mutex_lock(&disconnect_lock);
  737. context = usb_get_intfdata(interface);
  738. mutex_lock(&context->ctx_lock);
  739. dev_info(&interface->dev, "%s: Sasem device disconnected\n",
  740. __func__);
  741. usb_set_intfdata(interface, NULL);
  742. context->dev_present = 0;
  743. /* Stop reception */
  744. usb_kill_urb(context->rx_urb);
  745. /* Abort ongoing write */
  746. if (atomic_read(&context->tx.busy)) {
  747. usb_kill_urb(context->tx_urb);
  748. wait_for_completion(&context->tx.finished);
  749. }
  750. /* De-register from lirc_dev if IR port is not open */
  751. if (!context->ir_isopen)
  752. deregister_from_lirc(context);
  753. usb_deregister_dev(interface, &sasem_class);
  754. mutex_unlock(&context->ctx_lock);
  755. if (!context->ir_isopen && !context->vfd_isopen)
  756. delete_context(context);
  757. mutex_unlock(&disconnect_lock);
  758. }
  759. module_usb_driver(sasem_driver);