Import 2.4.0-test5pre2
[davej-history.git] / drivers / usb / plusb.c
blob9165779cb117bf83021884b5cb5d3a8149c362a4
1 /*****************************************************************************/
3 /*
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>
43 //#define DEBUG
44 #include <linux/usb.h>
46 #include "plusb.h"
48 /* --------------------------------------------------------------------- */
50 #define NRPLUSB 4
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)
59 unsigned long flags;
60 struct list_head *tmp;
61 int ret = 0;
63 spin_lock_irqsave (&s->lock, flags);
65 if (list_empty (src)) {
66 // no elements in source buffer
67 ret = -1;
68 goto err;
70 tmp = src->next;
71 list_del (tmp);
72 list_add_tail (tmp, dst);
74 err: spin_unlock_irqrestore (&s->lock, flags);
75 return ret;
77 /*-------------------------------------------------------------------*/
79 static int plusb_my_bulk(plusb_t *s, int pipe, void *data, int size, int *actual_length)
81 int ret;
83 dbg("plusb_my_bulk: len:%d",size);
85 ret=usb_bulk_msg(s->usbdev, pipe, data, size, actual_length, 500);
86 if(ret<0) {
87 err("plusb: usb_bulk_msg failed(%d)",ret);
90 if( ret == -EPIPE ) {
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);
97 return ret;
100 /* --------------------------------------------------------------------- */
102 static void plusb_bh(void *context)
104 plusb_t *s=context;
105 struct net_device_stats *stats=&s->net_stats;
106 int ret=0;
107 int actual_length;
108 skb_list_t *skb_list;
109 struct sk_buff *skb;
111 dbg("plusb_bh: i:%d",in_interrupt());
113 while(!list_empty(&s->tx_skb_list)) {
115 if(!(s->status&_PLUSB_TXOK))
116 break;
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");
121 schedule();
122 continue;
125 skb=skb_list->skb;
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);
134 if(!ret) {
135 stats->tx_packets++;
136 stats->tx_bytes+=skb->len;
138 else {
139 stats->tx_errors++;
140 stats->tx_aborted_errors++;
143 dbg("plusb_bh: dev_kfree_skb");
145 dev_kfree_skb(skb);
146 skb_list->state=0;
147 plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list);
150 dbg("plusb_bh: finished");
151 s->in_bh=0;
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)) {
165 ret=NET_XMIT_CN;
166 goto lab;
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);
171 skb_list->skb=skb;
172 skb_list->state=1;
174 lab:
175 if(s->in_bh)
176 return ret;
178 dbg("plusb_net_xmit: queue_task");
180 s->in_bh=1;
181 queue_task(&s->bh, &tq_scheduler);
183 dbg("plusb_net_xmit: finished");
184 return ret;
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);
195 if(!s->connected)
196 return;
198 if( !purb->status) {
199 struct sk_buff *skb;
200 unsigned char *dst;
201 int len=purb->transfer_buffer_length;
202 struct net_device_stats *stats=&s->net_stats;
204 skb=dev_alloc_skb(len);
206 if(!skb) {
207 err("plusb_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame",len);
208 stats->rx_dropped++;
209 return;
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);
217 stats->rx_packets++;
218 stats->rx_bytes+=len;
219 netif_rx(skb);
221 else
222 purb->status=0;
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;
231 #if 0
232 if((s->status&0x3f)!=0x20) {
233 warn("invalid device status %02X", s->status);
234 return;
236 #endif
237 if(!s->connected)
238 return;
240 if(s->status&_PLUSB_RXD) {
241 int ret;
243 if(s->bulkurb->status) {
244 err("plusb_int_complete: URB still in use");
245 return;
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);
268 if(s->inturb) {
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;
279 if(s->inturb) {
280 dbg("free_urb inturb");
281 usb_free_urb(s->inturb);
282 s->inturb=NULL;
285 if(s->bulkurb) {
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;
295 if(s->bulkurb) {
296 dbg("free_urb bulkurb");
297 usb_free_urb(s->bulkurb);
298 s->bulkurb=NULL;
301 while(!list_empty(&s->free_skb_list)) {
302 skb=s->free_skb_list.next;
303 list_del(skb);
304 skb_list = list_entry (skb, skb_list_t, skb_list);
305 kfree(skb_list);
308 while(!list_empty(&s->tx_skb_list)) {
309 skb=s->tx_skb_list.next;
310 list_del(skb);
311 skb_list = list_entry (skb, skb_list_t, skb_list);
312 kfree(skb_list);
314 dbg("plusb_free_all: finished");
317 /*-------------------------------------------------------------------*/
319 static int plusb_alloc(plusb_t *s)
321 int i;
322 skb_list_t *skb;
324 dbg("plusb_alloc");
326 for(i=0 ; i < _SKB_NUM ; i++) {
327 skb=kmalloc(sizeof(skb_list_t), GFP_KERNEL);
328 if(!skb) {
329 err("kmalloc for skb_list failed");
330 goto reject;
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);
338 if(!s->inturb) {
339 err("alloc_urb failed");
340 goto reject;
343 dbg("bulkurb allocation:");
344 s->bulkurb=usb_alloc_urb(0);
345 if(!s->bulkurb) {
346 err("alloc_urb failed");
347 goto reject;
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");
356 goto reject;
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");
367 goto reject;
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");
376 goto reject;
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");
385 return 0;
387 reject:
388 dbg("plusb_alloc: failed");
390 plusb_free_all(s);
391 return -ENOMEM;
394 /*-------------------------------------------------------------------*/
396 static int plusb_net_open(struct net_device *dev)
398 plusb_t *s=dev->priv;
400 dbg("plusb_net_open");
402 if(plusb_alloc(s))
403 return -ENOMEM;
405 s->opened=1;
406 MOD_INC_USE_COUNT;
408 dbg("plusb_net_open: success");
410 return 0;
414 /* --------------------------------------------------------------------- */
416 static int plusb_net_stop(struct net_device *dev)
418 plusb_t *s=dev->priv;
420 dbg("plusb_net_stop");
422 plusb_free_all(s);
423 s->opened=0;
424 MOD_DEC_USE_COUNT;
425 dbg("plusb_net_stop:finished");
426 return 0;
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)
444 int u;
446 for (u = 0; u < NRPLUSB; u++) {
447 plusb_t *s = &plusb[u];
448 if (!s->connected)
449 return s;
451 return NULL;
454 /* --------------------------------------------------------------------- */
456 static void plusb_disconnect (struct usb_device *usbdev, void *ptr)
458 plusb_t *s = ptr;
460 dbg("plusb_disconnect");
461 s->connected = 0;
463 plusb_free_all(s);
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");
472 MOD_DEC_USE_COUNT;
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;
485 ether_setup(dev);
486 dev->tx_queue_len = 0;
487 dev->flags = IFF_POINTOPOINT|IFF_NOARP;
490 dbg("plusb_net_init: finished");
491 return 0;
494 /* --------------------------------------------------------------------- */
496 static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum)
498 plusb_t *s;
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)
504 return NULL;
506 /* We don't handle multiple configurations */
507 if (usbdev->descriptor.bNumConfigurations != 1)
508 return NULL;
510 s = plusb_find_struct ();
511 if (!s)
512 return NULL;
514 s->usbdev = usbdev;
516 if (usb_set_configuration (s->usbdev, usbdev->config[0].bConfigurationValue) < 0) {
517 err("set_configuration failed");
518 return NULL;
521 if (usb_set_interface (s->usbdev, 0, 0) < 0) {
522 err("set_interface failed");
523 return NULL;
526 if(!s->net_dev.name[0]) {
527 strcpy(s->net_dev.name, "plusb%d");
528 s->net_dev.init=plusb_net_init;
529 s->net_dev.priv=s;
530 if(!register_netdev(&s->net_dev))
531 info("registered: %s", s->net_dev.name);
532 else {
533 err("register_netdev failed");
534 s->net_dev.name[0] = '\0';
538 s->connected = 1;
540 if(s->opened) {
541 dbg("net device already allocated, restarting USB transfers");
542 plusb_alloc(s);
545 info("bound to interface: %d dev: %p", ifnum, usbdev);
546 MOD_INC_USE_COUNT;
547 return s;
549 /* --------------------------------------------------------------------- */
551 static struct usb_driver plusb_driver =
553 name: "plusb",
554 probe: plusb_probe,
555 disconnect: plusb_disconnect,
558 /* --------------------------------------------------------------------- */
560 int __init plusb_init (void)
562 unsigned u;
563 dbg("plusb_init");
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;
570 s->bh.data = s;
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");
581 return 0;
584 /* --------------------------------------------------------------------- */
586 void __exit plusb_cleanup (void)
588 unsigned u;
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 /* --------------------------------------------------------------------- */
604 #ifdef MODULE
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)
616 plusb_cleanup ();
619 #endif
621 /* --------------------------------------------------------------------- */