PageRenderTime 73ms CodeModel.GetById 11ms app.highlight 56ms RepoModel.GetById 2ms app.codeStats 0ms

/drivers/net/irda/kingsun-sir.c

http://github.com/mirrors/linux
C | 634 lines | 387 code | 97 blank | 150 comment | 53 complexity | bc1fbac2ffcdefbe38ad0b5eba0a170f MD5 | raw 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 <a_villacis@palosanto.com>
  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/slab.h>
 68#include <linux/usb.h>
 69#include <linux/device.h>
 70#include <linux/crc32.h>
 71
 72#include <asm/unaligned.h>
 73#include <asm/byteorder.h>
 74#include <asm/uaccess.h>
 75
 76#include <net/irda/irda.h>
 77#include <net/irda/wrapper.h>
 78#include <net/irda/crc.h>
 79
 80/*
 81 * According to lsusb, 0x07c0 is assigned to
 82 * "Code Mercenaries Hard- und Software GmbH"
 83 */
 84#define KING_VENDOR_ID 0x07c0
 85#define KING_PRODUCT_ID 0x4200
 86
 87/* These are the currently known USB ids */
 88static struct usb_device_id dongles[] = {
 89    /* KingSun Co,Ltd  IrDA/USB Bridge */
 90    { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
 91    { }
 92};
 93
 94MODULE_DEVICE_TABLE(usb, dongles);
 95
 96#define KINGSUN_MTT 0x07
 97
 98#define KINGSUN_FIFO_SIZE		4096
 99#define KINGSUN_EP_IN			0
100#define KINGSUN_EP_OUT			1
101
102struct kingsun_cb {
103	struct usb_device *usbdev;      /* init: probe_irda */
104	struct net_device *netdev;      /* network layer */
105	struct irlap_cb   *irlap;       /* The link layer we are binded to */
106
107	struct qos_info   qos;
108
109	__u8		  *in_buf;	/* receive buffer */
110	__u8		  *out_buf;	/* transmit buffer */
111	__u8		  max_rx;	/* max. atomic read from dongle
112					   (usually 8), also size of in_buf */
113	__u8		  max_tx;	/* max. atomic write to dongle
114					   (usually 8) */
115
116	iobuff_t  	  rx_buff;	/* receive unwrap state machine */
117	spinlock_t lock;
118	int receiving;
119
120	__u8 ep_in;
121	__u8 ep_out;
122
123	struct urb	 *tx_urb;
124	struct urb	 *rx_urb;
125};
126
127/* Callback transmission routine */
128static void kingsun_send_irq(struct urb *urb)
129{
130	struct kingsun_cb *kingsun = urb->context;
131	struct net_device *netdev = kingsun->netdev;
132
133	/* in process of stopping, just drop data */
134	if (!netif_running(kingsun->netdev)) {
135		dev_err(&kingsun->usbdev->dev,
136			"kingsun_send_irq: Network not running!\n");
137		return;
138	}
139
140	/* unlink, shutdown, unplug, other nasties */
141	if (urb->status != 0) {
142		dev_err(&kingsun->usbdev->dev,
143			"kingsun_send_irq: urb asynchronously failed - %d\n",
144			urb->status);
145	}
146	netif_wake_queue(netdev);
147}
148
149/*
150 * Called from net/core when new frame is available.
151 */
152static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb,
153					   struct net_device *netdev)
154{
155	struct kingsun_cb *kingsun;
156	int wraplen;
157	int ret = 0;
158
159	netif_stop_queue(netdev);
160
161	/* the IRDA wrapping routines don't deal with non linear skb */
162	SKB_LINEAR_ASSERT(skb);
163
164	kingsun = netdev_priv(netdev);
165
166	spin_lock(&kingsun->lock);
167
168	/* Append data to the end of whatever data remains to be transmitted */
169	wraplen = async_wrap_skb(skb,
170		kingsun->out_buf,
171		KINGSUN_FIFO_SIZE);
172
173	/* Calculate how much data can be transmitted in this urb */
174	usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
175		usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
176		kingsun->out_buf, wraplen, kingsun_send_irq,
177		kingsun, 1);
178
179	if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
180		dev_err(&kingsun->usbdev->dev,
181			"kingsun_hard_xmit: failed tx_urb submit: %d\n", ret);
182		switch (ret) {
183		case -ENODEV:
184		case -EPIPE:
185			break;
186		default:
187			netdev->stats.tx_errors++;
188			netif_start_queue(netdev);
189		}
190	} else {
191		netdev->stats.tx_packets++;
192		netdev->stats.tx_bytes += skb->len;
193	}
194
195	dev_kfree_skb(skb);
196	spin_unlock(&kingsun->lock);
197
198	return NETDEV_TX_OK;
199}
200
201/* Receive callback function */
202static void kingsun_rcv_irq(struct urb *urb)
203{
204	struct kingsun_cb *kingsun = urb->context;
205	int ret;
206
207	/* in process of stopping, just drop data */
208	if (!netif_running(kingsun->netdev)) {
209		kingsun->receiving = 0;
210		return;
211	}
212
213	/* unlink, shutdown, unplug, other nasties */
214	if (urb->status != 0) {
215		dev_err(&kingsun->usbdev->dev,
216			"kingsun_rcv_irq: urb asynchronously failed - %d\n",
217			urb->status);
218		kingsun->receiving = 0;
219		return;
220	}
221
222	if (urb->actual_length == kingsun->max_rx) {
223		__u8 *bytes = urb->transfer_buffer;
224		int i;
225
226		/* The very first byte in the buffer indicates the length of
227		   valid data in the read. This byte must be in the range
228		   1..kingsun->max_rx -1 . Values outside this range indicate
229		   an uninitialized Rx buffer when the dongle has just been
230		   plugged in. */
231		if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
232			for (i = 1; i <= bytes[0]; i++) {
233				async_unwrap_char(kingsun->netdev,
234						  &kingsun->netdev->stats,
235						  &kingsun->rx_buff, bytes[i]);
236			}
237			kingsun->receiving =
238				(kingsun->rx_buff.state != OUTSIDE_FRAME)
239				? 1 : 0;
240		}
241	} else if (urb->actual_length > 0) {
242		dev_err(&kingsun->usbdev->dev,
243			"%s(): Unexpected response length, expected %d got %d\n",
244			__func__, kingsun->max_rx, urb->actual_length);
245	}
246	/* This urb has already been filled in kingsun_net_open */
247	ret = usb_submit_urb(urb, GFP_ATOMIC);
248}
249
250/*
251 * Function kingsun_net_open (dev)
252 *
253 *    Network device is taken up. Usually this is done by "ifconfig irda0 up"
254 */
255static int kingsun_net_open(struct net_device *netdev)
256{
257	struct kingsun_cb *kingsun = netdev_priv(netdev);
258	int err = -ENOMEM;
259	char hwname[16];
260
261	/* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
262	kingsun->receiving = 0;
263
264	/* Initialize for SIR to copy data directly into skb.  */
265	kingsun->rx_buff.in_frame = FALSE;
266	kingsun->rx_buff.state = OUTSIDE_FRAME;
267	kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
268	kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
269	if (!kingsun->rx_buff.skb)
270		goto free_mem;
271
272	skb_reserve(kingsun->rx_buff.skb, 1);
273	kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
274
275	kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
276	if (!kingsun->rx_urb)
277		goto free_mem;
278
279	kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
280	if (!kingsun->tx_urb)
281		goto free_mem;
282
283	/*
284	 * Now that everything should be initialized properly,
285	 * Open new IrLAP layer instance to take care of us...
286	 */
287	sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
288	kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
289	if (!kingsun->irlap) {
290		dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
291		goto free_mem;
292	}
293
294	/* Start first reception */
295	usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
296			  usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
297			  kingsun->in_buf, kingsun->max_rx,
298			  kingsun_rcv_irq, kingsun, 1);
299	kingsun->rx_urb->status = 0;
300	err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
301	if (err) {
302		dev_err(&kingsun->usbdev->dev,
303			"first urb-submit failed: %d\n", err);
304		goto close_irlap;
305	}
306
307	netif_start_queue(netdev);
308
309	/* Situation at this point:
310	   - all work buffers allocated
311	   - urbs allocated and ready to fill
312	   - max rx packet known (in max_rx)
313	   - unwrap state machine initialized, in state outside of any frame
314	   - receive request in progress
315	   - IrLAP layer started, about to hand over packets to send
316	 */
317
318	return 0;
319
320 close_irlap:
321	irlap_close(kingsun->irlap);
322 free_mem:
323	if (kingsun->tx_urb) {
324		usb_free_urb(kingsun->tx_urb);
325		kingsun->tx_urb = NULL;
326	}
327	if (kingsun->rx_urb) {
328		usb_free_urb(kingsun->rx_urb);
329		kingsun->rx_urb = NULL;
330	}
331	if (kingsun->rx_buff.skb) {
332		kfree_skb(kingsun->rx_buff.skb);
333		kingsun->rx_buff.skb = NULL;
334		kingsun->rx_buff.head = NULL;
335	}
336	return err;
337}
338
339/*
340 * Function kingsun_net_close (kingsun)
341 *
342 *    Network device is taken down. Usually this is done by
343 *    "ifconfig irda0 down"
344 */
345static int kingsun_net_close(struct net_device *netdev)
346{
347	struct kingsun_cb *kingsun = netdev_priv(netdev);
348
349	/* Stop transmit processing */
350	netif_stop_queue(netdev);
351
352	/* Mop up receive && transmit urb's */
353	usb_kill_urb(kingsun->tx_urb);
354	usb_kill_urb(kingsun->rx_urb);
355
356	usb_free_urb(kingsun->tx_urb);
357	usb_free_urb(kingsun->rx_urb);
358
359	kingsun->tx_urb = NULL;
360	kingsun->rx_urb = NULL;
361
362	kfree_skb(kingsun->rx_buff.skb);
363	kingsun->rx_buff.skb = NULL;
364	kingsun->rx_buff.head = NULL;
365	kingsun->rx_buff.in_frame = FALSE;
366	kingsun->rx_buff.state = OUTSIDE_FRAME;
367	kingsun->receiving = 0;
368
369	/* Stop and remove instance of IrLAP */
370	if (kingsun->irlap)
371		irlap_close(kingsun->irlap);
372
373	kingsun->irlap = NULL;
374
375	return 0;
376}
377
378/*
379 * IOCTLs : Extra out-of-band network commands...
380 */
381static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
382			     int cmd)
383{
384	struct if_irda_req *irq = (struct if_irda_req *) rq;
385	struct kingsun_cb *kingsun = netdev_priv(netdev);
386	int ret = 0;
387
388	switch (cmd) {
389	case SIOCSBANDWIDTH: /* Set bandwidth */
390		if (!capable(CAP_NET_ADMIN))
391			return -EPERM;
392
393		/* Check if the device is still there */
394		if (netif_device_present(kingsun->netdev))
395			/* No observed commands for speed change */
396			ret = -EOPNOTSUPP;
397		break;
398
399	case SIOCSMEDIABUSY: /* Set media busy */
400		if (!capable(CAP_NET_ADMIN))
401			return -EPERM;
402
403		/* Check if the IrDA stack is still there */
404		if (netif_running(kingsun->netdev))
405			irda_device_set_media_busy(kingsun->netdev, TRUE);
406		break;
407
408	case SIOCGRECEIVING:
409		/* Only approximately true */
410		irq->ifr_receiving = kingsun->receiving;
411		break;
412
413	default:
414		ret = -EOPNOTSUPP;
415	}
416
417	return ret;
418}
419
420static const struct net_device_ops kingsun_ops = {
421	.ndo_start_xmit	     = kingsun_hard_xmit,
422	.ndo_open            = kingsun_net_open,
423	.ndo_stop            = kingsun_net_close,
424	.ndo_do_ioctl        = kingsun_net_ioctl,
425};
426
427/*
428 * This routine is called by the USB subsystem for each new device
429 * in the system. We need to check if the device is ours, and in
430 * this case start handling it.
431 */
432static int kingsun_probe(struct usb_interface *intf,
433		      const struct usb_device_id *id)
434{
435	struct usb_host_interface *interface;
436	struct usb_endpoint_descriptor *endpoint;
437
438	struct usb_device *dev = interface_to_usbdev(intf);
439	struct kingsun_cb *kingsun = NULL;
440	struct net_device *net = NULL;
441	int ret = -ENOMEM;
442	int pipe, maxp_in, maxp_out;
443	__u8 ep_in;
444	__u8 ep_out;
445
446	/* Check that there really are two interrupt endpoints.
447	   Check based on the one in drivers/usb/input/usbmouse.c
448	 */
449	interface = intf->cur_altsetting;
450	if (interface->desc.bNumEndpoints != 2) {
451		dev_err(&intf->dev,
452			"kingsun-sir: expected 2 endpoints, found %d\n",
453			interface->desc.bNumEndpoints);
454		return -ENODEV;
455	}
456	endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
457	if (!usb_endpoint_is_int_in(endpoint)) {
458		dev_err(&intf->dev,
459			"kingsun-sir: endpoint 0 is not interrupt IN\n");
460		return -ENODEV;
461	}
462
463	ep_in = endpoint->bEndpointAddress;
464	pipe = usb_rcvintpipe(dev, ep_in);
465	maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
466	if (maxp_in > 255 || maxp_in <= 1) {
467		dev_err(&intf->dev,
468			"endpoint 0 has max packet size %d not in range\n",
469			maxp_in);
470		return -ENODEV;
471	}
472
473	endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
474	if (!usb_endpoint_is_int_out(endpoint)) {
475		dev_err(&intf->dev,
476			"kingsun-sir: endpoint 1 is not interrupt OUT\n");
477		return -ENODEV;
478	}
479
480	ep_out = endpoint->bEndpointAddress;
481	pipe = usb_sndintpipe(dev, ep_out);
482	maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
483
484	/* Allocate network device container. */
485	net = alloc_irdadev(sizeof(*kingsun));
486	if(!net)
487		goto err_out1;
488
489	SET_NETDEV_DEV(net, &intf->dev);
490	kingsun = netdev_priv(net);
491	kingsun->irlap = NULL;
492	kingsun->tx_urb = NULL;
493	kingsun->rx_urb = NULL;
494	kingsun->ep_in = ep_in;
495	kingsun->ep_out = ep_out;
496	kingsun->in_buf = NULL;
497	kingsun->out_buf = NULL;
498	kingsun->max_rx = (__u8)maxp_in;
499	kingsun->max_tx = (__u8)maxp_out;
500	kingsun->netdev = net;
501	kingsun->usbdev = dev;
502	kingsun->rx_buff.in_frame = FALSE;
503	kingsun->rx_buff.state = OUTSIDE_FRAME;
504	kingsun->rx_buff.skb = NULL;
505	kingsun->receiving = 0;
506	spin_lock_init(&kingsun->lock);
507
508	/* Allocate input buffer */
509	kingsun->in_buf = kmalloc(kingsun->max_rx, GFP_KERNEL);
510	if (!kingsun->in_buf)
511		goto free_mem;
512
513	/* Allocate output buffer */
514	kingsun->out_buf = kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
515	if (!kingsun->out_buf)
516		goto free_mem;
517
518	printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, "
519		"Vendor: %x, Product: %x\n",
520	       dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
521	       le16_to_cpu(dev->descriptor.idProduct));
522
523	/* Initialize QoS for this device */
524	irda_init_max_qos_capabilies(&kingsun->qos);
525
526	/* That's the Rx capability. */
527	kingsun->qos.baud_rate.bits       &= IR_9600;
528	kingsun->qos.min_turn_time.bits   &= KINGSUN_MTT;
529	irda_qos_bits_to_value(&kingsun->qos);
530
531	/* Override the network functions we need to use */
532	net->netdev_ops = &kingsun_ops;
533
534	ret = register_netdev(net);
535	if (ret != 0)
536		goto free_mem;
537
538	dev_info(&net->dev, "IrDA: Registered KingSun/DonShine device %s\n",
539		 net->name);
540
541	usb_set_intfdata(intf, kingsun);
542
543	/* Situation at this point:
544	   - all work buffers allocated
545	   - urbs not allocated, set to NULL
546	   - max rx packet known (in max_rx)
547	   - unwrap state machine (partially) initialized, but skb == NULL
548	 */
549
550	return 0;
551
552free_mem:
553	kfree(kingsun->out_buf);
554	kfree(kingsun->in_buf);
555	free_netdev(net);
556err_out1:
557	return ret;
558}
559
560/*
561 * The current device is removed, the USB layer tell us to shut it down...
562 */
563static void kingsun_disconnect(struct usb_interface *intf)
564{
565	struct kingsun_cb *kingsun = usb_get_intfdata(intf);
566
567	if (!kingsun)
568		return;
569
570	unregister_netdev(kingsun->netdev);
571
572	/* Mop up receive && transmit urb's */
573	if (kingsun->tx_urb != NULL) {
574		usb_kill_urb(kingsun->tx_urb);
575		usb_free_urb(kingsun->tx_urb);
576		kingsun->tx_urb = NULL;
577	}
578	if (kingsun->rx_urb != NULL) {
579		usb_kill_urb(kingsun->rx_urb);
580		usb_free_urb(kingsun->rx_urb);
581		kingsun->rx_urb = NULL;
582	}
583
584	kfree(kingsun->out_buf);
585	kfree(kingsun->in_buf);
586	free_netdev(kingsun->netdev);
587
588	usb_set_intfdata(intf, NULL);
589}
590
591#ifdef CONFIG_PM
592/* USB suspend, so power off the transmitter/receiver */
593static int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
594{
595	struct kingsun_cb *kingsun = usb_get_intfdata(intf);
596
597	netif_device_detach(kingsun->netdev);
598	if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
599	if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
600	return 0;
601}
602
603/* Coming out of suspend, so reset hardware */
604static int kingsun_resume(struct usb_interface *intf)
605{
606	struct kingsun_cb *kingsun = usb_get_intfdata(intf);
607
608	if (kingsun->rx_urb != NULL)
609		usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
610	netif_device_attach(kingsun->netdev);
611
612	return 0;
613}
614#endif
615
616/*
617 * USB device callbacks
618 */
619static struct usb_driver irda_driver = {
620	.name		= "kingsun-sir",
621	.probe		= kingsun_probe,
622	.disconnect	= kingsun_disconnect,
623	.id_table	= dongles,
624#ifdef CONFIG_PM
625	.suspend	= kingsun_suspend,
626	.resume		= kingsun_resume,
627#endif
628};
629
630module_usb_driver(irda_driver);
631
632MODULE_AUTHOR("Alex VillacĂ­s Lasso <a_villacis@palosanto.com>");
633MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
634MODULE_LICENSE("GPL");