Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
kingsun-sir.c
Go to the documentation of this file.
1 /*****************************************************************************
2 *
3 * Filename: kingsun-sir.c
4 * Version: 0.1.1
5 * Description: Irda KingSun/DonShine USB Dongle
6 * Status: Experimental
7 * Author: Alex Villacís Lasso <[email protected]>
8 *
9 * Based on stir4200 and mcs7780 drivers, with (strange?) differences
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *****************************************************************************/
25 
26 /*
27  * This is my current (2007-04-25) understanding of how this dongle is supposed
28  * to work. This is based on reverse-engineering and examination of the packet
29  * data sent and received by the WinXP driver using USBSnoopy. Feel free to
30  * update here as more of this dongle is known:
31  *
32  * General: Unlike the other USB IrDA dongles, this particular dongle exposes,
33  * not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle,
34  * like the bulk based ones (stir4200.c and mcs7780.c), requires polling in
35  * order to receive data.
36  * Transmission: Just like stir4200, this dongle uses a raw stream of data,
37  * which needs to be wrapped and escaped in a similar way as in stir4200.c.
38  * Reception: Poll-based, as in stir4200. Each read returns the contents of a
39  * 8-byte buffer, of which the first byte (LSB) indicates the number of bytes
40  * (1-7) of valid data contained within the remaining 7 bytes. For example, if
41  * the buffer had the following contents:
42  * 06 ff ff ff c0 01 04 aa
43  * This means that (06) there are 6 bytes of valid data. The byte 0xaa at the
44  * end is garbage (left over from a previous reception) and is discarded.
45  * If a read returns an "impossible" value as the length of valid data (such as
46  * 0x36) in the first byte, then the buffer is uninitialized (as is the case of
47  * first plug-in) and its contents should be discarded. There is currently no
48  * evidence that the top 5 bits of the 1st byte of the buffer can have values
49  * other than 0 once reception begins.
50  * Once valid bytes are collected, the assembled stream is a sequence of
51  * wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c.
52  * BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after
53  * a successful read from the host, which means that in absence of further
54  * reception, repeated reads from the dongle will return the exact same
55  * contents repeatedly. Attempts to be smart and cache a previous read seem
56  * to result in corrupted packets, so this driver depends on the unwrap logic
57  * to sort out any repeated reads.
58  * Speed change: no commands observed so far to change speed, assumed fixed
59  * 9600bps (SIR).
60  */
61 
62 #include <linux/module.h>
63 #include <linux/moduleparam.h>
64 #include <linux/kernel.h>
65 #include <linux/types.h>
66 #include <linux/errno.h>
67 #include <linux/init.h>
68 #include <linux/slab.h>
69 #include <linux/usb.h>
70 #include <linux/device.h>
71 #include <linux/crc32.h>
72 
73 #include <asm/unaligned.h>
74 #include <asm/byteorder.h>
75 #include <asm/uaccess.h>
76 
77 #include <net/irda/irda.h>
78 #include <net/irda/wrapper.h>
79 #include <net/irda/crc.h>
80 
81 /*
82  * According to lsusb, 0x07c0 is assigned to
83  * "Code Mercenaries Hard- und Software GmbH"
84  */
85 #define KING_VENDOR_ID 0x07c0
86 #define KING_PRODUCT_ID 0x4200
87 
88 /* These are the currently known USB ids */
89 static struct usb_device_id dongles[] = {
90  /* KingSun Co,Ltd IrDA/USB Bridge */
91  { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
92  { }
93 };
94 
95 MODULE_DEVICE_TABLE(usb, dongles);
96 
97 #define KINGSUN_MTT 0x07
98 
99 #define KINGSUN_FIFO_SIZE 4096
100 #define KINGSUN_EP_IN 0
101 #define KINGSUN_EP_OUT 1
102 
103 struct kingsun_cb {
104  struct usb_device *usbdev; /* init: probe_irda */
105  struct net_device *netdev; /* network layer */
106  struct irlap_cb *irlap; /* The link layer we are binded to */
107 
108  struct qos_info qos;
109 
110  __u8 *in_buf; /* receive buffer */
111  __u8 *out_buf; /* transmit buffer */
112  __u8 max_rx; /* max. atomic read from dongle
113  (usually 8), also size of in_buf */
114  __u8 max_tx; /* max. atomic write to dongle
115  (usually 8) */
116 
117  iobuff_t rx_buff; /* receive unwrap state machine */
118  struct timeval rx_time;
121 
124 
125  struct urb *tx_urb;
126  struct urb *rx_urb;
127 };
128 
129 /* Callback transmission routine */
130 static void kingsun_send_irq(struct urb *urb)
131 {
132  struct kingsun_cb *kingsun = urb->context;
133  struct net_device *netdev = kingsun->netdev;
134 
135  /* in process of stopping, just drop data */
136  if (!netif_running(kingsun->netdev)) {
137  dev_err(&kingsun->usbdev->dev,
138  "kingsun_send_irq: Network not running!\n");
139  return;
140  }
141 
142  /* unlink, shutdown, unplug, other nasties */
143  if (urb->status != 0) {
144  dev_err(&kingsun->usbdev->dev,
145  "kingsun_send_irq: urb asynchronously failed - %d\n",
146  urb->status);
147  }
148  netif_wake_queue(netdev);
149 }
150 
151 /*
152  * Called from net/core when new frame is available.
153  */
154 static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb,
155  struct net_device *netdev)
156 {
157  struct kingsun_cb *kingsun;
158  int wraplen;
159  int ret = 0;
160 
161  netif_stop_queue(netdev);
162 
163  /* the IRDA wrapping routines don't deal with non linear skb */
164  SKB_LINEAR_ASSERT(skb);
165 
166  kingsun = netdev_priv(netdev);
167 
168  spin_lock(&kingsun->lock);
169 
170  /* Append data to the end of whatever data remains to be transmitted */
171  wraplen = async_wrap_skb(skb,
172  kingsun->out_buf,
174 
175  /* Calculate how much data can be transmitted in this urb */
176  usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
177  usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
178  kingsun->out_buf, wraplen, kingsun_send_irq,
179  kingsun, 1);
180 
181  if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
182  dev_err(&kingsun->usbdev->dev,
183  "kingsun_hard_xmit: failed tx_urb submit: %d\n", ret);
184  switch (ret) {
185  case -ENODEV:
186  case -EPIPE:
187  break;
188  default:
189  netdev->stats.tx_errors++;
190  netif_start_queue(netdev);
191  }
192  } else {
193  netdev->stats.tx_packets++;
194  netdev->stats.tx_bytes += skb->len;
195  }
196 
197  dev_kfree_skb(skb);
198  spin_unlock(&kingsun->lock);
199 
200  return NETDEV_TX_OK;
201 }
202 
203 /* Receive callback function */
204 static void kingsun_rcv_irq(struct urb *urb)
205 {
206  struct kingsun_cb *kingsun = urb->context;
207  int ret;
208 
209  /* in process of stopping, just drop data */
210  if (!netif_running(kingsun->netdev)) {
211  kingsun->receiving = 0;
212  return;
213  }
214 
215  /* unlink, shutdown, unplug, other nasties */
216  if (urb->status != 0) {
217  dev_err(&kingsun->usbdev->dev,
218  "kingsun_rcv_irq: urb asynchronously failed - %d\n",
219  urb->status);
220  kingsun->receiving = 0;
221  return;
222  }
223 
224  if (urb->actual_length == kingsun->max_rx) {
225  __u8 *bytes = urb->transfer_buffer;
226  int i;
227 
228  /* The very first byte in the buffer indicates the length of
229  valid data in the read. This byte must be in the range
230  1..kingsun->max_rx -1 . Values outside this range indicate
231  an uninitialized Rx buffer when the dongle has just been
232  plugged in. */
233  if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
234  for (i = 1; i <= bytes[0]; i++) {
235  async_unwrap_char(kingsun->netdev,
236  &kingsun->netdev->stats,
237  &kingsun->rx_buff, bytes[i]);
238  }
239  do_gettimeofday(&kingsun->rx_time);
240  kingsun->receiving =
241  (kingsun->rx_buff.state != OUTSIDE_FRAME)
242  ? 1 : 0;
243  }
244  } else if (urb->actual_length > 0) {
245  dev_err(&kingsun->usbdev->dev,
246  "%s(): Unexpected response length, expected %d got %d\n",
247  __func__, kingsun->max_rx, urb->actual_length);
248  }
249  /* This urb has already been filled in kingsun_net_open */
250  ret = usb_submit_urb(urb, GFP_ATOMIC);
251 }
252 
253 /*
254  * Function kingsun_net_open (dev)
255  *
256  * Network device is taken up. Usually this is done by "ifconfig irda0 up"
257  */
258 static int kingsun_net_open(struct net_device *netdev)
259 {
260  struct kingsun_cb *kingsun = netdev_priv(netdev);
261  int err = -ENOMEM;
262  char hwname[16];
263 
264  /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
265  kingsun->receiving = 0;
266 
267  /* Initialize for SIR to copy data directly into skb. */
268  kingsun->rx_buff.in_frame = FALSE;
269  kingsun->rx_buff.state = OUTSIDE_FRAME;
270  kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
271  kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
272  if (!kingsun->rx_buff.skb)
273  goto free_mem;
274 
275  skb_reserve(kingsun->rx_buff.skb, 1);
276  kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
277  do_gettimeofday(&kingsun->rx_time);
278 
279  kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
280  if (!kingsun->rx_urb)
281  goto free_mem;
282 
283  kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
284  if (!kingsun->tx_urb)
285  goto free_mem;
286 
287  /*
288  * Now that everything should be initialized properly,
289  * Open new IrLAP layer instance to take care of us...
290  */
291  sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
292  kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
293  if (!kingsun->irlap) {
294  dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
295  goto free_mem;
296  }
297 
298  /* Start first reception */
299  usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
300  usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
301  kingsun->in_buf, kingsun->max_rx,
302  kingsun_rcv_irq, kingsun, 1);
303  kingsun->rx_urb->status = 0;
304  err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
305  if (err) {
306  dev_err(&kingsun->usbdev->dev,
307  "first urb-submit failed: %d\n", err);
308  goto close_irlap;
309  }
310 
311  netif_start_queue(netdev);
312 
313  /* Situation at this point:
314  - all work buffers allocated
315  - urbs allocated and ready to fill
316  - max rx packet known (in max_rx)
317  - unwrap state machine initialized, in state outside of any frame
318  - receive request in progress
319  - IrLAP layer started, about to hand over packets to send
320  */
321 
322  return 0;
323 
324  close_irlap:
325  irlap_close(kingsun->irlap);
326  free_mem:
327  if (kingsun->tx_urb) {
328  usb_free_urb(kingsun->tx_urb);
329  kingsun->tx_urb = NULL;
330  }
331  if (kingsun->rx_urb) {
332  usb_free_urb(kingsun->rx_urb);
333  kingsun->rx_urb = NULL;
334  }
335  if (kingsun->rx_buff.skb) {
336  kfree_skb(kingsun->rx_buff.skb);
337  kingsun->rx_buff.skb = NULL;
338  kingsun->rx_buff.head = NULL;
339  }
340  return err;
341 }
342 
343 /*
344  * Function kingsun_net_close (kingsun)
345  *
346  * Network device is taken down. Usually this is done by
347  * "ifconfig irda0 down"
348  */
349 static int kingsun_net_close(struct net_device *netdev)
350 {
351  struct kingsun_cb *kingsun = netdev_priv(netdev);
352 
353  /* Stop transmit processing */
354  netif_stop_queue(netdev);
355 
356  /* Mop up receive && transmit urb's */
357  usb_kill_urb(kingsun->tx_urb);
358  usb_kill_urb(kingsun->rx_urb);
359 
360  usb_free_urb(kingsun->tx_urb);
361  usb_free_urb(kingsun->rx_urb);
362 
363  kingsun->tx_urb = NULL;
364  kingsun->rx_urb = NULL;
365 
366  kfree_skb(kingsun->rx_buff.skb);
367  kingsun->rx_buff.skb = NULL;
368  kingsun->rx_buff.head = NULL;
369  kingsun->rx_buff.in_frame = FALSE;
370  kingsun->rx_buff.state = OUTSIDE_FRAME;
371  kingsun->receiving = 0;
372 
373  /* Stop and remove instance of IrLAP */
374  if (kingsun->irlap)
375  irlap_close(kingsun->irlap);
376 
377  kingsun->irlap = NULL;
378 
379  return 0;
380 }
381 
382 /*
383  * IOCTLs : Extra out-of-band network commands...
384  */
385 static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
386  int cmd)
387 {
388  struct if_irda_req *irq = (struct if_irda_req *) rq;
389  struct kingsun_cb *kingsun = netdev_priv(netdev);
390  int ret = 0;
391 
392  switch (cmd) {
393  case SIOCSBANDWIDTH: /* Set bandwidth */
394  if (!capable(CAP_NET_ADMIN))
395  return -EPERM;
396 
397  /* Check if the device is still there */
398  if (netif_device_present(kingsun->netdev))
399  /* No observed commands for speed change */
400  ret = -EOPNOTSUPP;
401  break;
402 
403  case SIOCSMEDIABUSY: /* Set media busy */
404  if (!capable(CAP_NET_ADMIN))
405  return -EPERM;
406 
407  /* Check if the IrDA stack is still there */
408  if (netif_running(kingsun->netdev))
410  break;
411 
412  case SIOCGRECEIVING:
413  /* Only approximately true */
414  irq->ifr_receiving = kingsun->receiving;
415  break;
416 
417  default:
418  ret = -EOPNOTSUPP;
419  }
420 
421  return ret;
422 }
423 
424 static const struct net_device_ops kingsun_ops = {
425  .ndo_start_xmit = kingsun_hard_xmit,
426  .ndo_open = kingsun_net_open,
427  .ndo_stop = kingsun_net_close,
428  .ndo_do_ioctl = kingsun_net_ioctl,
429 };
430 
431 /*
432  * This routine is called by the USB subsystem for each new device
433  * in the system. We need to check if the device is ours, and in
434  * this case start handling it.
435  */
436 static int kingsun_probe(struct usb_interface *intf,
437  const struct usb_device_id *id)
438 {
439  struct usb_host_interface *interface;
441 
442  struct usb_device *dev = interface_to_usbdev(intf);
443  struct kingsun_cb *kingsun = NULL;
444  struct net_device *net = NULL;
445  int ret = -ENOMEM;
446  int pipe, maxp_in, maxp_out;
447  __u8 ep_in;
448  __u8 ep_out;
449 
450  /* Check that there really are two interrupt endpoints.
451  Check based on the one in drivers/usb/input/usbmouse.c
452  */
453  interface = intf->cur_altsetting;
454  if (interface->desc.bNumEndpoints != 2) {
455  dev_err(&intf->dev,
456  "kingsun-sir: expected 2 endpoints, found %d\n",
457  interface->desc.bNumEndpoints);
458  return -ENODEV;
459  }
460  endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
461  if (!usb_endpoint_is_int_in(endpoint)) {
462  dev_err(&intf->dev,
463  "kingsun-sir: endpoint 0 is not interrupt IN\n");
464  return -ENODEV;
465  }
466 
467  ep_in = endpoint->bEndpointAddress;
468  pipe = usb_rcvintpipe(dev, ep_in);
469  maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
470  if (maxp_in > 255 || maxp_in <= 1) {
471  dev_err(&intf->dev,
472  "endpoint 0 has max packet size %d not in range\n",
473  maxp_in);
474  return -ENODEV;
475  }
476 
477  endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
478  if (!usb_endpoint_is_int_out(endpoint)) {
479  dev_err(&intf->dev,
480  "kingsun-sir: endpoint 1 is not interrupt OUT\n");
481  return -ENODEV;
482  }
483 
484  ep_out = endpoint->bEndpointAddress;
485  pipe = usb_sndintpipe(dev, ep_out);
486  maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
487 
488  /* Allocate network device container. */
489  net = alloc_irdadev(sizeof(*kingsun));
490  if(!net)
491  goto err_out1;
492 
493  SET_NETDEV_DEV(net, &intf->dev);
494  kingsun = netdev_priv(net);
495  kingsun->irlap = NULL;
496  kingsun->tx_urb = NULL;
497  kingsun->rx_urb = NULL;
498  kingsun->ep_in = ep_in;
499  kingsun->ep_out = ep_out;
500  kingsun->in_buf = NULL;
501  kingsun->out_buf = NULL;
502  kingsun->max_rx = (__u8)maxp_in;
503  kingsun->max_tx = (__u8)maxp_out;
504  kingsun->netdev = net;
505  kingsun->usbdev = dev;
506  kingsun->rx_buff.in_frame = FALSE;
507  kingsun->rx_buff.state = OUTSIDE_FRAME;
508  kingsun->rx_buff.skb = NULL;
509  kingsun->receiving = 0;
510  spin_lock_init(&kingsun->lock);
511 
512  /* Allocate input buffer */
513  kingsun->in_buf = kmalloc(kingsun->max_rx, GFP_KERNEL);
514  if (!kingsun->in_buf)
515  goto free_mem;
516 
517  /* Allocate output buffer */
519  if (!kingsun->out_buf)
520  goto free_mem;
521 
522  printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, "
523  "Vendor: %x, Product: %x\n",
524  dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
525  le16_to_cpu(dev->descriptor.idProduct));
526 
527  /* Initialize QoS for this device */
529 
530  /* That's the Rx capability. */
531  kingsun->qos.baud_rate.bits &= IR_9600;
532  kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
533  irda_qos_bits_to_value(&kingsun->qos);
534 
535  /* Override the network functions we need to use */
536  net->netdev_ops = &kingsun_ops;
537 
538  ret = register_netdev(net);
539  if (ret != 0)
540  goto free_mem;
541 
542  dev_info(&net->dev, "IrDA: Registered KingSun/DonShine device %s\n",
543  net->name);
544 
545  usb_set_intfdata(intf, kingsun);
546 
547  /* Situation at this point:
548  - all work buffers allocated
549  - urbs not allocated, set to NULL
550  - max rx packet known (in max_rx)
551  - unwrap state machine (partially) initialized, but skb == NULL
552  */
553 
554  return 0;
555 
556 free_mem:
557  if (kingsun->out_buf) kfree(kingsun->out_buf);
558  if (kingsun->in_buf) kfree(kingsun->in_buf);
559  free_netdev(net);
560 err_out1:
561  return ret;
562 }
563 
564 /*
565  * The current device is removed, the USB layer tell us to shut it down...
566  */
567 static void kingsun_disconnect(struct usb_interface *intf)
568 {
569  struct kingsun_cb *kingsun = usb_get_intfdata(intf);
570 
571  if (!kingsun)
572  return;
573 
574  unregister_netdev(kingsun->netdev);
575 
576  /* Mop up receive && transmit urb's */
577  if (kingsun->tx_urb != NULL) {
578  usb_kill_urb(kingsun->tx_urb);
579  usb_free_urb(kingsun->tx_urb);
580  kingsun->tx_urb = NULL;
581  }
582  if (kingsun->rx_urb != NULL) {
583  usb_kill_urb(kingsun->rx_urb);
584  usb_free_urb(kingsun->rx_urb);
585  kingsun->rx_urb = NULL;
586  }
587 
588  kfree(kingsun->out_buf);
589  kfree(kingsun->in_buf);
590  free_netdev(kingsun->netdev);
591 
592  usb_set_intfdata(intf, NULL);
593 }
594 
595 #ifdef CONFIG_PM
596 /* USB suspend, so power off the transmitter/receiver */
597 static int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
598 {
599  struct kingsun_cb *kingsun = usb_get_intfdata(intf);
600 
601  netif_device_detach(kingsun->netdev);
602  if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
603  if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
604  return 0;
605 }
606 
607 /* Coming out of suspend, so reset hardware */
608 static int kingsun_resume(struct usb_interface *intf)
609 {
610  struct kingsun_cb *kingsun = usb_get_intfdata(intf);
611 
612  if (kingsun->rx_urb != NULL)
613  usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
614  netif_device_attach(kingsun->netdev);
615 
616  return 0;
617 }
618 #endif
619 
620 /*
621  * USB device callbacks
622  */
623 static struct usb_driver irda_driver = {
624  .name = "kingsun-sir",
625  .probe = kingsun_probe,
626  .disconnect = kingsun_disconnect,
627  .id_table = dongles,
628 #ifdef CONFIG_PM
629  .suspend = kingsun_suspend,
630  .resume = kingsun_resume,
631 #endif
632 };
633 
634 module_usb_driver(irda_driver);
635 
636 MODULE_AUTHOR("Alex Villacís Lasso <[email protected]>");
637 MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
638 MODULE_LICENSE("GPL");