Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lirc_sasem.c
Go to the documentation of this file.
1 /*
2  * lirc_sasem.c - USB remote support for LIRC
3  * Version 0.5
4  *
5  * Copyright (C) 2004-2005 Oliver Stabel <[email protected]>
6  * Tim Davies <[email protected]>
7  *
8  * This driver was derived from:
9  * Venky Raju <[email protected]>
10  * "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD"
11  * Paul Miller <[email protected]>'s 2003-2004
12  * "lirc_atiusb - USB remote support for LIRC"
13  * Culver Consulting Services <[email protected]>'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 /*
22  * This program is free software; you can redistribute it and/or modify
23  * it under the terms of the GNU General Public License as published by
24  * the Free Software Foundation; either version 2 of the License, or
25  * (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program; if not, write to the Free Software
34  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35  */
36 
37 #include <linux/errno.h>
38 #include <linux/init.h>
39 #include <linux/kernel.h>
40 #include <linux/module.h>
41 #include <linux/slab.h>
42 #include <linux/uaccess.h>
43 #include <linux/usb.h>
44 
45 #include <media/lirc.h>
46 #include <media/lirc_dev.h>
47 
48 
49 #define MOD_AUTHOR "Oliver Stabel <[email protected]>, " \
50  "Tim Davies <[email protected]>"
51 #define MOD_DESC "USB Driver for Sasem Remote Controller V1.1"
52 #define MOD_NAME "lirc_sasem"
53 #define MOD_VERSION "0.5"
54 
55 #define VFD_MINOR_BASE 144 /* Same as LCD */
56 #define DEVICE_NAME "lcd%d"
57 
58 #define BUF_CHUNK_SIZE 8
59 #define BUF_SIZE 128
60 
61 #define IOCTL_LCD_CONTRAST 1
62 
63 /*** P R O T O T Y P E S ***/
64 
65 /* USB Callback prototypes */
66 static int sasem_probe(struct usb_interface *interface,
67  const struct usb_device_id *id);
68 static void sasem_disconnect(struct usb_interface *interface);
69 static void usb_rx_callback(struct urb *urb);
70 static void usb_tx_callback(struct urb *urb);
71 
72 /* VFD file_operations function prototypes */
73 static int vfd_open(struct inode *inode, struct file *file);
74 static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg);
75 static int vfd_close(struct inode *inode, struct file *file);
76 static ssize_t vfd_write(struct file *file, const char *buf,
77  size_t n_bytes, loff_t *pos);
78 
79 /* LIRC driver function prototypes */
80 static int ir_open(void *data);
81 static void ir_close(void *data);
82 
83 /*** G L O B A L S ***/
84 #define SASEM_DATA_BUF_SZ 32
85 
86 struct sasem_context {
87 
88  struct usb_device *dev;
89  int vfd_isopen; /* VFD port has been opened */
90  unsigned int vfd_contrast; /* VFD contrast */
91  int ir_isopen; /* IR port has been opened */
92  int dev_present; /* USB device presence */
93  struct mutex ctx_lock; /* to lock this object */
94  wait_queue_head_t remove_ok; /* For unexpected USB disconnects */
95 
99  struct urb *rx_urb;
100  struct urb *tx_urb;
101  unsigned char usb_rx_buf[8];
102  unsigned char usb_tx_buf[8];
103 
104  struct tx_t {
105  unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data
106  * buffer */
107  struct completion finished; /* wait for write to finish */
108  atomic_t busy; /* write in progress */
109  int status; /* status of tx completion */
110  } tx;
111 
112  /* for dealing with repeat codes (wish there was a toggle bit!) */
114  char lastcode[8];
116 };
117 
118 /* VFD file operations */
119 static const struct file_operations vfd_fops = {
120  .owner = THIS_MODULE,
121  .open = &vfd_open,
122  .write = &vfd_write,
123  .unlocked_ioctl = &vfd_ioctl,
124  .release = &vfd_close,
125  .llseek = noop_llseek,
126 };
127 
128 /* USB Device ID for Sasem USB Control Board */
129 static struct usb_device_id sasem_usb_id_table[] = {
130  /* Sasem USB Control Board */
131  { USB_DEVICE(0x11ba, 0x0101) },
132  /* Terminating entry */
133  {}
134 };
135 
136 /* USB Device data */
137 static struct usb_driver sasem_driver = {
138  .name = MOD_NAME,
139  .probe = sasem_probe,
140  .disconnect = sasem_disconnect,
141  .id_table = sasem_usb_id_table,
142 };
143 
144 static struct usb_class_driver sasem_class = {
145  .name = DEVICE_NAME,
146  .fops = &vfd_fops,
147  .minor_base = VFD_MINOR_BASE,
148 };
149 
150 /* to prevent races between open() and disconnect() */
151 static DEFINE_MUTEX(disconnect_lock);
152 
153 static int debug;
154 
155 
156 /*** M O D U L E C O D E ***/
157 
160 MODULE_LICENSE("GPL");
162 MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
163 
164 static void delete_context(struct sasem_context *context)
165 {
166  usb_free_urb(context->tx_urb); /* VFD */
167  usb_free_urb(context->rx_urb); /* IR */
168  lirc_buffer_free(context->driver->rbuf);
169  kfree(context->driver->rbuf);
170  kfree(context->driver);
171  kfree(context);
172 
173  if (debug)
174  printk(KERN_INFO "%s: context deleted\n", __func__);
175 }
176 
177 static void deregister_from_lirc(struct sasem_context *context)
178 {
179  int retval;
180  int minor = context->driver->minor;
181 
182  retval = lirc_unregister_driver(minor);
183  if (retval)
184  printk(KERN_ERR "%s: unable to deregister from lirc (%d)\n",
185  __func__, retval);
186  else
187  printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n",
188  minor);
189 
190 }
191 
196 static int vfd_open(struct inode *inode, struct file *file)
197 {
198  struct usb_interface *interface;
199  struct sasem_context *context = NULL;
200  int subminor;
201  int retval = 0;
202 
203  /* prevent races with disconnect */
204  mutex_lock(&disconnect_lock);
205 
206  subminor = iminor(inode);
207  interface = usb_find_interface(&sasem_driver, subminor);
208  if (!interface) {
209  printk(KERN_ERR KBUILD_MODNAME
210  ": %s: could not find interface for minor %d\n",
211  __func__, subminor);
212  retval = -ENODEV;
213  goto exit;
214  }
215  context = usb_get_intfdata(interface);
216 
217  if (!context) {
218  dev_err(&interface->dev,
219  "%s: no context found for minor %d\n",
220  __func__, subminor);
221  retval = -ENODEV;
222  goto exit;
223  }
224 
225  mutex_lock(&context->ctx_lock);
226 
227  if (context->vfd_isopen) {
228  dev_err(&interface->dev,
229  "%s: VFD port is already open", __func__);
230  retval = -EBUSY;
231  } else {
232  context->vfd_isopen = 1;
233  file->private_data = context;
234  dev_info(&interface->dev, "VFD port opened\n");
235  }
236 
237  mutex_unlock(&context->ctx_lock);
238 
239 exit:
240  mutex_unlock(&disconnect_lock);
241  return retval;
242 }
243 
248 static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg)
249 {
250  struct sasem_context *context = NULL;
251 
252  context = (struct sasem_context *) file->private_data;
253 
254  if (!context) {
255  printk(KERN_ERR KBUILD_MODNAME
256  ": %s: no context for device\n", __func__);
257  return -ENODEV;
258  }
259 
260  mutex_lock(&context->ctx_lock);
261 
262  switch (cmd) {
263  case IOCTL_LCD_CONTRAST:
264  if (arg > 1000)
265  arg = 1000;
266  context->vfd_contrast = (unsigned int)arg;
267  break;
268  default:
269  printk(KERN_INFO "Unknown IOCTL command\n");
270  mutex_unlock(&context->ctx_lock);
271  return -ENOIOCTLCMD; /* not supported */
272  }
273 
274  mutex_unlock(&context->ctx_lock);
275  return 0;
276 }
277 
282 static int vfd_close(struct inode *inode, struct file *file)
283 {
284  struct sasem_context *context = NULL;
285  int retval = 0;
286 
287  context = (struct sasem_context *) file->private_data;
288 
289  if (!context) {
290  printk(KERN_ERR KBUILD_MODNAME
291  ": %s: no context for device\n", __func__);
292  return -ENODEV;
293  }
294 
295  mutex_lock(&context->ctx_lock);
296 
297  if (!context->vfd_isopen) {
298  dev_err(&context->dev->dev, "%s: VFD is not open\n", __func__);
299  retval = -EIO;
300  } else {
301  context->vfd_isopen = 0;
302  printk(KERN_INFO "VFD port closed\n");
303  if (!context->dev_present && !context->ir_isopen) {
304 
305  /* Device disconnected before close and IR port is
306  * not open. If IR port is open, context will be
307  * deleted by ir_close. */
308  mutex_unlock(&context->ctx_lock);
309  delete_context(context);
310  return retval;
311  }
312  }
313 
314  mutex_unlock(&context->ctx_lock);
315  return retval;
316 }
317 
321 static int send_packet(struct sasem_context *context)
322 {
323  unsigned int pipe;
324  int interval = 0;
325  int retval = 0;
326 
327  pipe = usb_sndintpipe(context->dev,
328  context->tx_endpoint->bEndpointAddress);
329  interval = context->tx_endpoint->bInterval;
330 
331  usb_fill_int_urb(context->tx_urb, context->dev, pipe,
332  context->usb_tx_buf, sizeof(context->usb_tx_buf),
333  usb_tx_callback, context, interval);
334 
335  context->tx_urb->actual_length = 0;
336 
337  init_completion(&context->tx.finished);
338  atomic_set(&(context->tx.busy), 1);
339 
340  retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
341  if (retval) {
342  atomic_set(&(context->tx.busy), 0);
343  dev_err(&context->dev->dev, "%s: error submitting urb (%d)\n",
344  __func__, retval);
345  } else {
346  /* Wait for transmission to complete (or abort) */
347  mutex_unlock(&context->ctx_lock);
348  wait_for_completion(&context->tx.finished);
349  mutex_lock(&context->ctx_lock);
350 
351  retval = context->tx.status;
352  if (retval)
353  dev_err(&context->dev->dev,
354  "%s: packet tx failed (%d)\n",
355  __func__, retval);
356  }
357 
358  return retval;
359 }
360 
366 static ssize_t vfd_write(struct file *file, const char *buf,
367  size_t n_bytes, loff_t *pos)
368 {
369  int i;
370  int retval = 0;
371  struct sasem_context *context;
372  int *data_buf = NULL;
373 
374  context = (struct sasem_context *) file->private_data;
375  if (!context) {
376  printk(KERN_ERR KBUILD_MODNAME
377  ": %s: no context for device\n", __func__);
378  return -ENODEV;
379  }
380 
381  mutex_lock(&context->ctx_lock);
382 
383  if (!context->dev_present) {
384  printk(KERN_ERR KBUILD_MODNAME
385  ": %s: no Sasem device present\n", __func__);
386  retval = -ENODEV;
387  goto exit;
388  }
389 
390  if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
391  dev_err(&context->dev->dev, "%s: invalid payload size\n",
392  __func__);
393  retval = -EINVAL;
394  goto exit;
395  }
396 
397  data_buf = memdup_user(buf, n_bytes);
398  if (IS_ERR(data_buf)) {
399  retval = PTR_ERR(data_buf);
400  goto exit;
401  }
402 
403  memcpy(context->tx.data_buf, data_buf, n_bytes);
404 
405  /* Pad with spaces */
406  for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i)
407  context->tx.data_buf[i] = ' ';
408 
409  /* Nine 8 byte packets to be sent */
410  /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0"
411  * will clear the VFD */
412  for (i = 0; i < 9; i++) {
413  switch (i) {
414  case 0:
415  memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8);
416  context->usb_tx_buf[1] = (context->vfd_contrast) ?
417  (0x2B - (context->vfd_contrast - 1) / 250)
418  : 0x2B;
419  break;
420  case 1:
421  memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
422  break;
423  case 2:
424  memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8);
425  break;
426  case 3:
427  memcpy(context->usb_tx_buf, context->tx.data_buf, 8);
428  break;
429  case 4:
430  memcpy(context->usb_tx_buf,
431  context->tx.data_buf + 8, 8);
432  break;
433  case 5:
434  memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
435  break;
436  case 6:
437  memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8);
438  break;
439  case 7:
440  memcpy(context->usb_tx_buf,
441  context->tx.data_buf + 16, 8);
442  break;
443  case 8:
444  memcpy(context->usb_tx_buf,
445  context->tx.data_buf + 24, 8);
446  break;
447  }
448  retval = send_packet(context);
449  if (retval) {
450  dev_err(&context->dev->dev,
451  "%s: send packet failed for packet #%d\n",
452  __func__, i);
453  goto exit;
454  }
455  }
456 exit:
457 
458  mutex_unlock(&context->ctx_lock);
459  kfree(data_buf);
460 
461  return (!retval) ? n_bytes : retval;
462 }
463 
467 static void usb_tx_callback(struct urb *urb)
468 {
469  struct sasem_context *context;
470 
471  if (!urb)
472  return;
473  context = (struct sasem_context *) urb->context;
474  if (!context)
475  return;
476 
477  context->tx.status = urb->status;
478 
479  /* notify waiters that write has finished */
480  atomic_set(&context->tx.busy, 0);
481  complete(&context->tx.finished);
482 
483  return;
484 }
485 
489 static int ir_open(void *data)
490 {
491  int retval = 0;
492  struct sasem_context *context;
493 
494  /* prevent races with disconnect */
495  mutex_lock(&disconnect_lock);
496 
497  context = (struct sasem_context *) data;
498 
499  mutex_lock(&context->ctx_lock);
500 
501  if (context->ir_isopen) {
502  dev_err(&context->dev->dev, "%s: IR port is already open\n",
503  __func__);
504  retval = -EBUSY;
505  goto exit;
506  }
507 
508  usb_fill_int_urb(context->rx_urb, context->dev,
509  usb_rcvintpipe(context->dev,
510  context->rx_endpoint->bEndpointAddress),
511  context->usb_rx_buf, sizeof(context->usb_rx_buf),
512  usb_rx_callback, context, context->rx_endpoint->bInterval);
513 
514  retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
515 
516  if (retval)
517  dev_err(&context->dev->dev,
518  "%s: usb_submit_urb failed for ir_open (%d)\n",
519  __func__, retval);
520  else {
521  context->ir_isopen = 1;
522  printk(KERN_INFO "IR port opened\n");
523  }
524 
525 exit:
526  mutex_unlock(&context->ctx_lock);
527 
528  mutex_unlock(&disconnect_lock);
529  return retval;
530 }
531 
535 static void ir_close(void *data)
536 {
537  struct sasem_context *context;
538 
539  context = (struct sasem_context *)data;
540  if (!context) {
541  printk(KERN_ERR KBUILD_MODNAME
542  ": %s: no context for device\n", __func__);
543  return;
544  }
545 
546  mutex_lock(&context->ctx_lock);
547 
548  usb_kill_urb(context->rx_urb);
549  context->ir_isopen = 0;
550  printk(KERN_INFO "IR port closed\n");
551 
552  if (!context->dev_present) {
553 
554  /*
555  * Device disconnected while IR port was
556  * still open. Driver was not deregistered
557  * at disconnect time, so do it now.
558  */
559  deregister_from_lirc(context);
560 
561  if (!context->vfd_isopen) {
562 
563  mutex_unlock(&context->ctx_lock);
564  delete_context(context);
565  return;
566  }
567  /* If VFD port is open, context will be deleted by vfd_close */
568  }
569 
570  mutex_unlock(&context->ctx_lock);
571  return;
572 }
573 
577 static void incoming_packet(struct sasem_context *context,
578  struct urb *urb)
579 {
580  int len = urb->actual_length;
581  unsigned char *buf = urb->transfer_buffer;
582  long ms;
583  struct timeval tv;
584  int i;
585 
586  if (len != 8) {
587  printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n",
588  __func__, len);
589  return;
590  }
591 
592  if (debug) {
593  printk(KERN_INFO "Incoming data: ");
594  for (i = 0; i < 8; ++i)
595  printk(KERN_CONT "%02x ", buf[i]);
596  printk(KERN_CONT "\n");
597  }
598 
599  /*
600  * Lirc could deal with the repeat code, but we really need to block it
601  * if it arrives too late. Otherwise we could repeat the wrong code.
602  */
603 
604  /* get the time since the last button press */
605  do_gettimeofday(&tv);
606  ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 +
607  (tv.tv_usec - context->presstime.tv_usec) / 1000;
608 
609  if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) {
610  /*
611  * the repeat code is being sent, so we copy
612  * the old code to LIRC
613  */
614 
615  /*
616  * NOTE: Only if the last code was less than 250ms ago
617  * - no one should be able to push another (undetected) button
618  * in that time and then get a false repeat of the previous
619  * press but it is long enough for a genuine repeat
620  */
621  if ((ms < 250) && (context->codesaved != 0)) {
622  memcpy(buf, &context->lastcode, 8);
623  context->presstime.tv_sec = tv.tv_sec;
624  context->presstime.tv_usec = tv.tv_usec;
625  }
626  } else {
627  /* save the current valid code for repeats */
628  memcpy(&context->lastcode, buf, 8);
629  /*
630  * set flag to signal a valid code was save;
631  * just for safety reasons
632  */
633  context->codesaved = 1;
634  context->presstime.tv_sec = tv.tv_sec;
635  context->presstime.tv_usec = tv.tv_usec;
636  }
637 
638  lirc_buffer_write(context->driver->rbuf, buf);
639  wake_up(&context->driver->rbuf->wait_poll);
640 }
641 
645 static void usb_rx_callback(struct urb *urb)
646 {
647  struct sasem_context *context;
648 
649  if (!urb)
650  return;
651  context = (struct sasem_context *) urb->context;
652  if (!context)
653  return;
654 
655  switch (urb->status) {
656 
657  case -ENOENT: /* usbcore unlink successful! */
658  return;
659 
660  case 0:
661  if (context->ir_isopen)
662  incoming_packet(context, urb);
663  break;
664 
665  default:
666  printk(KERN_WARNING "%s: status (%d): ignored",
667  __func__, urb->status);
668  break;
669  }
670 
671  usb_submit_urb(context->rx_urb, GFP_ATOMIC);
672  return;
673 }
674 
675 
676 
680 static int sasem_probe(struct usb_interface *interface,
681  const struct usb_device_id *id)
682 {
683  struct usb_device *dev = NULL;
684  struct usb_host_interface *iface_desc = NULL;
685  struct usb_endpoint_descriptor *rx_endpoint = NULL;
686  struct usb_endpoint_descriptor *tx_endpoint = NULL;
687  struct urb *rx_urb = NULL;
688  struct urb *tx_urb = NULL;
689  struct lirc_driver *driver = NULL;
690  struct lirc_buffer *rbuf = NULL;
691  int lirc_minor = 0;
692  int num_endpoints;
693  int retval = 0;
694  int vfd_ep_found;
695  int ir_ep_found;
696  int alloc_status;
697  struct sasem_context *context = NULL;
698  int i;
699 
700  dev_info(&interface->dev, "%s: found Sasem device\n", __func__);
701 
702 
703  dev = usb_get_dev(interface_to_usbdev(interface));
704  iface_desc = interface->cur_altsetting;
705  num_endpoints = iface_desc->desc.bNumEndpoints;
706 
707  /*
708  * Scan the endpoint list and set:
709  * first input endpoint = IR endpoint
710  * first output endpoint = VFD endpoint
711  */
712 
713  ir_ep_found = 0;
714  vfd_ep_found = 0;
715 
716  for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) {
717 
718  struct usb_endpoint_descriptor *ep;
719  int ep_dir;
720  int ep_type;
721  ep = &iface_desc->endpoint [i].desc;
724 
725  if (!ir_ep_found &&
726  ep_dir == USB_DIR_IN &&
727  ep_type == USB_ENDPOINT_XFER_INT) {
728 
729  rx_endpoint = ep;
730  ir_ep_found = 1;
731  if (debug)
732  dev_info(&interface->dev,
733  "%s: found IR endpoint\n", __func__);
734 
735  } else if (!vfd_ep_found &&
736  ep_dir == USB_DIR_OUT &&
737  ep_type == USB_ENDPOINT_XFER_INT) {
738 
739  tx_endpoint = ep;
740  vfd_ep_found = 1;
741  if (debug)
742  dev_info(&interface->dev,
743  "%s: found VFD endpoint\n", __func__);
744  }
745  }
746 
747  /* Input endpoint is mandatory */
748  if (!ir_ep_found) {
749  dev_err(&interface->dev,
750  "%s: no valid input (IR) endpoint found.\n", __func__);
751  retval = -ENODEV;
752  goto exit;
753  }
754 
755  if (!vfd_ep_found)
756  dev_info(&interface->dev,
757  "%s: no valid output (VFD) endpoint found.\n",
758  __func__);
759 
760 
761  /* Allocate memory */
762  alloc_status = 0;
763 
764  context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
765  if (!context) {
766  dev_err(&interface->dev,
767  "%s: kzalloc failed for context\n", __func__);
768  alloc_status = 1;
769  goto alloc_status_switch;
770  }
771  driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
772  if (!driver) {
773  dev_err(&interface->dev,
774  "%s: kzalloc failed for lirc_driver\n", __func__);
775  alloc_status = 2;
776  goto alloc_status_switch;
777  }
778  rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
779  if (!rbuf) {
780  dev_err(&interface->dev,
781  "%s: kmalloc failed for lirc_buffer\n", __func__);
782  alloc_status = 3;
783  goto alloc_status_switch;
784  }
785  if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
786  dev_err(&interface->dev,
787  "%s: lirc_buffer_init failed\n", __func__);
788  alloc_status = 4;
789  goto alloc_status_switch;
790  }
791  rx_urb = usb_alloc_urb(0, GFP_KERNEL);
792  if (!rx_urb) {
793  dev_err(&interface->dev,
794  "%s: usb_alloc_urb failed for IR urb\n", __func__);
795  alloc_status = 5;
796  goto alloc_status_switch;
797  }
798  if (vfd_ep_found) {
799  tx_urb = usb_alloc_urb(0, GFP_KERNEL);
800  if (!tx_urb) {
801  dev_err(&interface->dev,
802  "%s: usb_alloc_urb failed for VFD urb",
803  __func__);
804  alloc_status = 6;
805  goto alloc_status_switch;
806  }
807  }
808 
809  mutex_init(&context->ctx_lock);
810 
811  strcpy(driver->name, MOD_NAME);
812  driver->minor = -1;
813  driver->code_length = 64;
814  driver->sample_rate = 0;
816  driver->data = context;
817  driver->rbuf = rbuf;
818  driver->set_use_inc = ir_open;
819  driver->set_use_dec = ir_close;
820  driver->dev = &interface->dev;
821  driver->owner = THIS_MODULE;
822 
823  mutex_lock(&context->ctx_lock);
824 
825  lirc_minor = lirc_register_driver(driver);
826  if (lirc_minor < 0) {
827  dev_err(&interface->dev,
828  "%s: lirc_register_driver failed\n", __func__);
829  alloc_status = 7;
830  retval = lirc_minor;
831  goto unlock;
832  } else
833  printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n",
834  __func__, lirc_minor);
835 
836  /* Needed while unregistering! */
837  driver->minor = lirc_minor;
838 
839  context->dev = dev;
840  context->dev_present = 1;
841  context->rx_endpoint = rx_endpoint;
842  context->rx_urb = rx_urb;
843  if (vfd_ep_found) {
844  context->tx_endpoint = tx_endpoint;
845  context->tx_urb = tx_urb;
846  context->vfd_contrast = 1000; /* range 0 - 1000 */
847  }
848  context->driver = driver;
849 
850  usb_set_intfdata(interface, context);
851 
852  if (vfd_ep_found) {
853 
854  if (debug)
855  printk(KERN_INFO "Registering VFD with sysfs\n");
856  if (usb_register_dev(interface, &sasem_class))
857  /* Not a fatal error, so ignore */
858  printk(KERN_INFO "%s: could not get a minor number "
859  "for VFD\n", __func__);
860  }
861 
862  printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n",
863  __func__, dev->bus->busnum, dev->devnum);
864 unlock:
865  mutex_unlock(&context->ctx_lock);
866 
867 alloc_status_switch:
868  switch (alloc_status) {
869 
870  case 7:
871  if (vfd_ep_found)
872  usb_free_urb(tx_urb);
873  case 6:
874  usb_free_urb(rx_urb);
875  case 5:
876  lirc_buffer_free(rbuf);
877  case 4:
878  kfree(rbuf);
879  case 3:
880  kfree(driver);
881  case 2:
882  kfree(context);
883  context = NULL;
884  case 1:
885  if (retval == 0)
886  retval = -ENOMEM;
887  }
888 
889 exit:
890  return retval;
891 }
892 
896 static void sasem_disconnect(struct usb_interface *interface)
897 {
898  struct sasem_context *context;
899 
900  /* prevent races with ir_open()/vfd_open() */
901  mutex_lock(&disconnect_lock);
902 
903  context = usb_get_intfdata(interface);
904  mutex_lock(&context->ctx_lock);
905 
906  printk(KERN_INFO "%s: Sasem device disconnected\n", __func__);
907 
908  usb_set_intfdata(interface, NULL);
909  context->dev_present = 0;
910 
911  /* Stop reception */
912  usb_kill_urb(context->rx_urb);
913 
914  /* Abort ongoing write */
915  if (atomic_read(&context->tx.busy)) {
916 
917  usb_kill_urb(context->tx_urb);
918  wait_for_completion(&context->tx.finished);
919  }
920 
921  /* De-register from lirc_dev if IR port is not open */
922  if (!context->ir_isopen)
923  deregister_from_lirc(context);
924 
925  usb_deregister_dev(interface, &sasem_class);
926 
927  mutex_unlock(&context->ctx_lock);
928 
929  if (!context->ir_isopen && !context->vfd_isopen)
930  delete_context(context);
931 
932  mutex_unlock(&disconnect_lock);
933 }
934 
935 module_usb_driver(sasem_driver);