[go: nahoru, domu]

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