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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [net/] [hp-plus.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */
2
/*
3
        Written 1994 by Donald Becker.
4
 
5
        This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
6
        These cards are sold under several model numbers, usually 2724*.
7
 
8
        This software may be used and distributed according to the terms
9
        of the GNU General Public License, incorporated herein by reference.
10
 
11
        The author may be reached as becker@scyld.com, or C/O
12
        Scyld Computing Corporation
13
        410 Severn Ave., Suite 210
14
        Annapolis MD 21403
15
 
16
        As is often the case, a great deal of credit is owed to Russ Nelson.
17
        The Crynwr packet driver was my primary source of HP-specific
18
        programming information.
19
*/
20
 
21
static const char version[] =
22
"hp-plus.c:v1.10 9/24/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
23
 
24
#include <linux/module.h>
25
 
26
#include <linux/string.h>               /* Important -- this inlines word moves. */
27
#include <linux/kernel.h>
28
#include <linux/errno.h>
29
#include <linux/ioport.h>
30
#include <linux/netdevice.h>
31
#include <linux/etherdevice.h>
32
#include <linux/init.h>
33
#include <linux/delay.h>
34
 
35
#include <asm/system.h>
36
#include <asm/io.h>
37
 
38
#include "8390.h"
39
 
40
#define DRV_NAME "hp-plus"
41
 
42
/* A zero-terminated list of I/O addresses to be probed. */
43
static unsigned int hpplus_portlist[] __initdata =
44
{0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
45
 
46
/*
47
   The HP EtherTwist chip implementation is a fairly routine DP8390
48
   implementation.  It allows both shared memory and programmed-I/O buffer
49
   access, using a custom interface for both.  The programmed-I/O mode is
50
   entirely implemented in the HP EtherTwist chip, bypassing the problem
51
   ridden built-in 8390 facilities used on NE2000 designs.  The shared
52
   memory mode is likewise special, with an offset register used to make
53
   packets appear at the shared memory base.  Both modes use a base and bounds
54
   page register to hide the Rx ring buffer wrap -- a packet that spans the
55
   end of physical buffer memory appears continuous to the driver. (c.f. the
56
   3c503 and Cabletron E2100)
57
 
58
   A special note: the internal buffer of the board is only 8 bits wide.
59
   This lays several nasty traps for the unaware:
60
   - the 8390 must be programmed for byte-wide operations
61
   - all I/O and memory operations must work on whole words (the access
62
     latches are serially preloaded and have no byte-swapping ability).
63
 
64
   This board is laid out in I/O space much like the earlier HP boards:
65
   the first 16 locations are for the board registers, and the second 16 are
66
   for the 8390.  The board is easy to identify, with both a dedicated 16 bit
67
   ID register and a constant 0x530* value in the upper bits of the paging
68
   register.
69
*/
70
 
71
#define HP_ID                   0x00    /* ID register, always 0x4850. */
72
#define HP_PAGING               0x02    /* Registers visible @ 8-f, see PageName. */
73
#define HPP_OPTION              0x04    /* Bitmapped options, see HP_Option.    */
74
#define HPP_OUT_ADDR    0x08    /* I/O output location in Perf_Page.    */
75
#define HPP_IN_ADDR             0x0A    /* I/O input location in Perf_Page.             */
76
#define HP_DATAPORT             0x0c    /* I/O data transfer in Perf_Page.              */
77
#define NIC_OFFSET              0x10    /* Offset to the 8390 registers.                */
78
#define HP_IO_EXTENT    32
79
 
80
#define HP_START_PG             0x00    /* First page of TX buffer */
81
#define HP_STOP_PG              0x80    /* Last page +1 of RX ring */
82
 
83
/* The register set selected in HP_PAGING. */
84
enum PageName {
85
        Perf_Page = 0,                           /* Normal operation. */
86
        MAC_Page = 1,                           /* The ethernet address (+checksum). */
87
        HW_Page = 2,                            /* EEPROM-loaded hardware parameters. */
88
        LAN_Page = 4,                           /* Transceiver selection, testing, etc. */
89
        ID_Page = 6 };
90
 
91
/* The bit definitions for the HPP_OPTION register. */
92
enum HP_Option {
93
        NICReset = 1, ChipReset = 2,    /* Active low, really UNreset. */
94
        EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20,
95
        MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, };
96
 
97
static int hpp_probe1(struct net_device *dev, int ioaddr);
98
 
99
static void hpp_reset_8390(struct net_device *dev);
100
static int hpp_open(struct net_device *dev);
101
static int hpp_close(struct net_device *dev);
102
static void hpp_mem_block_input(struct net_device *dev, int count,
103
                                                  struct sk_buff *skb, int ring_offset);
104
static void hpp_mem_block_output(struct net_device *dev, int count,
105
                                                        const unsigned char *buf, int start_page);
106
static void hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
107
                                                  int ring_page);
108
static void hpp_io_block_input(struct net_device *dev, int count,
109
                                                  struct sk_buff *skb, int ring_offset);
110
static void hpp_io_block_output(struct net_device *dev, int count,
111
                                                        const unsigned char *buf, int start_page);
112
static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
113
                                                  int ring_page);
114
 
115
 
116
/*      Probe a list of addresses for an HP LAN+ adaptor.
117
        This routine is almost boilerplate. */
118
 
119
static int __init do_hpp_probe(struct net_device *dev)
120
{
121
        int i;
122
        int base_addr = dev->base_addr;
123
        int irq = dev->irq;
124
 
125
        if (base_addr > 0x1ff)          /* Check a single specified location. */
126
                return hpp_probe1(dev, base_addr);
127
        else if (base_addr != 0) /* Don't probe at all. */
128
                return -ENXIO;
129
 
130
        for (i = 0; hpplus_portlist[i]; i++) {
131
                if (hpp_probe1(dev, hpplus_portlist[i]) == 0)
132
                        return 0;
133
                dev->irq = irq;
134
        }
135
 
136
        return -ENODEV;
137
}
138
 
139
#ifndef MODULE
140
struct net_device * __init hp_plus_probe(int unit)
141
{
142
        struct net_device *dev = alloc_ei_netdev();
143
        int err;
144
 
145
        if (!dev)
146
                return ERR_PTR(-ENOMEM);
147
 
148
        sprintf(dev->name, "eth%d", unit);
149
        netdev_boot_setup_check(dev);
150
 
151
        err = do_hpp_probe(dev);
152
        if (err)
153
                goto out;
154
        return dev;
155
out:
156
        free_netdev(dev);
157
        return ERR_PTR(err);
158
}
159
#endif
160
 
161
/* Do the interesting part of the probe at a single address. */
162
static int __init hpp_probe1(struct net_device *dev, int ioaddr)
163
{
164
        int i, retval;
165
        unsigned char checksum = 0;
166
        const char name[] = "HP-PC-LAN+";
167
        int mem_start;
168
        static unsigned version_printed;
169
        DECLARE_MAC_BUF(mac);
170
 
171
        if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
172
                return -EBUSY;
173
 
174
        /* Check for the HP+ signature, 50 48 0x 53. */
175
        if (inw(ioaddr + HP_ID) != 0x4850
176
                || (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) {
177
                retval = -ENODEV;
178
                goto out;
179
        }
180
 
181
        if (ei_debug  &&  version_printed++ == 0)
182
                printk(version);
183
 
184
        printk("%s: %s at %#3x, ", dev->name, name, ioaddr);
185
 
186
        /* Retrieve and checksum the station address. */
187
        outw(MAC_Page, ioaddr + HP_PAGING);
188
 
189
        for(i = 0; i < ETHER_ADDR_LEN; i++) {
190
                unsigned char inval = inb(ioaddr + 8 + i);
191
                dev->dev_addr[i] = inval;
192
                checksum += inval;
193
        }
194
        checksum += inb(ioaddr + 14);
195
 
196
        printk("%s", print_mac(mac, dev->dev_addr));
197
 
198
        if (checksum != 0xff) {
199
                printk(" bad checksum %2.2x.\n", checksum);
200
                retval = -ENODEV;
201
                goto out;
202
        } else {
203
                /* Point at the Software Configuration Flags. */
204
                outw(ID_Page, ioaddr + HP_PAGING);
205
                printk(" ID %4.4x", inw(ioaddr + 12));
206
        }
207
 
208
        /* Read the IRQ line. */
209
        outw(HW_Page, ioaddr + HP_PAGING);
210
        {
211
                int irq = inb(ioaddr + 13) & 0x0f;
212
                int option = inw(ioaddr + HPP_OPTION);
213
 
214
                dev->irq = irq;
215
                if (option & MemEnable) {
216
                        mem_start = inw(ioaddr + 9) << 8;
217
                        printk(", IRQ %d, memory address %#x.\n", irq, mem_start);
218
                } else {
219
                        mem_start = 0;
220
                        printk(", IRQ %d, programmed-I/O mode.\n", irq);
221
                }
222
        }
223
 
224
        /* Set the wrap registers for string I/O reads.   */
225
        outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
226
 
227
        /* Set the base address to point to the NIC, not the "real" base! */
228
        dev->base_addr = ioaddr + NIC_OFFSET;
229
 
230
        dev->open = &hpp_open;
231
        dev->stop = &hpp_close;
232
#ifdef CONFIG_NET_POLL_CONTROLLER
233
        dev->poll_controller = ei_poll;
234
#endif
235
 
236
        ei_status.name = name;
237
        ei_status.word16 = 0;            /* Agggghhhhh! Debug time: 2 days! */
238
        ei_status.tx_start_page = HP_START_PG;
239
        ei_status.rx_start_page = HP_START_PG + TX_PAGES/2;
240
        ei_status.stop_page = HP_STOP_PG;
241
 
242
        ei_status.reset_8390 = &hpp_reset_8390;
243
        ei_status.block_input = &hpp_io_block_input;
244
        ei_status.block_output = &hpp_io_block_output;
245
        ei_status.get_8390_hdr = &hpp_io_get_8390_hdr;
246
 
247
        /* Check if the memory_enable flag is set in the option register. */
248
        if (mem_start) {
249
                ei_status.block_input = &hpp_mem_block_input;
250
                ei_status.block_output = &hpp_mem_block_output;
251
                ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
252
                dev->mem_start = mem_start;
253
                ei_status.mem = ioremap(mem_start,
254
                                        (HP_STOP_PG - HP_START_PG)*256);
255
                if (!ei_status.mem) {
256
                        retval = -ENOMEM;
257
                        goto out;
258
                }
259
                ei_status.rmem_start = dev->mem_start + TX_PAGES/2*256;
260
                dev->mem_end = ei_status.rmem_end
261
                        = dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
262
        }
263
 
264
        outw(Perf_Page, ioaddr + HP_PAGING);
265
        NS8390_init(dev, 0);
266
        /* Leave the 8390 and HP chip reset. */
267
        outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
268
 
269
        retval = register_netdev(dev);
270
        if (retval)
271
                goto out1;
272
        return 0;
273
out1:
274
        iounmap(ei_status.mem);
275
out:
276
        release_region(ioaddr, HP_IO_EXTENT);
277
        return retval;
278
}
279
 
280
static int
281
hpp_open(struct net_device *dev)
282
{
283
        int ioaddr = dev->base_addr - NIC_OFFSET;
284
        int option_reg;
285
        int retval;
286
 
287
        if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
288
            return retval;
289
        }
290
 
291
        /* Reset the 8390 and HP chip. */
292
        option_reg = inw(ioaddr + HPP_OPTION);
293
        outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
294
        udelay(5);
295
        /* Unreset the board and enable interrupts. */
296
        outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
297
 
298
        /* Set the wrap registers for programmed-I/O operation.   */
299
        outw(HW_Page, ioaddr + HP_PAGING);
300
        outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
301
 
302
        /* Select the operational page. */
303
        outw(Perf_Page, ioaddr + HP_PAGING);
304
 
305
        ei_open(dev);
306
        return 0;
307
}
308
 
309
static int
310
hpp_close(struct net_device *dev)
311
{
312
        int ioaddr = dev->base_addr - NIC_OFFSET;
313
        int option_reg = inw(ioaddr + HPP_OPTION);
314
 
315
        free_irq(dev->irq, dev);
316
        ei_close(dev);
317
        outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
318
                 ioaddr + HPP_OPTION);
319
 
320
        return 0;
321
}
322
 
323
static void
324
hpp_reset_8390(struct net_device *dev)
325
{
326
        int ioaddr = dev->base_addr - NIC_OFFSET;
327
        int option_reg = inw(ioaddr + HPP_OPTION);
328
 
329
        if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
330
 
331
        outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
332
        /* Pause a few cycles for the hardware reset to take place. */
333
        udelay(5);
334
        ei_status.txing = 0;
335
        outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
336
 
337
        udelay(5);
338
 
339
 
340
        if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
341
                printk("%s: hp_reset_8390() did not complete.\n", dev->name);
342
 
343
        if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
344
        return;
345
}
346
 
347
/* The programmed-I/O version of reading the 4 byte 8390 specific header.
348
   Note that transfer with the EtherTwist+ must be on word boundaries. */
349
 
350
static void
351
hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
352
{
353
        int ioaddr = dev->base_addr - NIC_OFFSET;
354
 
355
        outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
356
        insw(ioaddr + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
357
}
358
 
359
/* Block input and output, similar to the Crynwr packet driver. */
360
 
361
static void
362
hpp_io_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
363
{
364
        int ioaddr = dev->base_addr - NIC_OFFSET;
365
        char *buf = skb->data;
366
 
367
        outw(ring_offset, ioaddr + HPP_IN_ADDR);
368
        insw(ioaddr + HP_DATAPORT, buf, count>>1);
369
        if (count & 0x01)
370
        buf[count-1] = inw(ioaddr + HP_DATAPORT);
371
}
372
 
373
/* The corresponding shared memory versions of the above 2 functions. */
374
 
375
static void
376
hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
377
{
378
        int ioaddr = dev->base_addr - NIC_OFFSET;
379
        int option_reg = inw(ioaddr + HPP_OPTION);
380
 
381
        outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
382
        outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
383
        memcpy_fromio(hdr, ei_status.mem, sizeof(struct e8390_pkt_hdr));
384
        outw(option_reg, ioaddr + HPP_OPTION);
385
        hdr->count = (le16_to_cpu(hdr->count) + 3) & ~3;        /* Round up allocation. */
386
}
387
 
388
static void
389
hpp_mem_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
390
{
391
        int ioaddr = dev->base_addr - NIC_OFFSET;
392
        int option_reg = inw(ioaddr + HPP_OPTION);
393
 
394
        outw(ring_offset, ioaddr + HPP_IN_ADDR);
395
 
396
        outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
397
 
398
        /* Caution: this relies on get_8390_hdr() rounding up count!
399
           Also note that we *can't* use eth_io_copy_and_sum() because
400
           it will not always copy "count" bytes (e.g. padded IP).  */
401
 
402
        memcpy_fromio(skb->data, ei_status.mem, count);
403
        outw(option_reg, ioaddr + HPP_OPTION);
404
}
405
 
406
/* A special note: we *must* always transfer >=16 bit words.
407
   It's always safe to round up, so we do. */
408
static void
409
hpp_io_block_output(struct net_device *dev, int count,
410
                                        const unsigned char *buf, int start_page)
411
{
412
        int ioaddr = dev->base_addr - NIC_OFFSET;
413
        outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
414
        outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
415
        return;
416
}
417
 
418
static void
419
hpp_mem_block_output(struct net_device *dev, int count,
420
                                const unsigned char *buf, int start_page)
421
{
422
        int ioaddr = dev->base_addr - NIC_OFFSET;
423
        int option_reg = inw(ioaddr + HPP_OPTION);
424
 
425
        outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
426
        outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
427
        memcpy_toio(ei_status.mem, buf, (count + 3) & ~3);
428
        outw(option_reg, ioaddr + HPP_OPTION);
429
 
430
        return;
431
}
432
 
433
 
434
#ifdef MODULE
435
#define MAX_HPP_CARDS   4       /* Max number of HPP cards per module */
436
static struct net_device *dev_hpp[MAX_HPP_CARDS];
437
static int io[MAX_HPP_CARDS];
438
static int irq[MAX_HPP_CARDS];
439
 
440
module_param_array(io, int, NULL, 0);
441
module_param_array(irq, int, NULL, 0);
442
MODULE_PARM_DESC(io, "I/O port address(es)");
443
MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected");
444
MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver");
445
MODULE_LICENSE("GPL");
446
 
447
/* This is set up so that only a single autoprobe takes place per call.
448
ISA device autoprobes on a running machine are not recommended. */
449
int __init
450
init_module(void)
451
{
452
        struct net_device *dev;
453
        int this_dev, found = 0;
454
 
455
        for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
456
                if (io[this_dev] == 0)  {
457
                        if (this_dev != 0) break; /* only autoprobe 1st one */
458
                        printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n");
459
                }
460
                dev = alloc_ei_netdev();
461
                if (!dev)
462
                        break;
463
                dev->irq = irq[this_dev];
464
                dev->base_addr = io[this_dev];
465
                if (do_hpp_probe(dev) == 0) {
466
                        dev_hpp[found++] = dev;
467
                        continue;
468
                }
469
                free_netdev(dev);
470
                printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
471
                break;
472
        }
473
        if (found)
474
                return 0;
475
        return -ENXIO;
476
}
477
 
478
static void cleanup_card(struct net_device *dev)
479
{
480
        /* NB: hpp_close() handles free_irq */
481
        iounmap(ei_status.mem);
482
        release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
483
}
484
 
485
void __exit
486
cleanup_module(void)
487
{
488
        int this_dev;
489
 
490
        for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
491
                struct net_device *dev = dev_hpp[this_dev];
492
                if (dev) {
493
                        unregister_netdev(dev);
494
                        cleanup_card(dev);
495
                        free_netdev(dev);
496
                }
497
        }
498
}
499
#endif /* MODULE */

powered by: WebSVN 2.1.0

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