OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [io/] [usb/] [eth/] [slave/] [v2_0/] [host/] [ecos_usbeth.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      ecos_usbeth.c
4
//
5
//      Linux device driver for eCos-based USB ethernet peripherals.
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####                                             
42
//
43
// Author(s):           bartv
44
// Contributors:        bartv
45
// Date:                2000-11-12
46
//
47
//####DESCRIPTIONEND####
48
//==========================================================================
49
 
50
#include <linux/module.h>
51
#include <linux/init.h>
52
#include <linux/usb.h>
53
#include <linux/netdevice.h>
54
#include <linux/etherdevice.h>
55
 
56
#ifdef MODULE
57
MODULE_AUTHOR("Bart Veer <bartv@redhat.com>");
58
MODULE_DESCRIPTION("USB ethernet driver for eCos-based peripherals");
59
#endif
60
 
61
// This array identifies specific implementations of eCos USB-ethernet
62
// devices. All implementations should add their vendor and device
63
// details.
64
 
65
typedef struct ecos_usbeth_impl {
66
    const char* name;
67
    __u16       vendor;
68
    __u16       id;
69
} ecos_usbeth_impl;
70
 
71
const static ecos_usbeth_impl ecos_usbeth_implementations[] = {
72
    { "eCos ether",     0x4242, 0x4242 },
73
    { (const char*) 0,       0,      0 }
74
};
75
 
76
 
77
// Constants. These have to be kept in sync with the target-side
78
// code.
79
#define ECOS_USBETH_MAXTU                           1516
80
#define ECOS_USBETH_MAX_CONTROL_TU                     8
81
#define ECOS_USBETH_CONTROL_GET_MAC_ADDRESS         0x01
82
#define ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE    0x02
83
 
84
// The main data structure. It keeps track of both the USB
85
// and network side of things, and provides buffers for
86
// the various operations.
87
//
88
// NOTE: currently this driver only supports a single
89
// plugged-in device. Theoretically multiple eCos-based
90
// USB ethernet devices could be plugged in to a single
91
// host and each one would require an ecos_usbeth
92
// structure.
93
typedef struct ecos_usbeth {
94
    spinlock_t                  usb_lock;
95
    int                         target_promiscuous;
96
    struct usb_device*          usb_dev;
97
    struct net_device*          net_dev;
98
    struct net_device_stats     stats;
99
    struct urb                  rx_urb;
100
    struct urb                  tx_urb;
101
    unsigned char               rx_buffer[ECOS_USBETH_MAXTU];
102
    unsigned char               tx_buffer[ECOS_USBETH_MAXTU];
103
} ecos_usbeth;
104
 
105
 
106
// open()
107
// Invoked by the TCP/IP stack when the interface is brought up.
108
// This just starts a receive operation.
109
static int
110
ecos_usbeth_open(struct net_device* net)
111
{
112
    ecos_usbeth* usbeth = (ecos_usbeth*) net->priv;
113
    int          res;
114
 
115
    netif_start_queue(net);
116
    res = usb_submit_urb(&(usbeth->rx_urb));
117
    if (0 != res) {
118
        printk("ecos_usbeth: failed to start USB receives, %d\n", res);
119
    }
120
    MOD_INC_USE_COUNT;
121
    return 0;
122
}
123
 
124
// close()
125
// Invoked by the TCP/IP stack when the interface is taken down.
126
// Any active USB operations need to be cancelled. During
127
// a disconnect this may get called twice, once for the
128
// disconnect and once for the network interface being
129
// brought down.
130
static int
131
ecos_usbeth_close(struct net_device* net)
132
{
133
    ecos_usbeth* usbeth = (ecos_usbeth*) net->priv;
134
 
135
    if (0 != netif_running(net)) {
136
        netif_stop_queue(net);
137
        net->start = 0;
138
 
139
        if (-EINPROGRESS == usbeth->rx_urb.status) {
140
            usb_unlink_urb(&(usbeth->rx_urb));
141
        }
142
        if (-EINPROGRESS == usbeth->tx_urb.status) {
143
            usb_unlink_urb(&(usbeth->tx_urb));
144
        }
145
        MOD_DEC_USE_COUNT;
146
    }
147
 
148
    return 0;
149
}
150
 
151
// Reception.
152
// probe() fills in an rx_urb. When the net device is brought up
153
// the urb is activated, and this callback gets run for incoming
154
// data.
155
static void
156
ecos_usbeth_rx_callback(struct urb* urb)
157
{
158
    ecos_usbeth*        usbeth  = (ecos_usbeth*) urb->context;
159
    struct net_device*  net     = usbeth->net_dev;
160
    struct sk_buff*     skb;
161
    int                 len;
162
    int                 res;
163
 
164
    if (0 != urb->status) {
165
        // This happens numerous times during a disconnect. Do not
166
        // issue a warning, but do clear the status field or things
167
        // get confused when resubmitting.
168
        //
169
        // Some host hardware does not distinguish between CRC errors
170
        // (very rare) and timeouts (perfectly normal). Do not
171
        // increment the error count if it might have been a timeout.
172
        if (USB_ST_CRC != urb->status) {
173
            usbeth->stats.rx_errors++;
174
        }
175
        urb->status = 0;
176
    } else if (2 > urb->actual_length) {
177
        // With some hardware the target may have to send a bogus
178
        // first packet. Just ignore those.
179
 
180
    } else {
181
        len = usbeth->rx_buffer[0] + (usbeth->rx_buffer[1] << 8);
182
        if (len > (urb->actual_length - 2)) {
183
            usbeth->stats.rx_errors++;
184
            usbeth->stats.rx_length_errors++;
185
            printk("ecos_usbeth: warning, packet size mismatch, got %d bytes, expected %d\n",
186
                   urb->actual_length, len);
187
        } else {
188
            skb = dev_alloc_skb(len + 2);
189
            if ((struct sk_buff*)0 == skb) {
190
                printk("ecos_usbeth: failed to alloc skb, dropping packet\n");
191
                usbeth->stats.rx_dropped++;
192
            } else {
193
#if 0
194
                {
195
                    int i;
196
                    printk("--------------------------------------------------------------\n");
197
                    printk("ecos_usbeth RX: total size %d\n", len);
198
                    for (i = 0; (i < len) && (i < 128); i+= 8) {
199
                        printk("rx  %x %x %x %x %x %x %x %x\n",
200
                               usbeth->rx_buffer[i+0], usbeth->rx_buffer[i+1], usbeth->rx_buffer[i+2], usbeth->rx_buffer[i+3],
201
                               usbeth->rx_buffer[i+4], usbeth->rx_buffer[i+5], usbeth->rx_buffer[i+6], usbeth->rx_buffer[i+7]);
202
                    }
203
                    printk("--------------------------------------------------------------\n");
204
                }
205
#endif
206
                skb->dev        = net;
207
                eth_copy_and_sum(skb, &(usbeth->rx_buffer[2]), len, 0);
208
                skb_put(skb, len);
209
                skb->protocol   = eth_type_trans(skb, net);
210
                netif_rx(skb);
211
                usbeth->stats.rx_packets++;
212
                usbeth->stats.rx_bytes += len;
213
            }
214
        }
215
    }
216
 
217
    if (0 != netif_running(net)) {
218
        res = usb_submit_urb(&(usbeth->rx_urb));
219
        if (0 != res) {
220
            printk("ecos_usbeth: failed to restart USB receives after packet, %d\n", res);
221
        }
222
    }
223
}
224
 
225
// start_tx().
226
// Transmit a single packet. The relevant USB protocol requires a
227
// 2-byte length field at the start, the incoming buffer has no space
228
// for this, and the URB API does not support any form of
229
// scatter/gather. Therefore unfortunately the whole packet has to be
230
// copied. The callback function is specified when the URB is filled
231
// in by probe().
232
static void
233
ecos_usbeth_tx_callback(struct urb* urb)
234
{
235
    ecos_usbeth* usbeth = (ecos_usbeth*) urb->context;
236
    spin_lock(&usbeth->usb_lock);
237
    if (0 != netif_running(usbeth->net_dev)) {
238
        netif_wake_queue(usbeth->net_dev);
239
    }
240
    spin_unlock(&usbeth->usb_lock);
241
}
242
 
243
static int
244
ecos_usbeth_start_tx(struct sk_buff* skb, struct net_device* net)
245
{
246
    ecos_usbeth* usbeth = (ecos_usbeth*) net->priv;
247
    int          res;
248
 
249
    if ((skb->len + 2) > ECOS_USBETH_MAXTU) {
250
        printk("ecos_usbeth: oversized packet of %d bytes\n", skb->len);
251
        return 0;
252
    }
253
 
254
    if (netif_queue_stopped(net)) {
255
        // Another transmission already in progress.
256
        // USB bulk operations should complete within 5s.
257
        int current_delay = jiffies - net->trans_start;
258
        if (current_delay < (5 * HZ)) {
259
            return 1;
260
        } else {
261
            // There has been a timeout. Discard this message.
262
            //printk("transmission timed out\n");
263
            usbeth->stats.tx_errors++;
264
            dev_kfree_skb(skb);
265
            return 0;
266
        }
267
    }
268
 
269
    spin_lock(&usbeth->usb_lock);
270
    usbeth->tx_buffer[0]        = skb->len & 0x00FF;
271
    usbeth->tx_buffer[1]        = (skb->len >> 8) & 0x00FF;
272
    memcpy(&(usbeth->tx_buffer[2]), skb->data, skb->len);
273
    usbeth->tx_urb.transfer_buffer_length = skb->len + 2;
274
 
275
    // Some targets are unhappy about receiving 0-length packets, not
276
    // just sending them.
277
    if (0 == (usbeth->tx_urb.transfer_buffer_length % 64)) {
278
        usbeth->tx_urb.transfer_buffer_length++;
279
    }
280
#if 0
281
    {
282
        int i;
283
        printk("--------------------------------------------------------------\n");
284
        printk("ecos_usbeth start_tx: len %d\n", skb->len + 2);
285
        for (i = 0; (i < (skb->len + 2)) && (i < 128); i+= 8) {
286
            printk("tx  %x %x %x %x %x %x %x %x\n",
287
                   usbeth->tx_buffer[i], usbeth->tx_buffer[i+1], usbeth->tx_buffer[i+2], usbeth->tx_buffer[i+3],
288
                   usbeth->tx_buffer[i+4], usbeth->tx_buffer[i+5], usbeth->tx_buffer[i+6], usbeth->tx_buffer[i+7]);
289
        }
290
        printk("--------------------------------------------------------------\n");
291
    }
292
#endif
293
    res = usb_submit_urb(&(usbeth->tx_urb));
294
    if (0 == res) {
295
        netif_stop_queue(net);
296
        net->trans_start        = jiffies;
297
        usbeth->stats.tx_packets++;
298
        usbeth->stats.tx_bytes  += skb->len;
299
    } else {
300
        printk("ecos_usbeth: failed to start USB packet transmission, %d\n", res);
301
        usbeth->stats.tx_errors++;
302
    }
303
 
304
    spin_unlock(&usbeth->usb_lock);
305
    dev_kfree_skb(skb);
306
    return 0;
307
}
308
 
309
 
310
// set_rx_mode()
311
// Invoked by the network stack to enable/disable promiscuous mode or
312
// for multicasting. The latter is not yet supported on the target
313
// side. The former involves a USB control message. The main call
314
// is not allowed to block.
315
static void
316
ecos_usbeth_set_rx_mode_callback(struct urb* urb)
317
{
318
    kfree(urb->setup_packet);
319
    usb_free_urb(urb);
320
}
321
 
322
static void
323
ecos_usbeth_set_rx_mode(struct net_device* net)
324
{
325
    ecos_usbeth* usbeth         = (ecos_usbeth*) net->priv;
326
    __u16        promiscuous    = net->flags & IFF_PROMISC;
327
    int          res;
328
 
329
    if (promiscuous != usbeth->target_promiscuous) {
330
        devrequest*     req;
331
        urb_t*          urb;
332
 
333
        urb = usb_alloc_urb(0);
334
        if ((urb_t*)0 == urb) {
335
            return;
336
        }
337
        req = kmalloc(sizeof(devrequest), GFP_KERNEL);
338
        if ((devrequest*)0 == req) {
339
            usb_free_urb(urb);
340
            return;
341
        }
342
        req->requesttype        = USB_TYPE_CLASS | USB_RECIP_DEVICE;
343
        req->request            = ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE;
344
        req->value              = cpu_to_le16p(&promiscuous);
345
        req->index              = 0;
346
        req->length             = 0;
347
 
348
        FILL_CONTROL_URB(urb,
349
                         usbeth->usb_dev,
350
                         usb_sndctrlpipe(usbeth->usb_dev, 0),
351
                         (unsigned char*) req,
352
                         (void*) 0,
353
                         0,
354
                         &ecos_usbeth_set_rx_mode_callback,
355
                         (void*) usbeth);
356
        res = usb_submit_urb(urb);
357
        if (0 != res) {
358
            kfree(req);
359
            usb_free_urb(urb);
360
        } else {
361
            usbeth->target_promiscuous = promiscuous;
362
        }
363
    }
364
}
365
 
366
// netdev_stats()
367
// Supply the current network statistics. These are held in
368
// the stats field of the ecos_usbeth structure
369
static struct net_device_stats*
370
ecos_usbeth_netdev_stats(struct net_device* net)
371
{
372
    ecos_usbeth* usbeth = (ecos_usbeth*) net->priv;
373
    return &(usbeth->stats);
374
}
375
 
376
// ioctl()
377
// Currently none of the network ioctl()'s are supported
378
static int
379
ecos_usbeth_ioctl(struct net_device* net, struct ifreq* request, int command)
380
{
381
    return -EINVAL;
382
}
383
 
384
// probe().
385
// This is invoked by the generic USB code when a new device has
386
// been detected and its configuration details have been extracted
387
// and stored in the usbdev structure. The interface_id specifies
388
// a specific USB interface, to cope with multifunction peripherals.
389
//
390
// FIXME; right now this code only copes with simple enumeration data.
391
// OK, to be really honest it just looks for the vendor and device ids
392
// in the simple test cases and ignores everything else.
393
//
394
// On success it should return a non-NULL pointer, which happens to be
395
// a newly allocated ecos_usbeth structure. This will get passed to
396
// the disconnect function. Filling in the ecos_usbeth structure will,
397
// amongst other things, register this as a network device driver.
398
// The MAC address is obtained from the peripheral via a control
399
// request.
400
 
401
static void*
402
ecos_usbeth_probe(struct usb_device* usbdev, unsigned int interface_id)
403
{
404
    struct net_device*  net;
405
    ecos_usbeth*        usbeth;
406
    int                 res;
407
    unsigned char       MAC[6];
408
    unsigned char       dummy[1];
409
    int                 tx_endpoint = -1;
410
    int                 rx_endpoint = -1;
411
    const ecos_usbeth_impl*   impl;
412
    int                 found_impl = 0;
413
 
414
    // See if this is the correct driver for this USB peripheral.
415
    impl = ecos_usbeth_implementations;
416
    while (impl->name != NULL) {
417
        if ((usbdev->descriptor.idVendor  != impl->vendor) ||
418
            (usbdev->descriptor.idProduct != impl->id)) {
419
            found_impl = 1;
420
            break;
421
        }
422
        impl++;
423
    }
424
    if (! found_impl) {
425
        return (void*) 0;
426
    }
427
 
428
    // For now only support USB-ethernet peripherals consisting of a single
429
    // configuration, with a single interface, with two bulk endpoints.
430
    if ((1 != usbdev->descriptor.bNumConfigurations)  ||
431
        (1 != usbdev->config[0].bNumInterfaces) ||
432
        (2 != usbdev->config[0].interface[0].altsetting->bNumEndpoints)) {
433
        return (void*) 0;
434
    }
435
    if ((0 == (usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & USB_DIR_IN)) &&
436
        (0 != (usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & USB_DIR_IN))) {
437
        tx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress;
438
        rx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & ~USB_DIR_IN;
439
    }
440
    if ((0 != (usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & USB_DIR_IN)) &&
441
        (0 == (usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & USB_DIR_IN))) {
442
        tx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress;
443
        rx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & ~USB_DIR_IN;
444
    }
445
    if (-1 == tx_endpoint) {
446
        return (void*) 0;
447
    }
448
 
449
    res = usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue);
450
    if (0 != res) {
451
        printk("ecos_usbeth: failed to set configuration, %d\n", res);
452
        return (void*) 0;
453
    }
454
    res = usb_control_msg(usbdev,
455
                          usb_rcvctrlpipe(usbdev, 0),
456
                          ECOS_USBETH_CONTROL_GET_MAC_ADDRESS,
457
                          USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN,
458
                          0,
459
                          0,
460
                          (void*) MAC,
461
                          6,
462
                          5 * HZ);
463
    if (6 != res) {
464
        printk("ecos_usbeth: failed to get MAC address, %d\n", res);
465
        return (void*) 0;
466
    }
467
 
468
    res = usb_control_msg(usbdev,
469
                          usb_sndctrlpipe(usbdev, 0),                           // pipe
470
                          ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE,             // request
471
                          USB_TYPE_CLASS | USB_RECIP_DEVICE,                    // requesttype
472
                          0,                                                    // value
473
                          0,                                                    // index
474
                          (void*) dummy,                                        // data
475
                          0,                                                    // size
476
                          5 * HZ);                                              // timeout
477
    if (0 != res) {
478
        printk("ecos_usbeth: failed to disable promiscous mode, %d\n", res);
479
    }
480
 
481
    usbeth = (ecos_usbeth*) kmalloc(sizeof(ecos_usbeth), GFP_KERNEL);
482
    if ((ecos_usbeth*)0 == usbeth) {
483
        printk("ecos_usbeth: failed to allocate memory for usbeth data structure\n");
484
        return (void*) 0;
485
    }
486
    memset(usbeth, 0, sizeof(ecos_usbeth));
487
 
488
    net                 = init_etherdev(0, 0);
489
    if ((struct net_device*) 0 == net) {
490
        kfree(usbeth);
491
        printk("ecos_usbeth: failed to allocate memory for net data structure\n");
492
        return (void*) 0;
493
    }
494
 
495
    usbeth->usb_lock    = SPIN_LOCK_UNLOCKED;
496
    usbeth->usb_dev     = usbdev;
497
    FILL_BULK_URB(&(usbeth->tx_urb), usbdev, usb_sndbulkpipe(usbdev, tx_endpoint),
498
                  usbeth->tx_buffer, ECOS_USBETH_MAXTU, &ecos_usbeth_tx_callback, (void*) usbeth);
499
    FILL_BULK_URB(&(usbeth->rx_urb), usbdev, usb_rcvbulkpipe(usbdev, rx_endpoint),
500
                  usbeth->rx_buffer, ECOS_USBETH_MAXTU, &ecos_usbeth_rx_callback, (void*) usbeth);
501
 
502
    usbeth->net_dev             = net;
503
    usbeth->target_promiscuous  = 0;
504
 
505
    net->priv                   = (void*) usbeth;
506
    net->open                   = &ecos_usbeth_open;
507
    net->stop                   = &ecos_usbeth_close;
508
    net->do_ioctl               = &ecos_usbeth_ioctl;
509
    net->hard_start_xmit        = &ecos_usbeth_start_tx;
510
    net->set_multicast_list     = &ecos_usbeth_set_rx_mode;
511
    net->get_stats              = &ecos_usbeth_netdev_stats;
512
    net->mtu                    = 1500; // ECOS_USBETH_MAXTU - 2;
513
    memcpy(net->dev_addr, MAC, 6);
514
 
515
    printk("eCos-based USB ethernet peripheral active at %s\n", net->name);
516
    MOD_INC_USE_COUNT;
517
    return (void*) usbeth;
518
}
519
 
520
// disconnect().
521
// Invoked after probe() has recognized a device but that device
522
// has gone away. 
523
static void
524
ecos_usbeth_disconnect(struct usb_device* usbdev, void* data)
525
{
526
    ecos_usbeth* usbeth = (ecos_usbeth*) data;
527
    if (!usbeth) {
528
        printk("ecos_usbeth: warning, disconnecting unconnected device\n");
529
        return;
530
    }
531
    if (0 != netif_running(usbeth->net_dev)) {
532
        ecos_usbeth_close(usbeth->net_dev);
533
    }
534
    unregister_netdev(usbeth->net_dev);
535
    if (-EINPROGRESS == usbeth->rx_urb.status) {
536
        usb_unlink_urb(&(usbeth->rx_urb));
537
    }
538
    if (-EINPROGRESS == usbeth->tx_urb.status) {
539
        usb_unlink_urb(&(usbeth->tx_urb));
540
    }
541
    kfree(usbeth);
542
    MOD_DEC_USE_COUNT;
543
}
544
 
545
static struct usb_driver ecos_usbeth_driver = {
546
    name:       "ecos_usbeth",
547
    probe:      ecos_usbeth_probe,
548
    disconnect: ecos_usbeth_disconnect,
549
};
550
 
551
// init()
552
// Called when the module is loaded. It just registers the device with
553
// the generic USB code. Nothing else can really be done until
554
// the USB code detects that a device has been attached.
555
int __init
556
ecos_usbeth_init(void)
557
{
558
    printk("eCos USB-ethernet device driver\n");
559
    return usb_register(&ecos_usbeth_driver);
560
}
561
 
562
// exit()
563
// Called when the module is unloaded. disconnect() will be
564
// invoked if appropriate.
565
void __exit
566
ecos_usbeth_exit(void)
567
{
568
    usb_deregister(&ecos_usbeth_driver);
569
}
570
 
571
module_init(ecos_usbeth_init);
572
module_exit(ecos_usbeth_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.