Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | #include <linux/if_ether.h> #include <linux/types.h> #include <asm/io.h> struct net_local { #ifdef __KERNEL__ struct net_device_stats stats; #endif ushort saved_tx_size; unsigned char re_tx, /* Number of packet retransmissions. */ tx_unit_busy, addr_mode, /* Current Rx filter e.g. promiscuous, etc. */ pac_cnt_in_tx_buf; }; struct rx_header { ushort pad; /* The first read is always corrupted. */ ushort rx_count; ushort rx_status; /* Unknown bit assignments :-<. */ ushort cur_addr; /* Apparently the current buffer address(?) */ }; #define PAR_DATA 0 #define PAR_STATUS 1 #define PAR_CONTROL 2 #define Ctrl_LNibRead 0x08 /* LP_PSELECP */ #define Ctrl_HNibRead 0 #define Ctrl_LNibWrite 0x08 /* LP_PSELECP */ #define Ctrl_HNibWrite 0 #define Ctrl_SelData 0x04 /* LP_PINITP */ #define Ctrl_IRQEN 0x10 /* LP_PINTEN */ #define EOW 0xE0 #define EOC 0xE0 #define WrAddr 0x40 /* Set address of EPLC read, write register. */ #define RdAddr 0xC0 #define HNib 0x10 enum page0_regs { /* The first six registers hold the ethernet physical station address. */ PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5, TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */ TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */ ISR = 10, IMR = 11, /* Interrupt status and mask. */ CMR1 = 12, /* Command register 1. */ CMR2 = 13, /* Command register 2. */ MAR = 14, /* Memory address register. */ CMR2_h = 0x1d, }; enum eepage_regs { PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */ #define ISR_TxOK 0x01 #define ISR_RxOK 0x04 #define ISR_TxErr 0x02 #define ISRh_RxErr 0x11 /* ISR, high nibble */ #define CMR1h_RESET 0x04 /* Reset. */ #define CMR1h_RxENABLE 0x02 /* Rx unit enable. */ #define CMR1h_TxENABLE 0x01 /* Tx unit enable. */ #define CMR1h_TxRxOFF 0x00 #define CMR1_ReXmit 0x08 /* Trigger a retransmit. */ #define CMR1_Xmit 0x04 /* Trigger a transmit. */ #define CMR1_IRQ 0x02 /* Interrupt active. */ #define CMR1_BufEnb 0x01 /* Enable the buffer(?). */ #define CMR1_NextPkt 0x01 /* Enable the buffer(?). */ #define CMR2_NULL 8 #define CMR2_IRQOUT 9 #define CMR2_RAMTEST 10 #define CMR2_EEPROM 12 /* Set to page 1, for reading the EEPROM. */ #define CMR2h_OFF 0 /* No accept mode. */ #define CMR2h_Physical 1 /* Accept a physical address match only. */ #define CMR2h_Normal 2 /* Accept physical and broadcast address. */ #define CMR2h_PROMISC 3 /* Promiscuous mode. */ /* An inline function used below: it differs from inb() by explicitly return an unsigned char, saving a truncation. */ extern inline unsigned char inbyte(unsigned short port) { unsigned char _v; __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port)); return _v; } /* Read register OFFSET. This command should always be terminated with read_end(). */ extern inline unsigned char read_nibble(short port, unsigned char offset) { unsigned char retval; outb(EOC+offset, port + PAR_DATA); outb(RdAddr+offset, port + PAR_DATA); inbyte(port + PAR_STATUS); /* Settling time delay */ retval = inbyte(port + PAR_STATUS); outb(EOC+offset, port + PAR_DATA); return retval; } /* Functions for bulk data read. The interrupt line is always disabled. */ /* Get a byte using read mode 0, reading data from the control lines. */ extern inline unsigned char read_byte_mode0(short ioaddr) { unsigned char low_nib; outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); inbyte(ioaddr + PAR_STATUS); low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); } /* The same as read_byte_mode0(), but does multiple inb()s for stability. */ extern inline unsigned char read_byte_mode2(short ioaddr) { unsigned char low_nib; outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); inbyte(ioaddr + PAR_STATUS); low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); } /* Read a byte through the data register. */ extern inline unsigned char read_byte_mode4(short ioaddr) { unsigned char low_nib; outb(RdAddr | MAR, ioaddr + PAR_DATA); low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); } /* Read a byte through the data register, double reading to allow settling. */ extern inline unsigned char read_byte_mode6(short ioaddr) { unsigned char low_nib; outb(RdAddr | MAR, ioaddr + PAR_DATA); inbyte(ioaddr + PAR_STATUS); low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); inbyte(ioaddr + PAR_STATUS); return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); } extern inline void write_reg(short port, unsigned char reg, unsigned char value) { unsigned char outval; outb(EOC | reg, port + PAR_DATA); outval = WrAddr | reg; outb(outval, port + PAR_DATA); outb(outval, port + PAR_DATA); /* Double write for PS/2. */ outval &= 0xf0; outval |= value; outb(outval, port + PAR_DATA); outval &= 0x1f; outb(outval, port + PAR_DATA); outb(outval, port + PAR_DATA); outb(EOC | outval, port + PAR_DATA); } extern inline void write_reg_high(short port, unsigned char reg, unsigned char value) { unsigned char outval = EOC | HNib | reg; outb(outval, port + PAR_DATA); outval &= WrAddr | HNib | 0x0f; outb(outval, port + PAR_DATA); outb(outval, port + PAR_DATA); /* Double write for PS/2. */ outval = WrAddr | HNib | value; outb(outval, port + PAR_DATA); outval &= HNib | 0x0f; /* HNib | value */ outb(outval, port + PAR_DATA); outb(outval, port + PAR_DATA); outb(EOC | HNib | outval, port + PAR_DATA); } /* Write a byte out using nibble mode. The low nibble is written first. */ extern inline void write_reg_byte(short port, unsigned char reg, unsigned char value) { unsigned char outval; outb(EOC | reg, port + PAR_DATA); /* Reset the address register. */ outval = WrAddr | reg; outb(outval, port + PAR_DATA); outb(outval, port + PAR_DATA); /* Double write for PS/2. */ outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA); outb(value & 0x0f, port + PAR_DATA); value >>= 4; outb(value, port + PAR_DATA); outb(0x10 | value, port + PAR_DATA); outb(0x10 | value, port + PAR_DATA); outb(EOC | value, port + PAR_DATA); /* Reset the address register. */ } /* * Bulk data writes to the packet buffer. The interrupt line remains enabled. * The first, faster method uses only the dataport (data modes 0, 2 & 4). * The second (backup) method uses data and control regs (modes 1, 3 & 5). * It should only be needed when there is skew between the individual data * lines. */ extern inline void write_byte_mode0(short ioaddr, unsigned char value) { outb(value & 0x0f, ioaddr + PAR_DATA); outb((value>>4) | 0x10, ioaddr + PAR_DATA); } extern inline void write_byte_mode1(short ioaddr, unsigned char value) { outb(value & 0x0f, ioaddr + PAR_DATA); outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL); outb((value>>4) | 0x10, ioaddr + PAR_DATA); outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL); } /* Write 16bit VALUE to the packet buffer: the same as above just doubled. */ extern inline void write_word_mode0(short ioaddr, unsigned short value) { outb(value & 0x0f, ioaddr + PAR_DATA); value >>= 4; outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); value >>= 4; outb(value & 0x0f, ioaddr + PAR_DATA); value >>= 4; outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); } /* EEPROM_Ctrl bits. */ #define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ #define EE_CS 0x02 /* EEPROM chip select. */ #define EE_CLK_HIGH 0x12 #define EE_CLK_LOW 0x16 #define EE_DATA_WRITE 0x01 /* EEPROM chip data in. */ #define EE_DATA_READ 0x08 /* EEPROM chip data out. */ /* Delay between EEPROM clock transitions. */ #define eeprom_delay(ticks) \ do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD(offset) (((5 << 6) + (offset)) << 17) #define EE_READ(offset) (((6 << 6) + (offset)) << 17) #define EE_ERASE(offset) (((7 << 6) + (offset)) << 17) #define EE_CMD_SIZE 27 /* The command+address+data size. */ |