blob: 55322fb92cf1c36508bb7f9a0ba68e5f7a234cbd [file] [log] [blame]
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -07001/*****************************************************************************
2*
3* Filename: ks959-sir.c
4* Version: 0.1.2
5* Description: Irda KingSun KS-959 USB Dongle
6* Status: Experimental
7* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
8* with help from Domen Puncer <domen@coderock.org>
9*
10* Based on stir4200, mcs7780, kingsun-sir drivers.
11*
12* This program is free software; you can redistribute it and/or modify
13* it under the terms of the GNU General Public License as published by
14* the Free Software Foundation; either version 2 of the License.
15*
16* This program is distributed in the hope that it will be useful,
17* but WITHOUT ANY WARRANTY; without even the implied warranty of
18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19* GNU General Public License for more details.
20*
21* You should have received a copy of the GNU General Public License
22* along with this program; if not, write to the Free Software
23* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*
25*****************************************************************************/
26
27/*
28 * Following is my most current (2007-07-17) understanding of how the Kingsun
29 * KS-959 dongle is supposed to work. This information was deduced by
30 * reverse-engineering and examining the USB traffic captured with USBSnoopy
31 * from the WinXP driver. Feel free to update here as more of the dongle is
32 * known.
33 *
34 * My most sincere thanks must go to Domen Puncer <domen@coderock.org> for
35 * invaluable help in cracking the obfuscation and padding required for this
36 * dongle.
37 *
38 * General: This dongle exposes one interface with one interrupt IN endpoint.
39 * However, the interrupt endpoint is NOT used at all for this dongle. Instead,
40 * this dongle uses control transfers for everything, including sending and
41 * receiving the IrDA frame data. Apparently the interrupt endpoint is just a
42 * dummy to ensure the dongle has a valid interface to present to the PC.And I
43 * thought the DonShine dongle was weird... In addition, this dongle uses
44 * obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent
45 * and received, from the dongle. I call it obfuscation because the XOR keying
46 * and padding required to produce an USB traffic acceptable for the dongle can
47 * not be explained by any other technical requirement.
48 *
49 * Transmission: To transmit an IrDA frame, the driver must prepare a control
50 * URB with the following as a setup packet:
51 * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
52 * bRequest 0x09
53 * wValue <length of valid data before padding, little endian>
54 * wIndex 0x0000
55 * wLength <length of padded data>
56 * The payload packet must be manually wrapped and escaped (as in stir4200.c),
57 * then padded and obfuscated before being sent. Both padding and obfuscation
58 * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the
59 * designer/programmer of the dongle used his name as a source for the
60 * obfuscation. WTF?!
61 * Apparently the dongle cannot handle payloads larger than 256 bytes. The
62 * driver has to perform fragmentation in order to send anything larger than
63 * this limit.
64 *
65 * Reception: To receive data, the driver must poll the dongle regularly (like
66 * kingsun-sir.c) with control URBs and the following as a setup packet:
67 * bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE
68 * bRequest 0x01
69 * wValue 0x0200
70 * wIndex 0x0000
71 * wLength 0x0800 (size of available buffer)
72 * If there is data to be read, it will be returned as the response payload.
73 * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate
74 * it, the driver must XOR every byte, in sequence, with a value that starts at
75 * 1 and is incremented with each byte processed, and then with 0x55. The value
76 * incremented with each byte processed overflows as an unsigned char. The
77 * resulting bytes form a wrapped SIR frame that is unwrapped and unescaped
78 * as in stir4200.c The incremented value is NOT reset with each frame, but is
79 * kept across the entire session with the dongle. Also, the dongle inserts an
80 * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which
81 * must be skipped.
82 *
83 * Speed change: To change the speed of the dongle, the driver prepares a
84 * control URB with the following as a setup packet:
85 * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
86 * bRequest 0x09
87 * wValue 0x0200
88 * wIndex 0x0001
89 * wLength 0x0008 (length of the payload)
90 * The payload is a 8-byte record, apparently identical to the one used in
91 * drivers/usb/serial/cypress_m8.c to change speed:
92 * __u32 baudSpeed;
93 * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
94 * unsigned int : 1;
95 * unsigned int stopBits : 1;
96 * unsigned int parityEnable : 1;
97 * unsigned int parityType : 1;
98 * unsigned int : 1;
99 * unsigned int reset : 1;
100 * unsigned char reserved[3]; // set to 0
101 *
102 * For now only SIR speeds have been observed with this dongle. Therefore,
103 * nothing is known on what changes (if any) must be done to frame wrapping /
104 * unwrapping for higher than SIR speeds. This driver assumes no change is
105 * necessary and announces support for all the way to 57600 bps. Although the
106 * package announces support for up to 4MBps, tests with a Sony Ericcson K300
107 * phone show corruption when receiving large frames at 115200 bps, the highest
108 * speed announced by the phone. However, transmission at 115200 bps is OK. Go
109 * figure. Since I don't know whether the phone or the dongle is at fault, max
110 * announced speed is 57600 bps until someone produces a device that can run
111 * at higher speeds with this dongle.
112 */
113
114#include <linux/module.h>
115#include <linux/moduleparam.h>
116#include <linux/kernel.h>
117#include <linux/types.h>
118#include <linux/errno.h>
119#include <linux/init.h>
120#include <linux/slab.h>
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700121#include <linux/kref.h>
122#include <linux/usb.h>
123#include <linux/device.h>
124#include <linux/crc32.h>
125
126#include <asm/unaligned.h>
127#include <asm/byteorder.h>
128#include <asm/uaccess.h>
129
130#include <net/irda/irda.h>
131#include <net/irda/wrapper.h>
132#include <net/irda/crc.h>
133
134#define KS959_VENDOR_ID 0x07d0
135#define KS959_PRODUCT_ID 0x4959
136
137/* These are the currently known USB ids */
138static struct usb_device_id dongles[] = {
139 /* KingSun Co,Ltd IrDA/USB Bridge */
140 {USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)},
141 {}
142};
143
144MODULE_DEVICE_TABLE(usb, dongles);
145
146#define KINGSUN_MTT 0x07
147#define KINGSUN_REQ_RECV 0x01
148#define KINGSUN_REQ_SEND 0x09
149
150#define KINGSUN_RCV_FIFO_SIZE 2048 /* Max length we can receive */
151#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */
152#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */
153
154struct ks959_speedparams {
155 __le32 baudrate; /* baud rate, little endian */
156 __u8 flags;
157 __u8 reserved[3];
158} __attribute__ ((packed));
159
160#define KS_DATA_5_BITS 0x00
161#define KS_DATA_6_BITS 0x01
162#define KS_DATA_7_BITS 0x02
163#define KS_DATA_8_BITS 0x03
164
165#define KS_STOP_BITS_1 0x00
166#define KS_STOP_BITS_2 0x08
167
168#define KS_PAR_DISABLE 0x00
169#define KS_PAR_EVEN 0x10
170#define KS_PAR_ODD 0x30
171#define KS_RESET 0x80
172
173struct ks959_cb {
174 struct usb_device *usbdev; /* init: probe_irda */
175 struct net_device *netdev; /* network layer */
176 struct irlap_cb *irlap; /* The link layer we are binded to */
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800177
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700178 struct qos_info qos;
179
180 struct usb_ctrlrequest *tx_setuprequest;
181 struct urb *tx_urb;
182 __u8 *tx_buf_clear;
183 unsigned int tx_buf_clear_used;
184 unsigned int tx_buf_clear_sent;
185 __u8 *tx_buf_xored;
186
187 struct usb_ctrlrequest *rx_setuprequest;
188 struct urb *rx_urb;
189 __u8 *rx_buf;
190 __u8 rx_variable_xormask;
191 iobuff_t rx_unwrap_buff;
192 struct timeval rx_time;
193
194 struct usb_ctrlrequest *speed_setuprequest;
195 struct urb *speed_urb;
196 struct ks959_speedparams speedparams;
197 unsigned int new_speed;
198
199 spinlock_t lock;
200 int receiving;
201};
202
203/* Procedure to perform the obfuscation/padding expected by the dongle
204 *
205 * buf_cleartext (IN) Cleartext version of the IrDA frame to transmit
206 * len_cleartext (IN) Length of the cleartext version of IrDA frame
207 * buf_xoredtext (OUT) Obfuscated version of frame built by proc
208 * len_maxbuf (OUT) Maximum space available at buf_xoredtext
209 *
210 * (return) length of obfuscated frame with padding
211 *
212 * If not enough space (as indicated by len_maxbuf vs. required padding),
213 * zero is returned
214 *
215 * The value of lookup_string is actually a required portion of the algorithm.
216 * Seems the designer of the dongle wanted to state who exactly is responsible
217 * for implementing obfuscation. Send your best (or other) wishes to him ]:-)
218 */
219static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext,
220 unsigned int len_cleartext,
221 __u8 * buf_xoredtext,
222 unsigned int len_maxbuf)
223{
224 unsigned int len_xoredtext;
225
226 /* Calculate required length with padding, check for necessary space */
227 len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10;
228 if (len_xoredtext <= len_maxbuf) {
229 static const __u8 lookup_string[] = "wangshuofei19710";
230 __u8 xor_mask;
231
232 /* Unlike the WinXP driver, we *do* clear out the padding */
233 memset(buf_xoredtext, 0, len_xoredtext);
234
235 xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55;
236
237 while (len_cleartext-- > 0) {
238 *buf_xoredtext++ = *buf_cleartext++ ^ xor_mask;
239 }
240 } else {
241 len_xoredtext = 0;
242 }
243 return len_xoredtext;
244}
245
246/* Callback transmission routine */
247static void ks959_speed_irq(struct urb *urb)
248{
249 /* unlink, shutdown, unplug, other nasties */
250 if (urb->status != 0) {
251 err("ks959_speed_irq: urb asynchronously failed - %d",
252 urb->status);
253 }
254}
255
256/* Send a control request to change speed of the dongle */
257static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed)
258{
259 static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
260 57600, 115200, 576000, 1152000, 4000000, 0
261 };
262 int err;
263 unsigned int i;
264
265 if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
266 return -ENOMEM;
267
268 /* Check that requested speed is among the supported ones */
269 for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
270 if (supported_speeds[i] == 0)
271 return -EOPNOTSUPP;
272
273 memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams));
274 kingsun->speedparams.baudrate = cpu_to_le32(speed);
275 kingsun->speedparams.flags = KS_DATA_8_BITS;
276
277 /* speed_setuprequest pre-filled in ks959_probe */
278 usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
279 usb_sndctrlpipe(kingsun->usbdev, 0),
280 (unsigned char *)kingsun->speed_setuprequest,
281 &(kingsun->speedparams),
282 sizeof(struct ks959_speedparams), ks959_speed_irq,
283 kingsun);
284 kingsun->speed_urb->status = 0;
285 err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
286
287 return err;
288}
289
290/* Submit one fragment of an IrDA frame to the dongle */
291static void ks959_send_irq(struct urb *urb);
292static int ks959_submit_tx_fragment(struct ks959_cb *kingsun)
293{
294 unsigned int padlen;
295 unsigned int wraplen;
296 int ret;
297
298 /* Check whether current plaintext can produce a padded buffer that fits
299 within the range handled by the dongle */
300 wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10;
301 if (wraplen > kingsun->tx_buf_clear_used)
302 wraplen = kingsun->tx_buf_clear_used;
303
304 /* Perform dongle obfuscation. Also remove the portion of the frame that
305 was just obfuscated and will now be sent to the dongle. */
306 padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen,
307 kingsun->tx_buf_xored,
308 KINGSUN_SND_PACKET_SIZE);
309
310 /* Calculate how much data can be transmitted in this urb */
311 kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen);
312 kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen);
313 /* Rest of the fields were filled in ks959_probe */
314 usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev,
315 usb_sndctrlpipe(kingsun->usbdev, 0),
316 (unsigned char *)kingsun->tx_setuprequest,
317 kingsun->tx_buf_xored, padlen,
318 ks959_send_irq, kingsun);
319 kingsun->tx_urb->status = 0;
320 ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
321
322 /* Remember how much data was sent, in order to update at callback */
323 kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
324 return ret;
325}
326
327/* Callback transmission routine */
328static void ks959_send_irq(struct urb *urb)
329{
330 struct ks959_cb *kingsun = urb->context;
331 struct net_device *netdev = kingsun->netdev;
332 int ret = 0;
333
334 /* in process of stopping, just drop data */
335 if (!netif_running(kingsun->netdev)) {
336 err("ks959_send_irq: Network not running!");
337 return;
338 }
339
340 /* unlink, shutdown, unplug, other nasties */
341 if (urb->status != 0) {
342 err("ks959_send_irq: urb asynchronously failed - %d",
343 urb->status);
344 return;
345 }
346
347 if (kingsun->tx_buf_clear_used > 0) {
348 /* Update data remaining to be sent */
349 if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
350 memmove(kingsun->tx_buf_clear,
351 kingsun->tx_buf_clear +
352 kingsun->tx_buf_clear_sent,
353 kingsun->tx_buf_clear_used -
354 kingsun->tx_buf_clear_sent);
355 }
356 kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
357 kingsun->tx_buf_clear_sent = 0;
358
359 if (kingsun->tx_buf_clear_used > 0) {
360 /* There is more data to be sent */
361 if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
362 err("ks959_send_irq: failed tx_urb submit: %d",
363 ret);
364 switch (ret) {
365 case -ENODEV:
366 case -EPIPE:
367 break;
368 default:
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800369 netdev->stats.tx_errors++;
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700370 netif_start_queue(netdev);
371 }
372 }
373 } else {
374 /* All data sent, send next speed && wake network queue */
375 if (kingsun->new_speed != -1 &&
376 cpu_to_le32(kingsun->new_speed) !=
377 kingsun->speedparams.baudrate)
378 ks959_change_speed(kingsun, kingsun->new_speed);
379
380 netif_wake_queue(netdev);
381 }
382 }
383}
384
385/*
386 * Called from net/core when new frame is available.
387 */
388static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
389{
390 struct ks959_cb *kingsun;
391 unsigned int wraplen;
392 int ret = 0;
393
394 if (skb == NULL || netdev == NULL)
395 return -EINVAL;
396
397 netif_stop_queue(netdev);
398
399 /* the IRDA wrapping routines don't deal with non linear skb */
400 SKB_LINEAR_ASSERT(skb);
401
402 kingsun = netdev_priv(netdev);
403
404 spin_lock(&kingsun->lock);
405 kingsun->new_speed = irda_get_next_speed(skb);
406
407 /* Append data to the end of whatever data remains to be transmitted */
408 wraplen =
409 async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
410 kingsun->tx_buf_clear_used = wraplen;
411
412 if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
413 err("ks959_hard_xmit: failed tx_urb submit: %d", ret);
414 switch (ret) {
415 case -ENODEV:
416 case -EPIPE:
417 break;
418 default:
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800419 netdev->stats.tx_errors++;
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700420 netif_start_queue(netdev);
421 }
422 } else {
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800423 netdev->stats.tx_packets++;
424 netdev->stats.tx_bytes += skb->len;
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700425
426 }
427
428 dev_kfree_skb(skb);
429 spin_unlock(&kingsun->lock);
430
431 return ret;
432}
433
434/* Receive callback function */
435static void ks959_rcv_irq(struct urb *urb)
436{
437 struct ks959_cb *kingsun = urb->context;
438 int ret;
439
440 /* in process of stopping, just drop data */
441 if (!netif_running(kingsun->netdev)) {
442 kingsun->receiving = 0;
443 return;
444 }
445
446 /* unlink, shutdown, unplug, other nasties */
447 if (urb->status != 0) {
448 err("kingsun_rcv_irq: urb asynchronously failed - %d",
449 urb->status);
450 kingsun->receiving = 0;
451 return;
452 }
453
454 if (urb->actual_length > 0) {
455 __u8 *bytes = urb->transfer_buffer;
456 unsigned int i;
457
458 for (i = 0; i < urb->actual_length; i++) {
459 /* De-obfuscation implemented here: variable portion of
460 xormask is incremented, and then used with the encoded
461 byte for the XOR. The result of the operation is used
462 to unwrap the SIR frame. */
463 kingsun->rx_variable_xormask++;
464 bytes[i] =
465 bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u;
466
467 /* rx_variable_xormask doubles as an index counter so we
468 can skip the byte at 0xff (wrapped around to 0).
469 */
470 if (kingsun->rx_variable_xormask != 0) {
471 async_unwrap_char(kingsun->netdev,
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800472 &kingsun->netdev->stats,
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700473 &kingsun->rx_unwrap_buff,
474 bytes[i]);
475 }
476 }
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700477 do_gettimeofday(&kingsun->rx_time);
478 kingsun->receiving =
479 (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
480 }
481
482 /* This urb has already been filled in kingsun_net_open. Setup
483 packet must be re-filled, but it is assumed that urb keeps the
484 pointer to the initial setup packet, as well as the payload buffer.
485 Setup packet is already pre-filled at ks959_probe.
486 */
487 urb->status = 0;
488 ret = usb_submit_urb(urb, GFP_ATOMIC);
489}
490
491/*
492 * Function kingsun_net_open (dev)
493 *
494 * Network device is taken up. Usually this is done by "ifconfig irda0 up"
495 */
496static int ks959_net_open(struct net_device *netdev)
497{
498 struct ks959_cb *kingsun = netdev_priv(netdev);
499 int err = -ENOMEM;
500 char hwname[16];
501
502 /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
503 kingsun->receiving = 0;
504
505 /* Initialize for SIR to copy data directly into skb. */
506 kingsun->rx_unwrap_buff.in_frame = FALSE;
507 kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
508 kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
509 kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
510 if (!kingsun->rx_unwrap_buff.skb)
511 goto free_mem;
512
513 skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
514 kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
515 do_gettimeofday(&kingsun->rx_time);
516
517 kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
518 if (!kingsun->rx_urb)
519 goto free_mem;
520
521 kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
522 if (!kingsun->tx_urb)
523 goto free_mem;
524
525 kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
526 if (!kingsun->speed_urb)
527 goto free_mem;
528
529 /* Initialize speed for dongle */
530 kingsun->new_speed = 9600;
531 err = ks959_change_speed(kingsun, 9600);
532 if (err < 0)
533 goto free_mem;
534
535 /*
536 * Now that everything should be initialized properly,
537 * Open new IrLAP layer instance to take care of us...
538 */
539 sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
540 kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
541 if (!kingsun->irlap) {
542 err("ks959-sir: irlap_open failed");
543 goto free_mem;
544 }
545
546 /* Start reception. Setup request already pre-filled in ks959_probe */
547 usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev,
548 usb_rcvctrlpipe(kingsun->usbdev, 0),
549 (unsigned char *)kingsun->rx_setuprequest,
550 kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE,
551 ks959_rcv_irq, kingsun);
552 kingsun->rx_urb->status = 0;
553 err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
554 if (err) {
555 err("ks959-sir: first urb-submit failed: %d", err);
556 goto close_irlap;
557 }
558
559 netif_start_queue(netdev);
560
561 /* Situation at this point:
562 - all work buffers allocated
563 - urbs allocated and ready to fill
564 - max rx packet known (in max_rx)
565 - unwrap state machine initialized, in state outside of any frame
566 - receive request in progress
567 - IrLAP layer started, about to hand over packets to send
568 */
569
570 return 0;
571
572 close_irlap:
573 irlap_close(kingsun->irlap);
574 free_mem:
575 usb_free_urb(kingsun->speed_urb);
576 kingsun->speed_urb = NULL;
577 usb_free_urb(kingsun->tx_urb);
578 kingsun->tx_urb = NULL;
579 usb_free_urb(kingsun->rx_urb);
580 kingsun->rx_urb = NULL;
581 if (kingsun->rx_unwrap_buff.skb) {
582 kfree_skb(kingsun->rx_unwrap_buff.skb);
583 kingsun->rx_unwrap_buff.skb = NULL;
584 kingsun->rx_unwrap_buff.head = NULL;
585 }
586 return err;
587}
588
589/*
590 * Function kingsun_net_close (kingsun)
591 *
592 * Network device is taken down. Usually this is done by
593 * "ifconfig irda0 down"
594 */
595static int ks959_net_close(struct net_device *netdev)
596{
597 struct ks959_cb *kingsun = netdev_priv(netdev);
598
599 /* Stop transmit processing */
600 netif_stop_queue(netdev);
601
602 /* Mop up receive && transmit urb's */
603 usb_kill_urb(kingsun->tx_urb);
604 usb_free_urb(kingsun->tx_urb);
605 kingsun->tx_urb = NULL;
606
607 usb_kill_urb(kingsun->speed_urb);
608 usb_free_urb(kingsun->speed_urb);
609 kingsun->speed_urb = NULL;
610
611 usb_kill_urb(kingsun->rx_urb);
612 usb_free_urb(kingsun->rx_urb);
613 kingsun->rx_urb = NULL;
614
615 kfree_skb(kingsun->rx_unwrap_buff.skb);
616 kingsun->rx_unwrap_buff.skb = NULL;
617 kingsun->rx_unwrap_buff.head = NULL;
618 kingsun->rx_unwrap_buff.in_frame = FALSE;
619 kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
620 kingsun->receiving = 0;
621
622 /* Stop and remove instance of IrLAP */
623 if (kingsun->irlap)
624 irlap_close(kingsun->irlap);
625
626 kingsun->irlap = NULL;
627
628 return 0;
629}
630
631/*
632 * IOCTLs : Extra out-of-band network commands...
633 */
634static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
635{
636 struct if_irda_req *irq = (struct if_irda_req *)rq;
637 struct ks959_cb *kingsun = netdev_priv(netdev);
638 int ret = 0;
639
640 switch (cmd) {
641 case SIOCSBANDWIDTH: /* Set bandwidth */
642 if (!capable(CAP_NET_ADMIN))
643 return -EPERM;
644
645 /* Check if the device is still there */
646 if (netif_device_present(kingsun->netdev))
647 return ks959_change_speed(kingsun, irq->ifr_baudrate);
648 break;
649
650 case SIOCSMEDIABUSY: /* Set media busy */
651 if (!capable(CAP_NET_ADMIN))
652 return -EPERM;
653
654 /* Check if the IrDA stack is still there */
655 if (netif_running(kingsun->netdev))
656 irda_device_set_media_busy(kingsun->netdev, TRUE);
657 break;
658
659 case SIOCGRECEIVING:
660 /* Only approximately true */
661 irq->ifr_receiving = kingsun->receiving;
662 break;
663
664 default:
665 ret = -EOPNOTSUPP;
666 }
667
668 return ret;
669}
670
671/*
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700672 * This routine is called by the USB subsystem for each new device
673 * in the system. We need to check if the device is ours, and in
674 * this case start handling it.
675 */
676static int ks959_probe(struct usb_interface *intf,
677 const struct usb_device_id *id)
678{
679 struct usb_device *dev = interface_to_usbdev(intf);
680 struct ks959_cb *kingsun = NULL;
681 struct net_device *net = NULL;
682 int ret = -ENOMEM;
683
684 /* Allocate network device container. */
685 net = alloc_irdadev(sizeof(*kingsun));
686 if (!net)
687 goto err_out1;
688
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700689 SET_NETDEV_DEV(net, &intf->dev);
690 kingsun = netdev_priv(net);
691 kingsun->netdev = net;
692 kingsun->usbdev = dev;
693 kingsun->irlap = NULL;
694 kingsun->tx_setuprequest = NULL;
695 kingsun->tx_urb = NULL;
696 kingsun->tx_buf_clear = NULL;
697 kingsun->tx_buf_xored = NULL;
698 kingsun->tx_buf_clear_used = 0;
699 kingsun->tx_buf_clear_sent = 0;
700
701 kingsun->rx_setuprequest = NULL;
702 kingsun->rx_urb = NULL;
703 kingsun->rx_buf = NULL;
704 kingsun->rx_variable_xormask = 0;
705 kingsun->rx_unwrap_buff.in_frame = FALSE;
706 kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
707 kingsun->rx_unwrap_buff.skb = NULL;
708 kingsun->receiving = 0;
709 spin_lock_init(&kingsun->lock);
710
711 kingsun->speed_setuprequest = NULL;
712 kingsun->speed_urb = NULL;
713 kingsun->speedparams.baudrate = 0;
714
715 /* Allocate input buffer */
716 kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL);
717 if (!kingsun->rx_buf)
718 goto free_mem;
719
720 /* Allocate input setup packet */
721 kingsun->rx_setuprequest =
722 kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
723 if (!kingsun->rx_setuprequest)
724 goto free_mem;
725 kingsun->rx_setuprequest->bRequestType =
726 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
727 kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV;
728 kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200);
729 kingsun->rx_setuprequest->wIndex = 0;
730 kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE);
731
732 /* Allocate output buffer */
733 kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
734 if (!kingsun->tx_buf_clear)
735 goto free_mem;
736 kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL);
737 if (!kingsun->tx_buf_xored)
738 goto free_mem;
739
740 /* Allocate and initialize output setup packet */
741 kingsun->tx_setuprequest =
742 kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
743 if (!kingsun->tx_setuprequest)
744 goto free_mem;
745 kingsun->tx_setuprequest->bRequestType =
746 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
747 kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND;
748 kingsun->tx_setuprequest->wValue = 0;
749 kingsun->tx_setuprequest->wIndex = 0;
750 kingsun->tx_setuprequest->wLength = 0;
751
752 /* Allocate and initialize speed setup packet */
753 kingsun->speed_setuprequest =
754 kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
755 if (!kingsun->speed_setuprequest)
756 goto free_mem;
757 kingsun->speed_setuprequest->bRequestType =
758 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
759 kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
760 kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
761 kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
762 kingsun->speed_setuprequest->wLength =
763 cpu_to_le16(sizeof(struct ks959_speedparams));
764
765 printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, "
766 "Vendor: %x, Product: %x\n",
767 dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
768 le16_to_cpu(dev->descriptor.idProduct));
769
770 /* Initialize QoS for this device */
771 irda_init_max_qos_capabilies(&kingsun->qos);
772
773 /* Baud rates known to be supported. Please uncomment if devices (other
774 than a SonyEriccson K300 phone) can be shown to support higher speed
775 with this dongle.
776 */
777 kingsun->qos.baud_rate.bits =
778 IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600;
779 kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
780 irda_qos_bits_to_value(&kingsun->qos);
781
782 /* Override the network functions we need to use */
783 net->hard_start_xmit = ks959_hard_xmit;
784 net->open = ks959_net_open;
785 net->stop = ks959_net_close;
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700786 net->do_ioctl = ks959_net_ioctl;
787
788 ret = register_netdev(net);
789 if (ret != 0)
790 goto free_mem;
791
Greg Kroah-Hartman880c9c62008-08-18 13:21:04 -0700792 dev_info(&net->dev, "IrDA: Registered KingSun KS-959 device %s\n",
793 net->name);
Alex Villacís Lasso4b6aa592007-08-28 15:58:31 -0700794
795 usb_set_intfdata(intf, kingsun);
796
797 /* Situation at this point:
798 - all work buffers allocated
799 - setup requests pre-filled
800 - urbs not allocated, set to NULL
801 - max rx packet known (is KINGSUN_FIFO_SIZE)
802 - unwrap state machine (partially) initialized, but skb == NULL
803 */
804
805 return 0;
806
807 free_mem:
808 kfree(kingsun->speed_setuprequest);
809 kfree(kingsun->tx_setuprequest);
810 kfree(kingsun->tx_buf_xored);
811 kfree(kingsun->tx_buf_clear);
812 kfree(kingsun->rx_setuprequest);
813 kfree(kingsun->rx_buf);
814 free_netdev(net);
815 err_out1:
816 return ret;
817}
818
819/*
820 * The current device is removed, the USB layer tell us to shut it down...
821 */
822static void ks959_disconnect(struct usb_interface *intf)
823{
824 struct ks959_cb *kingsun = usb_get_intfdata(intf);
825
826 if (!kingsun)
827 return;
828
829 unregister_netdev(kingsun->netdev);
830
831 /* Mop up receive && transmit urb's */
832 if (kingsun->speed_urb != NULL) {
833 usb_kill_urb(kingsun->speed_urb);
834 usb_free_urb(kingsun->speed_urb);
835 kingsun->speed_urb = NULL;
836 }
837 if (kingsun->tx_urb != NULL) {
838 usb_kill_urb(kingsun->tx_urb);
839 usb_free_urb(kingsun->tx_urb);
840 kingsun->tx_urb = NULL;
841 }
842 if (kingsun->rx_urb != NULL) {
843 usb_kill_urb(kingsun->rx_urb);
844 usb_free_urb(kingsun->rx_urb);
845 kingsun->rx_urb = NULL;
846 }
847
848 kfree(kingsun->speed_setuprequest);
849 kfree(kingsun->tx_setuprequest);
850 kfree(kingsun->tx_buf_xored);
851 kfree(kingsun->tx_buf_clear);
852 kfree(kingsun->rx_setuprequest);
853 kfree(kingsun->rx_buf);
854 free_netdev(kingsun->netdev);
855
856 usb_set_intfdata(intf, NULL);
857}
858
859#ifdef CONFIG_PM
860/* USB suspend, so power off the transmitter/receiver */
861static int ks959_suspend(struct usb_interface *intf, pm_message_t message)
862{
863 struct ks959_cb *kingsun = usb_get_intfdata(intf);
864
865 netif_device_detach(kingsun->netdev);
866 if (kingsun->speed_urb != NULL)
867 usb_kill_urb(kingsun->speed_urb);
868 if (kingsun->tx_urb != NULL)
869 usb_kill_urb(kingsun->tx_urb);
870 if (kingsun->rx_urb != NULL)
871 usb_kill_urb(kingsun->rx_urb);
872 return 0;
873}
874
875/* Coming out of suspend, so reset hardware */
876static int ks959_resume(struct usb_interface *intf)
877{
878 struct ks959_cb *kingsun = usb_get_intfdata(intf);
879
880 if (kingsun->rx_urb != NULL) {
881 /* Setup request already filled in ks959_probe */
882 usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
883 }
884 netif_device_attach(kingsun->netdev);
885
886 return 0;
887}
888#endif
889
890/*
891 * USB device callbacks
892 */
893static struct usb_driver irda_driver = {
894 .name = "ks959-sir",
895 .probe = ks959_probe,
896 .disconnect = ks959_disconnect,
897 .id_table = dongles,
898#ifdef CONFIG_PM
899 .suspend = ks959_suspend,
900 .resume = ks959_resume,
901#endif
902};
903
904/*
905 * Module insertion
906 */
907static int __init ks959_init(void)
908{
909 return usb_register(&irda_driver);
910}
911
912module_init(ks959_init);
913
914/*
915 * Module removal
916 */
917static void __exit ks959_cleanup(void)
918{
919 /* Deregister the driver and remove all pending instances */
920 usb_deregister(&irda_driver);
921}
922
923module_exit(ks959_cleanup);
924
925MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
926MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959");
927MODULE_LICENSE("GPL");