[go: nahoru, domu]

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/slab.h>
68a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#include <linux/usb.h>
69a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#include <linux/device.h>
70a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#include <linux/crc32.h>
71a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
72a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#include <asm/unaligned.h>
73a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#include <asm/byteorder.h>
74a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#include <asm/uaccess.h>
75a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
76a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#include <net/irda/irda.h>
77a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#include <net/irda/wrapper.h>
78a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#include <net/irda/crc.h>
79a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
80a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/*
81a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso * According to lsusb, 0x07c0 is assigned to
82a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso * "Code Mercenaries Hard- und Software GmbH"
83a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso */
84a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#define KING_VENDOR_ID 0x07c0
85a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#define KING_PRODUCT_ID 0x4200
86a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
87a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/* These are the currently known USB ids */
88a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostatic struct usb_device_id dongles[] = {
89a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso    /* KingSun Co,Ltd  IrDA/USB Bridge */
90a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso    { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
91a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso    { }
92a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso};
93a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
94a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s LassoMODULE_DEVICE_TABLE(usb, dongles);
95a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
96a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#define KINGSUN_MTT 0x07
97a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
98a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#define KINGSUN_FIFO_SIZE		4096
99a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#define KINGSUN_EP_IN			0
100a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#define KINGSUN_EP_OUT			1
101a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
102a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostruct kingsun_cb {
103a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct usb_device *usbdev;      /* init: probe_irda */
104a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct net_device *netdev;      /* network layer */
105a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct irlap_cb   *irlap;       /* The link layer we are binded to */
106af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger
107a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct qos_info   qos;
108a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
109a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	__u8		  *in_buf;	/* receive buffer */
110a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	__u8		  *out_buf;	/* transmit buffer */
111a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	__u8		  max_rx;	/* max. atomic read from dongle
112a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso					   (usually 8), also size of in_buf */
113a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	__u8		  max_tx;	/* max. atomic write to dongle
114a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso					   (usually 8) */
115a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
116a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	iobuff_t  	  rx_buff;	/* receive unwrap state machine */
117a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct timeval	  rx_time;
118a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	spinlock_t lock;
119a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	int receiving;
120a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
121a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	__u8 ep_in;
122a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	__u8 ep_out;
123a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
124a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct urb	 *tx_urb;
125a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct urb	 *rx_urb;
126a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso};
127a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
128a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/* Callback transmission routine */
129a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostatic void kingsun_send_irq(struct urb *urb)
130a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso{
131a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct kingsun_cb *kingsun = urb->context;
132a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct net_device *netdev = kingsun->netdev;
133a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
134a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* in process of stopping, just drop data */
135a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (!netif_running(kingsun->netdev)) {
1366f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&kingsun->usbdev->dev,
1376f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"kingsun_send_irq: Network not running!\n");
138a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		return;
139a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
140a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
141a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* unlink, shutdown, unplug, other nasties */
142a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (urb->status != 0) {
1436f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&kingsun->usbdev->dev,
1446f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"kingsun_send_irq: urb asynchronously failed - %d\n",
1456f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			urb->status);
146a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
147a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	netif_wake_queue(netdev);
148a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso}
149a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
150a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/*
151a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso * Called from net/core when new frame is available.
152a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso */
1536518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemmingerstatic netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb,
1546518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemminger					   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	netif_stop_queue(netdev);
161a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
162a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* the IRDA wrapping routines don't deal with non linear skb */
163a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	SKB_LINEAR_ASSERT(skb);
164a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
165a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun = netdev_priv(netdev);
166a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
167a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	spin_lock(&kingsun->lock);
168a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
169a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* Append data to the end of whatever data remains to be transmitted */
170a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	wraplen = async_wrap_skb(skb,
171a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		kingsun->out_buf,
172a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		KINGSUN_FIFO_SIZE);
173a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
174a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* Calculate how much data can be transmitted in this urb */
175a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
176a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
177a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		kingsun->out_buf, wraplen, kingsun_send_irq,
178a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		kingsun, 1);
179a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
180a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
1816f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&kingsun->usbdev->dev,
1826f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"kingsun_hard_xmit: failed tx_urb submit: %d\n", ret);
183a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		switch (ret) {
184a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		case -ENODEV:
185a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		case -EPIPE:
186a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso			break;
187a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		default:
188af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger			netdev->stats.tx_errors++;
189a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso			netif_start_queue(netdev);
190a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		}
191a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	} else {
192af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger		netdev->stats.tx_packets++;
193af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger		netdev->stats.tx_bytes += skb->len;
194a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
195a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
196a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	dev_kfree_skb(skb);
197a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	spin_unlock(&kingsun->lock);
198a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
1994bd73ae2682d9069746bb049a416d9ab90c6684bPatrick McHardy	return NETDEV_TX_OK;
200a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso}
201a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
202a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/* Receive callback function */
203a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostatic void kingsun_rcv_irq(struct urb *urb)
204a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso{
205a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct kingsun_cb *kingsun = urb->context;
206a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	int ret;
207a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
208a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* in process of stopping, just drop data */
209a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (!netif_running(kingsun->netdev)) {
210a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		kingsun->receiving = 0;
211a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		return;
212a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
213a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
214a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* unlink, shutdown, unplug, other nasties */
215a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (urb->status != 0) {
2166f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&kingsun->usbdev->dev,
2176f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"kingsun_rcv_irq: urb asynchronously failed - %d\n",
2186f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			urb->status);
219a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		kingsun->receiving = 0;
220a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		return;
221a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
222a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
223a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (urb->actual_length == kingsun->max_rx) {
224a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		__u8 *bytes = urb->transfer_buffer;
225a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		int i;
226a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
227a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		/* The very first byte in the buffer indicates the length of
228a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		   valid data in the read. This byte must be in the range
229a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		   1..kingsun->max_rx -1 . Values outside this range indicate
230a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		   an uninitialized Rx buffer when the dongle has just been
231a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		   plugged in. */
232a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
233a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso			for (i = 1; i <= bytes[0]; i++) {
234a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso				async_unwrap_char(kingsun->netdev,
235af0490810cfa159b4894ddecfc5eb2e4432fb976Stephen Hemminger						  &kingsun->netdev->stats,
236a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso						  &kingsun->rx_buff, bytes[i]);
237a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso			}
238a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso			do_gettimeofday(&kingsun->rx_time);
239a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso			kingsun->receiving =
240a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso				(kingsun->rx_buff.state != OUTSIDE_FRAME)
241a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso				? 1 : 0;
242a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		}
243a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	} else if (urb->actual_length > 0) {
2446f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&kingsun->usbdev->dev,
2456f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"%s(): Unexpected response length, expected %d got %d\n",
2466f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			__func__, kingsun->max_rx, urb->actual_length);
247a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
248a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* This urb has already been filled in kingsun_net_open */
249a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	ret = usb_submit_urb(urb, GFP_ATOMIC);
250a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso}
251a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
252a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/*
253a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso * Function kingsun_net_open (dev)
254a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso *
255a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso *    Network device is taken up. Usually this is done by "ifconfig irda0 up"
256a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso */
257a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostatic int kingsun_net_open(struct net_device *netdev)
258a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso{
259a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct kingsun_cb *kingsun = netdev_priv(netdev);
260a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	int err = -ENOMEM;
261a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	char hwname[16];
262a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
263a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
264a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->receiving = 0;
265a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
266a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* Initialize for SIR to copy data directly into skb.  */
267a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->rx_buff.in_frame = FALSE;
268a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->rx_buff.state = OUTSIDE_FRAME;
269a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
270a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
271a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (!kingsun->rx_buff.skb)
272a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		goto free_mem;
273a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
274a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	skb_reserve(kingsun->rx_buff.skb, 1);
275a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
276a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	do_gettimeofday(&kingsun->rx_time);
277a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
278a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
279a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (!kingsun->rx_urb)
280a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		goto free_mem;
281a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
282a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
283a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (!kingsun->tx_urb)
284a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		goto free_mem;
285a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
286a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/*
287a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	 * Now that everything should be initialized properly,
288a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	 * Open new IrLAP layer instance to take care of us...
289a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	 */
290a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
291a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
292a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (!kingsun->irlap) {
2936f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
294a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		goto free_mem;
295a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
296a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
297a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* Start first reception */
298a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
299a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso			  usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
300a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso			  kingsun->in_buf, kingsun->max_rx,
301a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso			  kingsun_rcv_irq, kingsun, 1);
302a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kingsun->rx_urb->status = 0;
303a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
304a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (err) {
3056f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&kingsun->usbdev->dev,
3066f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"first urb-submit failed: %d\n", 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
4239b634007d5694178c4e142fbc5f9dbcd767eafbdStephen Hemmingerstatic const struct net_device_ops kingsun_ops = {
4246518bbb803fe02b15a3211c8db2afdff0ac4f808Stephen Hemminger	.ndo_start_xmit	     = kingsun_hard_xmit,
4259b634007d5694178c4e142fbc5f9dbcd767eafbdStephen Hemminger	.ndo_open            = kingsun_net_open,
4269b634007d5694178c4e142fbc5f9dbcd767eafbdStephen Hemminger	.ndo_stop            = kingsun_net_close,
4279b634007d5694178c4e142fbc5f9dbcd767eafbdStephen Hemminger	.ndo_do_ioctl        = kingsun_net_ioctl,
4289b634007d5694178c4e142fbc5f9dbcd767eafbdStephen Hemminger};
429a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
430a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/*
431a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso * This routine is called by the USB subsystem for each new device
432a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso * in the system. We need to check if the device is ours, and in
433a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso * this case start handling it.
434a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso */
435a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostatic int kingsun_probe(struct usb_interface *intf,
436a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		      const struct usb_device_id *id)
437a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso{
438a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct usb_host_interface *interface;
439a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct usb_endpoint_descriptor *endpoint;
440a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
441a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct usb_device *dev = interface_to_usbdev(intf);
442a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct kingsun_cb *kingsun = NULL;
443a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct net_device *net = NULL;
444a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	int ret = -ENOMEM;
445a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	int pipe, maxp_in, maxp_out;
446a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	__u8 ep_in;
447a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	__u8 ep_out;
448a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
449a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* Check that there really are two interrupt endpoints.
450a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	   Check based on the one in drivers/usb/input/usbmouse.c
451a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	 */
452a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	interface = intf->cur_altsetting;
453a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (interface->desc.bNumEndpoints != 2) {
4546f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&intf->dev,
4556f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"kingsun-sir: expected 2 endpoints, found %d\n",
4566f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			interface->desc.bNumEndpoints);
457a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		return -ENODEV;
458a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
459a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
460a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (!usb_endpoint_is_int_in(endpoint)) {
4616f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&intf->dev,
4626f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"kingsun-sir: endpoint 0 is not interrupt IN\n");
463a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		return -ENODEV;
464a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
465a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
466a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	ep_in = endpoint->bEndpointAddress;
467a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	pipe = usb_rcvintpipe(dev, ep_in);
468a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
469a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (maxp_in > 255 || maxp_in <= 1) {
4706f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&intf->dev,
4716f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"endpoint 0 has max packet size %d not in range\n",
4726f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			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)) {
4786f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman		dev_err(&intf->dev,
4796f0d27ff97f66c041e2adc86b61e8957e8dd056dGreg Kroah-Hartman			"kingsun-sir: endpoint 1 is not interrupt OUT\n");
480a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		return -ENODEV;
481a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
482a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
483a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	ep_out = endpoint->bEndpointAddress;
484a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	pipe = usb_sndintpipe(dev, ep_out);
485a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
486a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
487a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* Allocate network device container. */
488a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	net = alloc_irdadev(sizeof(*kingsun));
489a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if(!net)
490a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		goto err_out1;
491a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
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 */
5359b634007d5694178c4e142fbc5f9dbcd767eafbdStephen Hemminger	net->netdev_ops = &kingsun_ops;
536a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
537a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	ret = register_netdev(net);
538a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (ret != 0)
539a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		goto free_mem;
540a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
541880c9c66a60c0aa4fb4dac2da9679da5f8f41903Greg Kroah-Hartman	dev_info(&net->dev, "IrDA: Registered KingSun/DonShine device %s\n",
542880c9c66a60c0aa4fb4dac2da9679da5f8f41903Greg Kroah-Hartman		 net->name);
543a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
544a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	usb_set_intfdata(intf, kingsun);
545a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
546a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* Situation at this point:
547a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	   - all work buffers allocated
548a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	   - urbs not allocated, set to NULL
549a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	   - max rx packet known (in max_rx)
550a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	   - unwrap state machine (partially) initialized, but skb == NULL
551a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	 */
552a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
553a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	return 0;
554a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
555a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassofree_mem:
55644f71cef92eb65bc4382ef3fb04a8e1437bda2d7Fabian Frederick	kfree(kingsun->out_buf);
55744f71cef92eb65bc4382ef3fb04a8e1437bda2d7Fabian Frederick	kfree(kingsun->in_buf);
558a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	free_netdev(net);
559a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassoerr_out1:
560a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	return ret;
561a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso}
562a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
563a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/*
564a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso * The current device is removed, the USB layer tell us to shut it down...
565a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso */
566a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostatic void kingsun_disconnect(struct usb_interface *intf)
567a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso{
568a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct kingsun_cb *kingsun = usb_get_intfdata(intf);
569a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
570a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (!kingsun)
571a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		return;
572a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
573a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	unregister_netdev(kingsun->netdev);
574a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
575a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	/* Mop up receive && transmit urb's */
576a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (kingsun->tx_urb != NULL) {
577a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		usb_kill_urb(kingsun->tx_urb);
578a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		usb_free_urb(kingsun->tx_urb);
579a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		kingsun->tx_urb = NULL;
580a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
581a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (kingsun->rx_urb != NULL) {
582a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		usb_kill_urb(kingsun->rx_urb);
583a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		usb_free_urb(kingsun->rx_urb);
584a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		kingsun->rx_urb = NULL;
585a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	}
586a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
587a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kfree(kingsun->out_buf);
588a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	kfree(kingsun->in_buf);
589a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	free_netdev(kingsun->netdev);
590a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
591a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	usb_set_intfdata(intf, NULL);
592a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso}
593a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
594a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#ifdef CONFIG_PM
595a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/* USB suspend, so power off the transmitter/receiver */
596a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostatic int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
597a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso{
598a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct kingsun_cb *kingsun = usb_get_intfdata(intf);
599a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
600a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	netif_device_detach(kingsun->netdev);
601a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
602a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
603a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	return 0;
604a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso}
605a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
606a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/* Coming out of suspend, so reset hardware */
607a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostatic int kingsun_resume(struct usb_interface *intf)
608a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso{
609a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	struct kingsun_cb *kingsun = usb_get_intfdata(intf);
610a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
611a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	if (kingsun->rx_urb != NULL)
612a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso		usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
613a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	netif_device_attach(kingsun->netdev);
614a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
615a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	return 0;
616a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso}
617a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#endif
618a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
619a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso/*
620a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso * USB device callbacks
621a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso */
622a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lassostatic struct usb_driver irda_driver = {
623a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	.name		= "kingsun-sir",
624a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	.probe		= kingsun_probe,
625a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	.disconnect	= kingsun_disconnect,
626a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	.id_table	= dongles,
627a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#ifdef CONFIG_PM
628a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	.suspend	= kingsun_suspend,
629a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso	.resume		= kingsun_resume,
630a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso#endif
631a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso};
632a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
633d632eb1bf22e11def74e4e53cc47d790fbdba105Greg Kroah-Hartmanmodule_usb_driver(irda_driver);
634a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s Lasso
63566f5e51ed5a300291b34bf3e2b1e22ac28ca3631Samuel OrtizMODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
636a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s LassoMODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
637a2af421f1819946556c6f467b1efdd0dc84af4d5Alex Villac�s LassoMODULE_LICENSE("GPL");
638