Import 1.3.15
[davej-history.git] / drivers / net / hp.c
blob68de711b2846b3bccd0e0e4a30c04cac4cfd0809
1 /* hp.c: A HP LAN ethernet driver for linux. */
2 /*
3 Written 1993-94 by Donald Becker.
5 Copyright 1993 United States Government as represented by the
6 Director, National Security Agency.
8 This software may be used and distributed according to the terms
9 of the GNU Public License, incorporated herein by reference.
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
15 This is a driver for the HP PC-LAN adaptors.
17 Sources:
18 The Crynwr packet driver.
21 static const char*version =
22 "hp.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
24 #include <linux/kernel.h>
25 #include <linux/sched.h>
26 #include <linux/errno.h>
27 #include <linux/ioport.h>
28 #include <asm/system.h>
29 #include <asm/io.h>
31 #include <linux/netdevice.h>
32 #include"8390.h"
34 externstruct device *init_etherdev(struct device *dev,int sizeof_private,
35 unsigned long*mem_startp);
37 /* A zero-terminated list of I/O addresses to be probed. */
38 static unsigned int hppclan_portlist[] =
39 {0x300,0x320,0x340,0x280,0x2C0,0x200,0x240,0};
41 #define HP_IO_EXTENT 32
43 #define HP_DATAPORT 0x0c/* "Remote DMA" data port. */
44 #define HP_ID 0x07
45 #define HP_CONFIGURE 0x08/* Configuration register. */
46 #define HP_RUN 0x01/* 1 == Run, 0 == reset. */
47 #define HP_IRQ 0x0E/* Mask for software-configured IRQ line. */
48 #define HP_DATAON 0x10/* Turn on dataport */
49 #define NIC_OFFSET 0x10/* Offset the 8390 registers. */
51 #define HP_START_PG 0x00/* First page of TX buffer */
52 #define HP_8BSTOP_PG 0x80/* Last page +1 of RX ring */
53 #define HP_16BSTOP_PG 0xFF/* Same, for 16 bit cards. */
55 inthp_probe(struct device *dev);
56 inthp_probe1(struct device *dev,int ioaddr);
58 static voidhp_reset_8390(struct device *dev);
59 static inthp_block_input(struct device *dev,int count,
60 char*buf,int ring_offset);
61 static voidhp_block_output(struct device *dev,int count,
62 const unsigned char*buf,const start_page);
63 static voidhp_init_card(struct device *dev);
65 /* The map from IRQ number to HP_CONFIGURE register setting. */
66 /* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */
67 static char irqmap[16] = {0,0,4,6,8,10,0,14,0,4,2,12,0,0,0,0};
70 /* Probe for an HP LAN adaptor.
71 Also initialize the card and fill in STATION_ADDR with the station
72 address. */
73 #ifdef HAVE_DEVLIST
74 struct netdev_entry netcard_drv =
75 {"hp", hp_probe1, HP_IO_EXTENT, hppclan_portlist};
76 #else
78 inthp_probe(struct device *dev)
80 int i;
81 int base_addr = dev ? dev->base_addr :0;
83 if(base_addr >0x1ff)/* Check a single specified location. */
84 returnhp_probe1(dev, base_addr);
85 else if(base_addr !=0)/* Don't probe at all. */
86 return ENXIO;
88 for(i =0; hppclan_portlist[i]; i++) {
89 int ioaddr = hppclan_portlist[i];
90 if(check_region(ioaddr, HP_IO_EXTENT))
91 continue;
92 if(hp_probe1(dev, ioaddr) ==0)
93 return0;
96 return ENODEV;
98 #endif
100 inthp_probe1(struct device *dev,int ioaddr)
102 int i, board_id, wordmode;
103 const char*name;
105 /* Check for the HP physical address, 08 00 09 xx xx xx. */
106 /* This really isn't good enough: we may pick up HP LANCE boards
107 also! Avoid the lance 0x5757 signature. */
108 if(inb(ioaddr) !=0x08
109 ||inb(ioaddr+1) !=0x00
110 ||inb(ioaddr+2) !=0x09
111 ||inb(ioaddr+14) ==0x57)
112 return ENODEV;
114 /* Set up the parameters based on the board ID.
115 If you have additional mappings, please mail them to me -djb. */
116 if((board_id =inb(ioaddr + HP_ID)) &0x80) {
117 name ="HP27247";
118 wordmode =1;
119 }else{
120 name ="HP27250";
121 wordmode =0;
124 if(dev == NULL)
125 dev =init_etherdev(0,sizeof(struct ei_device),0);
127 /* Grab the region so we can find another board if something fails. */
128 request_region(ioaddr, HP_IO_EXTENT,"hp");
130 printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
132 for(i =0; i < ETHER_ADDR_LEN; i++)
133 printk(" %2.2x", dev->dev_addr[i] =inb(ioaddr + i));
135 /* Snarf the interrupt now. Someday this could be moved to open(). */
136 if(dev->irq <2) {
137 int irq_16list[] = {11,10,5,3,4,7,9,0};
138 int irq_8list[] = {7,5,3,4,9,0};
139 int*irqp = wordmode ? irq_16list : irq_8list;
141 int irq = *irqp;
142 if(request_irq(irq, NULL,0,"bogus") != -EBUSY) {
143 autoirq_setup(0);
144 /* Twinkle the interrupt, and check if it's seen. */
145 outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
146 outb_p(0x00| HP_RUN, ioaddr + HP_CONFIGURE);
147 if(irq ==autoirq_report(0)/* It's a good IRQ line! */
148 &&request_irq(irq, &ei_interrupt,0,"hp") ==0) {
149 printk(" selecting IRQ %d.\n", irq);
150 dev->irq = *irqp;
151 break;
154 }while(*++irqp);
155 if(*irqp ==0) {
156 printk(" no free IRQ lines.\n");
157 return EBUSY;
159 }else{
160 if(dev->irq ==2)
161 dev->irq =9;
162 if(request_irq(dev->irq, ei_interrupt,0,"hp")) {
163 printk(" unable to get IRQ %d.\n", dev->irq);
164 return EBUSY;
168 if(ei_debug >1)
169 printk(version);
171 /* Set the base address to point to the NIC, not the "real" base! */
172 dev->base_addr = ioaddr + NIC_OFFSET;
174 ethdev_init(dev);
176 ei_status.name = name;
177 ei_status.word16 = wordmode;
178 ei_status.tx_start_page = HP_START_PG;
179 ei_status.rx_start_page = HP_START_PG + TX_PAGES;
180 ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG;
182 ei_status.reset_8390 = &hp_reset_8390;
183 ei_status.block_input = &hp_block_input;
184 ei_status.block_output = &hp_block_output;
185 hp_init_card(dev);
187 return0;
190 static void
191 hp_reset_8390(struct device *dev)
193 int hp_base = dev->base_addr - NIC_OFFSET;
194 int saved_config =inb_p(hp_base + HP_CONFIGURE);
196 if(ei_debug >1)printk("resetting the 8390 time=%ld...", jiffies);
197 outb_p(0x00, hp_base + HP_CONFIGURE);
198 ei_status.txing =0;
199 /* Pause just a few cycles for the hardware reset to take place. */
200 SLOW_DOWN_IO;
201 SLOW_DOWN_IO;
203 outb_p(saved_config, hp_base + HP_CONFIGURE);
204 SLOW_DOWN_IO; SLOW_DOWN_IO;
206 if((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) ==0)
207 printk("%s: hp_reset_8390() did not complete.\n", dev->name);
209 if(ei_debug >1)printk("8390 reset done (%ld).", jiffies);
210 return;
213 /* Block input and output, similar to the Crynwr packet driver. If you
214 porting to a new ethercard look at the packet driver source for hints.
215 The HP LAN doesn't use shared memory -- we put the packet
216 out through the "remote DMA" dataport. */
218 static int
219 hp_block_input(struct device *dev,int count,char*buf,int ring_offset)
221 int nic_base = dev->base_addr;
222 int saved_config =inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
223 int xfer_count = count;
225 outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
226 outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
227 outb_p(count &0xff, nic_base + EN0_RCNTLO);
228 outb_p(count >>8, nic_base + EN0_RCNTHI);
229 outb_p(ring_offset &0xff, nic_base + EN0_RSARLO);
230 outb_p(ring_offset >>8, nic_base + EN0_RSARHI);
231 outb_p(E8390_RREAD+E8390_START, nic_base);
232 if(ei_status.word16) {
233 insw(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
234 if(count &0x01)
235 buf[count-1] =inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
236 }else{
237 insb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
239 /* This is for the ALPHA version only, remove for later releases. */
240 if(ei_debug >0) {/* DMA termination address check... */
241 int high =inb_p(nic_base + EN0_RSARHI);
242 int low =inb_p(nic_base + EN0_RSARLO);
243 int addr = (high <<8) + low;
244 /* Check only the lower 8 bits so we can ignore ring wrap. */
245 if(((ring_offset + xfer_count) &0xff) != (addr &0xff))
246 printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
247 dev->name, ring_offset + xfer_count, addr);
249 outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
250 return ring_offset + count;
253 static void
254 hp_block_output(struct device *dev,int count,
255 const unsigned char*buf,const start_page)
257 int nic_base = dev->base_addr;
258 int saved_config =inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
260 outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
261 /* Round the count up for word writes. Do we need to do this?
262 What effect will an odd byte count have on the 8390?
263 I should check someday. */
264 if(ei_status.word16 && (count &0x01))
265 count++;
266 /* We should already be in page 0, but to be safe... */
267 outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
269 #ifdef ei8390_bug
270 /* Handle the read-before-write bug the same way as the
271 Crynwr packet driver -- the NatSemi method doesn't work. */
272 outb_p(0x42, nic_base + EN0_RCNTLO);
273 outb_p(0, nic_base + EN0_RCNTHI);
274 outb_p(0xff, nic_base + EN0_RSARLO);
275 outb_p(0x00, nic_base + EN0_RSARHI);
276 outb_p(E8390_RREAD+E8390_START, EN_CMD);
277 /* Make certain that the dummy read has occurred. */
278 inb_p(0x61);
279 inb_p(0x61);
280 #endif
282 outb_p(count &0xff, nic_base + EN0_RCNTLO);
283 outb_p(count >>8, nic_base + EN0_RCNTHI);
284 outb_p(0x00, nic_base + EN0_RSARLO);
285 outb_p(start_page, nic_base + EN0_RSARHI);
287 outb_p(E8390_RWRITE+E8390_START, nic_base);
288 if(ei_status.word16) {
289 /* Use the 'rep' sequence for 16 bit boards. */
290 outsw(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
291 }else{
292 outsb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
295 /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
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 if((start_page <<8) + count != addr)
303 printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
304 dev->name, (start_page <<8) + count, addr);
306 outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
307 return;
310 /* This function resets the ethercard if something screws up. */
311 static void
312 hp_init_card(struct device *dev)
314 int irq = dev->irq;
315 NS8390_init(dev,0);
316 outb_p(irqmap[irq&0x0f] | HP_RUN,
317 dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
318 return;
323 * Local variables:
324 * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c"
325 * version-control: t
326 * kept-new-versions: 5
327 * tab-width: 4
328 * c-indent-level: 4
329 * End:
close