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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [net/] [hp.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/* hp.c: A HP LAN ethernet driver for linux. */
2
/*
3
        Written 1993-94 by Donald Becker.
4
 
5
        Copyright 1993 United States Government as represented by the
6
        Director, National Security Agency.
7
 
8
        This software may be used and distributed according to the terms
9
        of the GNU Public License, incorporated herein by reference.
10
 
11
        The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
12
        Center of Excellence in Space Data and Information Sciences
13
           Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
14
 
15
        This is a driver for the HP PC-LAN adaptors.
16
 
17
        Sources:
18
          The Crynwr packet driver.
19
*/
20
 
21
static const char *version =
22
        "hp.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
23
 
24
 
25
#include <linux/module.h>
26
 
27
#include <linux/kernel.h>
28
#include <linux/sched.h>
29
#include <linux/errno.h>
30
#include <linux/ioport.h>
31
#include <linux/netdevice.h>
32
#include <linux/etherdevice.h>
33
 
34
#include <asm/system.h>
35
#include <asm/io.h>
36
 
37
#include "8390.h"
38
 
39
/* A zero-terminated list of I/O addresses to be probed. */
40
static unsigned int hppclan_portlist[] =
41
{ 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
42
 
43
#define HP_IO_EXTENT    32
44
 
45
#define HP_DATAPORT             0x0c    /* "Remote DMA" data port. */
46
#define HP_ID                   0x07
47
#define HP_CONFIGURE    0x08    /* Configuration register. */
48
#define  HP_RUN                 0x01    /* 1 == Run, 0 == reset. */
49
#define  HP_IRQ                 0x0E    /* Mask for software-configured IRQ line. */
50
#define  HP_DATAON              0x10    /* Turn on dataport */
51
#define NIC_OFFSET              0x10    /* Offset the 8390 registers. */
52
 
53
#define HP_START_PG             0x00    /* First page of TX buffer */
54
#define HP_8BSTOP_PG    0x80    /* Last page +1 of RX ring */
55
#define HP_16BSTOP_PG   0xFF    /* Same, for 16 bit cards. */
56
 
57
int hp_probe(struct device *dev);
58
int hp_probe1(struct device *dev, int ioaddr);
59
 
60
static int hp_open(struct device *dev);
61
static int hp_close(struct device *dev);
62
static void hp_reset_8390(struct device *dev);
63
static void hp_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
64
                                        int ring_page);
65
static void hp_block_input(struct device *dev, int count,
66
                                        struct sk_buff *skb , int ring_offset);
67
static void hp_block_output(struct device *dev, int count,
68
                                                        const unsigned char *buf, const int start_page);
69
 
70
static void hp_init_card(struct device *dev);
71
 
72
/* The map from IRQ number to HP_CONFIGURE register setting. */
73
/* My default is IRQ5      0  1  2  3  4  5  6  7  8  9 10 11 */
74
static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
75
 
76
 
77
/*      Probe for an HP LAN adaptor.
78
        Also initialize the card and fill in STATION_ADDR with the station
79
        address. */
80
#ifdef HAVE_DEVLIST
81
struct netdev_entry netcard_drv =
82
{"hp", hp_probe1, HP_IO_EXTENT, hppclan_portlist};
83
#else
84
 
85
int hp_probe(struct device *dev)
86
{
87
        int i;
88
        int base_addr = dev ? dev->base_addr : 0;
89
 
90
        if (base_addr > 0x1ff)          /* Check a single specified location. */
91
                return hp_probe1(dev, base_addr);
92
        else if (base_addr != 0) /* Don't probe at all. */
93
                return ENXIO;
94
 
95
        for (i = 0; hppclan_portlist[i]; i++) {
96
                int ioaddr = hppclan_portlist[i];
97
                if (check_region(ioaddr, HP_IO_EXTENT))
98
                        continue;
99
                if (hp_probe1(dev, ioaddr) == 0)
100
                        return 0;
101
        }
102
 
103
        return ENODEV;
104
}
105
#endif
106
 
107
int hp_probe1(struct device *dev, int ioaddr)
108
{
109
        int i, board_id, wordmode;
110
        const char *name;
111
        static unsigned version_printed = 0;
112
 
113
        /* Check for the HP physical address, 08 00 09 xx xx xx. */
114
        /* This really isn't good enough: we may pick up HP LANCE boards
115
           also!  Avoid the lance 0x5757 signature. */
116
        if (inb(ioaddr) != 0x08
117
                || inb(ioaddr+1) != 0x00
118
                || inb(ioaddr+2) != 0x09
119
                || inb(ioaddr+14) == 0x57)
120
                return ENODEV;
121
 
122
        /* Set up the parameters based on the board ID.
123
           If you have additional mappings, please mail them to me -djb. */
124
        if ((board_id = inb(ioaddr + HP_ID)) & 0x80) {
125
                name = "HP27247";
126
                wordmode = 1;
127
        } else {
128
                name = "HP27250";
129
                wordmode = 0;
130
        }
131
 
132
        /* We should have a "dev" from Space.c or the static module table. */
133
        if (dev == NULL) {
134
                printk("hp.c: Passed a NULL device.\n");
135
                dev = init_etherdev(0, 0);
136
        }
137
 
138
        if (ei_debug  &&  version_printed++ == 0)
139
                printk(version);
140
 
141
        printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
142
 
143
        for(i = 0; i < ETHER_ADDR_LEN; i++)
144
                printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
145
 
146
        /* Snarf the interrupt now.  Someday this could be moved to open(). */
147
        if (dev->irq < 2) {
148
                int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
149
                int irq_8list[] = { 7, 5, 3, 4, 9, 0};
150
                int *irqp = wordmode ? irq_16list : irq_8list;
151
                do {
152
                        int irq = *irqp;
153
                        if (request_irq (irq, NULL, 0, "bogus", NULL) != -EBUSY) {
154
                                autoirq_setup(0);
155
                                /* Twinkle the interrupt, and check if it's seen. */
156
                                outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
157
                                outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
158
                                if (irq == autoirq_report(0)              /* It's a good IRQ line! */
159
                                        && request_irq (irq, &ei_interrupt, 0, "hp", NULL) == 0) {
160
                                        printk(" selecting IRQ %d.\n", irq);
161
                                        dev->irq = *irqp;
162
                                        break;
163
                                }
164
                        }
165
                } while (*++irqp);
166
                if (*irqp == 0) {
167
                        printk(" no free IRQ lines.\n");
168
                        return EBUSY;
169
                }
170
        } else {
171
                if (dev->irq == 2)
172
                        dev->irq = 9;
173
                if (request_irq(dev->irq, ei_interrupt, 0, "hp", NULL)) {
174
                        printk (" unable to get IRQ %d.\n", dev->irq);
175
                        return EBUSY;
176
                }
177
        }
178
 
179
        /* Allocate dev->priv and fill in 8390 specific dev fields. */
180
        if (ethdev_init(dev)) {
181
                printk (" unable to get memory for dev->priv.\n");
182
                free_irq(dev->irq, NULL);
183
                return -ENOMEM;
184
        }
185
 
186
        /* Grab the region so we can find another board if something fails. */
187
        request_region(ioaddr, HP_IO_EXTENT,"hp");
188
 
189
        /* Set the base address to point to the NIC, not the "real" base! */
190
        dev->base_addr = ioaddr + NIC_OFFSET;
191
        dev->open = &hp_open;
192
        dev->stop = &hp_close;
193
 
194
        ei_status.name = name;
195
        ei_status.word16 = wordmode;
196
        ei_status.tx_start_page = HP_START_PG;
197
        ei_status.rx_start_page = HP_START_PG + TX_PAGES;
198
        ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG;
199
 
200
        ei_status.reset_8390 = &hp_reset_8390;
201
        ei_status.get_8390_hdr = &hp_get_8390_hdr;
202
        ei_status.block_input = &hp_block_input;
203
        ei_status.block_output = &hp_block_output;
204
        hp_init_card(dev);
205
 
206
        return 0;
207
}
208
 
209
static int
210
hp_open(struct device *dev)
211
{
212
        ei_open(dev);
213
        MOD_INC_USE_COUNT;
214
        return 0;
215
}
216
 
217
static int
218
hp_close(struct device *dev)
219
{
220
        ei_close(dev);
221
        MOD_DEC_USE_COUNT;
222
        return 0;
223
}
224
 
225
static void
226
hp_reset_8390(struct device *dev)
227
{
228
        int hp_base = dev->base_addr - NIC_OFFSET;
229
        int saved_config = inb_p(hp_base + HP_CONFIGURE);
230
 
231
        if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
232
        outb_p(0x00, hp_base + HP_CONFIGURE);
233
        ei_status.txing = 0;
234
        /* Pause just a few cycles for the hardware reset to take place. */
235
        SLOW_DOWN_IO;
236
        SLOW_DOWN_IO;
237
 
238
        outb_p(saved_config, hp_base + HP_CONFIGURE);
239
        SLOW_DOWN_IO; SLOW_DOWN_IO;
240
 
241
        if ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
242
                printk("%s: hp_reset_8390() did not complete.\n", dev->name);
243
 
244
        if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
245
        return;
246
}
247
 
248
static void
249
hp_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
250
{
251
        int nic_base = dev->base_addr;
252
        int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
253
 
254
        outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
255
        outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
256
        outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
257
        outb_p(0, nic_base + EN0_RCNTHI);
258
        outb_p(0, nic_base + EN0_RSARLO);        /* On page boundary */
259
        outb_p(ring_page, nic_base + EN0_RSARHI);
260
        outb_p(E8390_RREAD+E8390_START, nic_base);
261
 
262
        if (ei_status.word16)
263
          insw(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
264
        else
265
          insb(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
266
 
267
        outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
268
}
269
 
270
/* Block input and output, similar to the Crynwr packet driver. If you are
271
   porting to a new ethercard look at the packet driver source for hints.
272
   The HP LAN doesn't use shared memory -- we put the packet
273
   out through the "remote DMA" dataport. */
274
 
275
static void
276
hp_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
277
{
278
        int nic_base = dev->base_addr;
279
        int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
280
        int xfer_count = count;
281
        char *buf = skb->data;
282
 
283
        outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
284
        outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
285
        outb_p(count & 0xff, nic_base + EN0_RCNTLO);
286
        outb_p(count >> 8, nic_base + EN0_RCNTHI);
287
        outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
288
        outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
289
        outb_p(E8390_RREAD+E8390_START, nic_base);
290
        if (ei_status.word16) {
291
          insw(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
292
          if (count & 0x01)
293
                buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
294
        } else {
295
                insb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
296
        }
297
        /* This is for the ALPHA version only, remove for later releases. */
298
        if (ei_debug > 0) {                      /* DMA termination address check... */
299
          int high = inb_p(nic_base + EN0_RSARHI);
300
          int low = inb_p(nic_base + EN0_RSARLO);
301
          int addr = (high << 8) + low;
302
          /* Check only the lower 8 bits so we can ignore ring wrap. */
303
          if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
304
                printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
305
                           dev->name, ring_offset + xfer_count, addr);
306
        }
307
        outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
308
}
309
 
310
static void
311
hp_block_output(struct device *dev, int count,
312
                                const unsigned char *buf, const int start_page)
313
{
314
        int nic_base = dev->base_addr;
315
        int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
316
 
317
        outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
318
        /* Round the count up for word writes.  Do we need to do this?
319
           What effect will an odd byte count have on the 8390?
320
           I should check someday. */
321
        if (ei_status.word16 && (count & 0x01))
322
          count++;
323
        /* We should already be in page 0, but to be safe... */
324
        outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
325
 
326
#ifdef NE8390_RW_BUGFIX
327
        /* Handle the read-before-write bug the same way as the
328
           Crynwr packet driver -- the NatSemi method doesn't work. */
329
        outb_p(0x42, nic_base + EN0_RCNTLO);
330
        outb_p(0,        nic_base + EN0_RCNTHI);
331
        outb_p(0xff, nic_base + EN0_RSARLO);
332
        outb_p(0x00, nic_base + EN0_RSARHI);
333
#define NE_CMD          0x00
334
        outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
335
        /* Make certain that the dummy read has occurred. */
336
        inb_p(0x61);
337
        inb_p(0x61);
338
#endif
339
 
340
        outb_p(count & 0xff, nic_base + EN0_RCNTLO);
341
        outb_p(count >> 8,       nic_base + EN0_RCNTHI);
342
        outb_p(0x00, nic_base + EN0_RSARLO);
343
        outb_p(start_page, nic_base + EN0_RSARHI);
344
 
345
        outb_p(E8390_RWRITE+E8390_START, nic_base);
346
        if (ei_status.word16) {
347
                /* Use the 'rep' sequence for 16 bit boards. */
348
                outsw(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
349
        } else {
350
                outsb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
351
        }
352
 
353
        /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
354
 
355
        /* This is for the ALPHA version only, remove for later releases. */
356
        if (ei_debug > 0) {                      /* DMA termination address check... */
357
          int high = inb_p(nic_base + EN0_RSARHI);
358
          int low  = inb_p(nic_base + EN0_RSARLO);
359
          int addr = (high << 8) + low;
360
          if ((start_page << 8) + count != addr)
361
                printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
362
                           dev->name, (start_page << 8) + count, addr);
363
        }
364
        outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
365
        return;
366
}
367
 
368
/* This function resets the ethercard if something screws up. */
369
static void
370
hp_init_card(struct device *dev)
371
{
372
        int irq = dev->irq;
373
        NS8390_init(dev, 0);
374
        outb_p(irqmap[irq&0x0f] | HP_RUN,
375
                   dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
376
        return;
377
}
378
 
379
#ifdef MODULE
380
#define MAX_HP_CARDS    4       /* Max number of HP cards per module */
381
#define NAMELEN         8       /* # of chars for storing dev->name */
382
static char namelist[NAMELEN * MAX_HP_CARDS] = { 0, };
383
static struct device dev_hp[MAX_HP_CARDS] = {
384
        {
385
                NULL,           /* assign a chunk of namelist[] below */
386
                0, 0, 0, 0,
387
                0, 0,
388
                0, 0, 0, NULL, NULL
389
        },
390
};
391
 
392
static int io[MAX_HP_CARDS] = { 0, };
393
static int irq[MAX_HP_CARDS]  = { 0, };
394
 
395
/* This is set up so that only a single autoprobe takes place per call.
396
ISA device autoprobes on a running machine are not recommended. */
397
int
398
init_module(void)
399
{
400
        int this_dev, found = 0;
401
 
402
        for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
403
                struct device *dev = &dev_hp[this_dev];
404
                dev->name = namelist+(NAMELEN*this_dev);
405
                dev->irq = irq[this_dev];
406
                dev->base_addr = io[this_dev];
407
                dev->init = hp_probe;
408
                if (io[this_dev] == 0)  {
409
                        if (this_dev != 0) break; /* only autoprobe 1st one */
410
                        printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n");
411
                }
412
                if (register_netdev(dev) != 0) {
413
                        printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]);
414
                        if (found != 0) return 0; /* Got at least one. */
415
                        return -ENXIO;
416
                }
417
                found++;
418
        }
419
 
420
        return 0;
421
}
422
 
423
void
424
cleanup_module(void)
425
{
426
        int this_dev;
427
 
428
        for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
429
                struct device *dev = &dev_hp[this_dev];
430
                if (dev->priv != NULL) {
431
                        int ioaddr = dev->base_addr - NIC_OFFSET;
432
                        kfree(dev->priv);
433
                        dev->priv = NULL;
434
                        free_irq(dev->irq, NULL);
435
                        irq2dev_map[dev->irq] = NULL;
436
                        release_region(ioaddr, HP_IO_EXTENT);
437
                        unregister_netdev(dev);
438
                }
439
        }
440
}
441
#endif /* MODULE */
442
 
443
/*
444
 * Local variables:
445
 * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c"
446
 * version-control: t
447
 * kept-new-versions: 5
448
 * tab-width: 4
449
 * c-indent-level: 4
450
 * End:
451
 */

powered by: WebSVN 2.1.0

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