1 /*****************************************************************************/
4 * plusb.c -- prolific pl-2302 driver.
6 * Copyright (C) 2000 Deti Fliegl (deti@fliegl.de)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * $Id: plusb.c,v 1.18 2000/02/14 10:38:58 fliegl Exp $
28 /*****************************************************************************/
30 #include <linux/module.h>
31 #include <linux/socket.h>
32 #include <linux/miscdevice.h>
33 #include <linux/list.h>
34 #include <linux/vmalloc.h>
35 #include <linux/slab.h>
36 #include <linux/init.h>
37 #include <asm/uaccess.h>
38 #include <asm/atomic.h>
39 #include <linux/delay.h>
40 #include <linux/netdevice.h>
41 #include <linux/etherdevice.h>
42 #include <linux/skbuff.h>
44 #include <linux/usb.h>
48 /* --------------------------------------------------------------------- */
52 /*-------------------------------------------------------------------*/
54 static plusb_t plusb
[NRPLUSB
];
56 /* --------------------------------------------------------------------- */
57 static int plusb_add_buf_tail (plusb_t
*s
, struct list_head
*dst
, struct list_head
*src
)
60 struct list_head
*tmp
;
63 spin_lock_irqsave (&s
->lock
, flags
);
65 if (list_empty (src
)) {
66 // no elements in source buffer
72 list_add_tail (tmp
, dst
);
74 err
: spin_unlock_irqrestore (&s
->lock
, flags
);
77 /*-------------------------------------------------------------------*/
79 static int plusb_my_bulk(plusb_t
*s
, int pipe
, void *data
, int size
, int *actual_length
)
83 dbg("plusb_my_bulk: len:%d",size
);
85 ret
=usb_bulk_msg(s
->usbdev
, pipe
, data
, size
, actual_length
, 500);
87 err("plusb: usb_bulk_msg failed(%d)",ret
);
91 warn("CLEAR_FEATURE request to remove STALL condition.");
92 if(usb_clear_halt(s
->usbdev
, usb_pipeendpoint(pipe
)))
93 err("request failed");
96 dbg("plusb_my_bulk: finished act: %d", *actual_length
);
100 /* --------------------------------------------------------------------- */
102 static void plusb_bh(void *context
)
105 struct net_device_stats
*stats
=&s
->net_stats
;
108 skb_list_t
*skb_list
;
111 dbg("plusb_bh: i:%d",in_interrupt());
113 while(!list_empty(&s
->tx_skb_list
)) {
115 if(!(s
->status
&_PLUSB_TXOK
))
118 skb_list
= list_entry (s
->tx_skb_list
.next
, skb_list_t
, skb_list
);
119 if(!skb_list
->state
) {
120 dbg("plusb_bh: not yet ready");
126 ret
=plusb_my_bulk(s
, usb_sndbulkpipe (s
->usbdev
, _PLUSB_BULKOUTPIPE
),
127 skb
->data
, skb
->len
, &actual_length
);
129 if(ret
|| skb
->len
!= actual_length
||!(skb
->len
%64)) {
130 plusb_my_bulk(s
, usb_sndbulkpipe (s
->usbdev
, _PLUSB_BULKOUTPIPE
),
131 NULL
, 0, &actual_length
);
136 stats
->tx_bytes
+=skb
->len
;
140 stats
->tx_aborted_errors
++;
143 dbg("plusb_bh: dev_kfree_skb");
147 plusb_add_buf_tail (s
, &s
->free_skb_list
, &s
->tx_skb_list
);
150 dbg("plusb_bh: finished");
154 /* --------------------------------------------------------------------- */
156 static int plusb_net_xmit(struct sk_buff
*skb
, struct net_device
*dev
)
158 plusb_t
*s
=dev
->priv
;
159 skb_list_t
*skb_list
;
160 int ret
=NET_XMIT_SUCCESS
;
162 dbg("plusb_net_xmit: len:%d i:%d",skb
->len
,in_interrupt());
164 if(!s
->connected
|| list_empty(&s
->free_skb_list
)) {
169 plusb_add_buf_tail (s
, &s
->tx_skb_list
, &s
->free_skb_list
);
170 skb_list
= list_entry (s
->tx_skb_list
.prev
, skb_list_t
, skb_list
);
178 dbg("plusb_net_xmit: queue_task");
181 queue_task(&s
->bh
, &tq_scheduler
);
183 dbg("plusb_net_xmit: finished");
188 /* --------------------------------------------------------------------- */
190 static void plusb_bulk_complete(urb_t
*purb
)
192 plusb_t
*s
=purb
->context
;
194 dbg("plusb_bulk_complete: status:%d length:%d",purb
->status
,purb
->actual_length
);
201 int len
=purb
->transfer_buffer_length
;
202 struct net_device_stats
*stats
=&s
->net_stats
;
204 skb
=dev_alloc_skb(len
);
207 err("plusb_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame",len
);
212 dst
=(char *)skb_put(skb
, len
);
213 memcpy( dst
, purb
->transfer_buffer
, len
);
215 skb
->dev
=&s
->net_dev
;
216 skb
->protocol
=eth_type_trans(skb
, skb
->dev
);
218 stats
->rx_bytes
+=len
;
225 /* --------------------------------------------------------------------- */
227 static void plusb_int_complete(urb_t
*purb
)
229 plusb_t
*s
=purb
->context
;
230 s
->status
=((unsigned char*)purb
->transfer_buffer
)[0]&255;
232 if((s
->status
&0x3f)!=0x20) {
233 warn("invalid device status %02X", s
->status
);
240 if(s
->status
&_PLUSB_RXD
) {
243 if(s
->bulkurb
->status
) {
244 err("plusb_int_complete: URB still in use");
248 ret
=usb_submit_urb(s
->bulkurb
);
249 if(ret
&& ret
!=-EBUSY
) {
250 err("plusb_int_complete: usb_submit_urb failed");
254 if(purb
->status
|| s
->status
!=160)
255 dbg("status: %p %d buf: %02X", purb
->dev
, purb
->status
, s
->status
);
258 /* --------------------------------------------------------------------- */
260 static void plusb_free_all(plusb_t
*s
)
262 struct list_head
*skb
;
263 skb_list_t
*skb_list
;
265 dbg("plusb_free_all");
266 run_task_queue(&tq_immediate
);
269 dbg("unlink inturb");
270 usb_unlink_urb(s
->inturb
);
273 if(s
->inturb
&& s
->inturb
->transfer_buffer
) {
274 dbg("kfree inturb->transfer_buffer");
275 kfree(s
->inturb
->transfer_buffer
);
276 s
->inturb
->transfer_buffer
=NULL
;
280 dbg("free_urb inturb");
281 usb_free_urb(s
->inturb
);
286 dbg("unlink bulkurb");
287 usb_unlink_urb(s
->bulkurb
);
290 if(s
->bulkurb
&& s
->bulkurb
->transfer_buffer
) {
291 dbg("kfree bulkurb->transfer_buffer");
292 kfree(s
->bulkurb
->transfer_buffer
);
293 s
->bulkurb
->transfer_buffer
=NULL
;
296 dbg("free_urb bulkurb");
297 usb_free_urb(s
->bulkurb
);
301 while(!list_empty(&s
->free_skb_list
)) {
302 skb
=s
->free_skb_list
.next
;
304 skb_list
= list_entry (skb
, skb_list_t
, skb_list
);
308 while(!list_empty(&s
->tx_skb_list
)) {
309 skb
=s
->tx_skb_list
.next
;
311 skb_list
= list_entry (skb
, skb_list_t
, skb_list
);
314 dbg("plusb_free_all: finished");
317 /*-------------------------------------------------------------------*/
319 static int plusb_alloc(plusb_t
*s
)
326 for(i
=0 ; i
< _SKB_NUM
; i
++) {
327 skb
=kmalloc(sizeof(skb_list_t
), GFP_KERNEL
);
329 err("kmalloc for skb_list failed");
332 memset(skb
, 0, sizeof(skb_list_t
));
333 list_add(&skb
->skb_list
, &s
->free_skb_list
);
336 dbg("inturb allocation:");
337 s
->inturb
=usb_alloc_urb(0);
339 err("alloc_urb failed");
343 dbg("bulkurb allocation:");
344 s
->bulkurb
=usb_alloc_urb(0);
346 err("alloc_urb failed");
350 dbg("bulkurb/inturb init:");
351 s
->inturb
->dev
=s
->usbdev
;
352 s
->inturb
->pipe
=usb_rcvintpipe (s
->usbdev
, _PLUSB_INTPIPE
);
353 s
->inturb
->transfer_buffer
=kmalloc(64, GFP_KERNEL
);
354 if(!s
->inturb
->transfer_buffer
) {
355 err("kmalloc failed");
359 s
->inturb
->transfer_buffer_length
=1;
360 s
->inturb
->complete
=plusb_int_complete
;
361 s
->inturb
->context
=s
;
362 s
->inturb
->interval
=10;
364 dbg("inturb submission:");
365 if(usb_submit_urb(s
->inturb
)<0) {
366 err("usb_submit_urb failed");
370 dbg("bulkurb init:");
371 s
->bulkurb
->dev
=s
->usbdev
;
372 s
->bulkurb
->pipe
=usb_rcvbulkpipe (s
->usbdev
, _PLUSB_BULKINPIPE
);
373 s
->bulkurb
->transfer_buffer
=kmalloc(_BULK_DATA_LEN
, GFP_KERNEL
);
374 if(!s
->bulkurb
->transfer_buffer
) {
375 err("kmalloc failed");
379 s
->bulkurb
->transfer_buffer_length
=_BULK_DATA_LEN
;
380 s
->bulkurb
->complete
=plusb_bulk_complete
;
381 s
->bulkurb
->context
=s
;
383 dbg("plusb_alloc: finished");
388 dbg("plusb_alloc: failed");
394 /*-------------------------------------------------------------------*/
396 static int plusb_net_open(struct net_device
*dev
)
398 plusb_t
*s
=dev
->priv
;
400 dbg("plusb_net_open");
408 dbg("plusb_net_open: success");
414 /* --------------------------------------------------------------------- */
416 static int plusb_net_stop(struct net_device
*dev
)
418 plusb_t
*s
=dev
->priv
;
420 dbg("plusb_net_stop");
425 dbg("plusb_net_stop:finished");
429 /* --------------------------------------------------------------------- */
431 static struct net_device_stats
*plusb_net_get_stats(struct net_device
*dev
)
433 plusb_t
*s
=dev
->priv
;
435 dbg("net_device_stats");
437 return &s
->net_stats
;
440 /* --------------------------------------------------------------------- */
442 static plusb_t
*plusb_find_struct (void)
446 for (u
= 0; u
< NRPLUSB
; u
++) {
447 plusb_t
*s
= &plusb
[u
];
454 /* --------------------------------------------------------------------- */
456 static void plusb_disconnect (struct usb_device
*usbdev
, void *ptr
)
460 dbg("plusb_disconnect");
465 if(!s
->opened
&& s
->net_dev
.name
) {
466 dbg("unregistering netdev: %s",s
->net_dev
.name
);
467 unregister_netdev(&s
->net_dev
);
468 s
->net_dev
.name
[0] = '\0';
471 dbg("plusb_disconnect: finished");
475 /* --------------------------------------------------------------------- */
477 int plusb_net_init(struct net_device
*dev
)
479 dbg("plusb_net_init");
481 dev
->open
=plusb_net_open
;
482 dev
->stop
=plusb_net_stop
;
483 dev
->hard_start_xmit
=plusb_net_xmit
;
484 dev
->get_stats
= plusb_net_get_stats
;
486 dev
->tx_queue_len
= 0;
487 dev
->flags
= IFF_POINTOPOINT
|IFF_NOARP
;
490 dbg("plusb_net_init: finished");
494 /* --------------------------------------------------------------------- */
496 static void *plusb_probe (struct usb_device
*usbdev
, unsigned int ifnum
)
500 dbg("plusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
501 usbdev
->descriptor
.idVendor
, usbdev
->descriptor
.idProduct
, ifnum
);
503 if (usbdev
->descriptor
.idVendor
!= 0x067b || usbdev
->descriptor
.idProduct
> 0x1)
506 /* We don't handle multiple configurations */
507 if (usbdev
->descriptor
.bNumConfigurations
!= 1)
510 s
= plusb_find_struct ();
516 if (usb_set_configuration (s
->usbdev
, usbdev
->config
[0].bConfigurationValue
) < 0) {
517 err("set_configuration failed");
521 if (usb_set_interface (s
->usbdev
, 0, 0) < 0) {
522 err("set_interface failed");
526 if(!s
->net_dev
.name
[0]) {
527 strcpy(s
->net_dev
.name
, "plusb%d");
528 s
->net_dev
.init
=plusb_net_init
;
530 if(!register_netdev(&s
->net_dev
))
531 info("registered: %s", s
->net_dev
.name
);
533 err("register_netdev failed");
534 s
->net_dev
.name
[0] = '\0';
541 dbg("net device already allocated, restarting USB transfers");
545 info("bound to interface: %d dev: %p", ifnum
, usbdev
);
549 /* --------------------------------------------------------------------- */
551 static struct usb_driver plusb_driver
=
555 disconnect
: plusb_disconnect
,
558 /* --------------------------------------------------------------------- */
560 int __init
plusb_init (void)
565 /* initialize struct */
566 for (u
= 0; u
< NRPLUSB
; u
++) {
567 plusb_t
*s
= &plusb
[u
];
568 memset (s
, 0, sizeof (plusb_t
));
569 s
->bh
.routine
= (void (*)(void *))plusb_bh
;
571 INIT_LIST_HEAD (&s
->tx_skb_list
);
572 INIT_LIST_HEAD (&s
->free_skb_list
);
573 spin_lock_init (&s
->lock
);
576 /* register misc device */
577 usb_register (&plusb_driver
);
579 dbg("plusb_init: driver registered");
584 /* --------------------------------------------------------------------- */
586 void __exit
plusb_cleanup (void)
590 dbg("plusb_cleanup");
591 for (u
= 0; u
< NRPLUSB
; u
++) {
592 plusb_t
*s
= &plusb
[u
];
593 if(s
->net_dev
.name
[0]) {
594 dbg("unregistering netdev: %s",s
->net_dev
.name
);
595 unregister_netdev(&s
->net_dev
);
598 usb_deregister (&plusb_driver
);
599 dbg("plusb_cleanup: finished");
602 /* --------------------------------------------------------------------- */
605 MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de");
606 MODULE_DESCRIPTION ("PL-2302 USB Interface Driver for Linux (c)2000");
608 /* --------------------------------------------------------------------- */
609 int __init
init_module (void)
611 return plusb_init ();
613 /* --------------------------------------------------------------------- */
614 void __exit
cleanup_module (void)
621 /* --------------------------------------------------------------------- */