1 /* 2 ** File: dp.c Version 1.01, Oct. 17, 2007 3 ** Original: eth.c Version 1.00, Jan. 14, 1997 4 ** 5 ** Author: Giovanni Falzoni <gfalzoni@inwind.it> 6 ** 7 ** This file contains the ethernet device driver main task. 8 ** It has to be integrated with the board specific drivers. 9 ** It is a rewriting of Minix 2.0.0 ethernet driver (dp8390.c) 10 ** to remove bord specific code. It should operate (I hope) 11 ** with any board driver. 12 */ 13 14 #include <minix/drivers.h> 15 #include <minix/netdriver.h> 16 #include <minix/endpoint.h> 17 #include <net/gen/ether.h> 18 #include <net/gen/eth_io.h> 19 #include <sys/mman.h> 20 #include <assert.h> 21 22 #include "dp.h" 23 24 /* 25 ** Local data 26 */ 27 static dpeth_t de_state; 28 29 typedef struct dp_conf { /* Configuration description structure */ 30 port_t dpc_port; 31 int dpc_irq; 32 phys_bytes dpc_mem; 33 } dp_conf_t; 34 35 /* Device default configuration */ 36 #define DP_CONF_NR 3 37 static dp_conf_t dp_conf[DP_CONF_NR] = { 38 /* I/O port, IRQ, Buff addr, Env. var */ 39 { 0x300, 5, 0xC8000, }, 40 { 0x280, 10, 0xCC000, }, 41 { 0x000, 0, 0x00000, }, 42 }; 43 44 static int do_init(unsigned int instance, ether_addr_t *addr); 45 static void do_stop(void); 46 static void do_mode(unsigned int mode); 47 static int do_send(struct netdriver_data *data, size_t size); 48 static ssize_t do_recv(struct netdriver_data *data, size_t max); 49 static void do_stat(eth_stat_t *stat); 50 static void do_intr(unsigned int mask); 51 static void do_other(const message *m_ptr, int ipc_status); 52 53 static const struct netdriver dp_table = { 54 .ndr_init = do_init, 55 .ndr_stop = do_stop, 56 .ndr_mode = do_mode, 57 .ndr_recv = do_recv, 58 .ndr_send = do_send, 59 .ndr_stat = do_stat, 60 .ndr_intr = do_intr, 61 .ndr_other = do_other 62 }; 63 64 /* 65 ** Name: update_conf 66 ** Function: Gets the default settings from 'dp_conf' table and 67 ** modifies them from the environment. 68 */ 69 static void update_conf(dpeth_t * dep, const dp_conf_t * dcp, 70 unsigned int instance) 71 { 72 static char dpc_fmt[] = "x:d:x"; 73 char ec_key[16]; 74 long val; 75 76 strlcpy(ec_key, "DPETH0", sizeof(ec_key)); 77 ec_key[5] += instance; 78 79 val = dcp->dpc_port; /* Get I/O port address */ 80 env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL); 81 dep->de_base_port = val; 82 83 val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */ 84 env_parse(ec_key, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1); 85 dep->de_irq = val; 86 87 val = dcp->dpc_mem; /* Get shared memory address */ 88 env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX); 89 dep->de_linmem = val; 90 } 91 92 /* 93 ** Name: do_dump 94 ** Function: Displays statistics on screen (SFx key from console) 95 */ 96 static void do_dump(void) 97 { 98 dpeth_t *dep; 99 100 dep = &de_state; 101 102 printf("\n\n"); 103 104 printf("%s statistics:\t\t", dep->de_name); 105 106 /* Network interface status */ 107 printf("Status: 0x%04x\n\n", dep->de_flags); 108 109 (*dep->de_dumpstatsf)(dep); 110 111 /* Transmitted/received bytes */ 112 printf("Tx bytes:%10ld\t", dep->bytes_Tx); 113 printf("Rx bytes:%10ld\n", dep->bytes_Rx); 114 115 /* Transmitted/received packets */ 116 printf("Tx OK: %8ld\t", dep->de_stat.ets_packetT); 117 printf("Rx OK: %8ld\n", dep->de_stat.ets_packetR); 118 119 /* Transmit/receive errors */ 120 printf("Tx Err: %8ld\t", dep->de_stat.ets_sendErr); 121 printf("Rx Err: %8ld\n", dep->de_stat.ets_recvErr); 122 123 /* Transmit unnerruns/receive overrruns */ 124 printf("Tx Und: %8ld\t", dep->de_stat.ets_fifoUnder); 125 printf("Rx Ovr: %8ld\n", dep->de_stat.ets_fifoOver); 126 127 /* Transmit collisions/receive CRC errors */ 128 printf("Tx Coll: %8ld\t", dep->de_stat.ets_collision); 129 printf("Rx CRC: %8ld\n", dep->de_stat.ets_CRCerr); 130 } 131 132 /* 133 ** Name: do_first_init 134 ** Function: Init action to setup task 135 */ 136 static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp) 137 { 138 139 dep->de_linmem = 0xFFFF0000; /* FIXME: this overrides update_conf, why? */ 140 141 /* Make sure statisics are cleared */ 142 memset(&dep->de_stat, 0, sizeof(dep->de_stat)); 143 144 /* Device specific initialization */ 145 (*dep->de_initf)(dep); 146 147 /* Map memory if requested */ 148 if (dep->de_linmem != 0) { 149 assert(dep->de_ramsize > 0); 150 dep->de_locmem = 151 vm_map_phys(SELF, (void *)dep->de_linmem, dep->de_ramsize); 152 if (dep->de_locmem == MAP_FAILED) 153 panic("unable to map memory"); 154 } 155 156 /* Set the interrupt handler policy. Request interrupts not to be reenabled 157 * automatically. Return the IRQ line number when an interrupt occurs. 158 */ 159 dep->de_hook = dep->de_irq; 160 if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK) 161 panic("unable to set IRQ policy"); 162 sys_irqenable(&dep->de_hook); 163 } 164 165 /* 166 ** Name: do_init 167 ** Function: Checks for hardware presence. 168 ** Initialize hardware and data structures. 169 ** Return status and ethernet address. 170 */ 171 static int do_init(unsigned int instance, ether_addr_t *addr) 172 { 173 dpeth_t *dep; 174 dp_conf_t *dcp; 175 int confnr, fkeys, sfkeys; 176 177 dep = &de_state; 178 179 strlcpy(dep->de_name, "dpeth#?", sizeof(dep->de_name)); 180 dep->de_name[4] = '0' + instance; 181 182 /* Pick a default configuration for this instance. */ 183 confnr = MIN(instance, DP_CONF_NR-1); 184 185 dcp = &dp_conf[confnr]; 186 187 update_conf(dep, dcp, instance); 188 189 if (!el1_probe(dep) && /* Probe for 3c501 */ 190 !wdeth_probe(dep) && /* Probe for WD80x3 */ 191 !ne_probe(dep) && /* Probe for NEx000 */ 192 !el2_probe(dep) && /* Probe for 3c503 */ 193 !el3_probe(dep)) { /* Probe for 3c509 */ 194 printf("%s: warning no ethernet card found at 0x%04X\n", 195 dep->de_name, dep->de_base_port); 196 return ENXIO; 197 } 198 199 do_first_init(dep, dcp); 200 201 /* Request function key for debug dumps */ 202 fkeys = sfkeys = 0; bit_set(sfkeys, 7); 203 if (fkey_map(&fkeys, &sfkeys) != OK) 204 printf("%s: couldn't bind Shift+F7 key (%d)\n", dep->de_name, errno); 205 206 memcpy(addr, dep->de_address.ea_addr, sizeof(*addr)); 207 return OK; 208 } 209 210 /* 211 ** Name: de_mode 212 ** Function: Sets packet receipt mode. 213 */ 214 static void do_mode(unsigned int mode) 215 { 216 dpeth_t *dep; 217 218 dep = &de_state; 219 220 dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD); 221 if (mode & NDEV_PROMISC) 222 dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD; 223 if (mode & NDEV_MULTI) 224 dep->de_flags |= DEF_MULTI; 225 if (mode & NDEV_BROAD) 226 dep->de_flags |= DEF_BROAD; 227 (*dep->de_flagsf)(dep); 228 } 229 230 /* 231 ** Name: do_send 232 ** Function: Send a packet, if possible. 233 */ 234 static int do_send(struct netdriver_data *data, size_t size) 235 { 236 dpeth_t *dep; 237 238 dep = &de_state; 239 240 return (*dep->de_sendf)(dep, data, size); 241 } 242 243 /* 244 ** Name: do_recv 245 ** Function: Receive a packet, if possible. 246 */ 247 static ssize_t do_recv(struct netdriver_data *data, size_t max) 248 { 249 dpeth_t *dep; 250 251 dep = &de_state; 252 253 return (*dep->de_recvf)(dep, data, max); 254 } 255 256 /* 257 ** Name: do_stat 258 ** Function: Reports device statistics. 259 */ 260 static void do_stat(eth_stat_t *stat) 261 { 262 263 memcpy(stat, &de_state.de_stat, sizeof(*stat)); 264 } 265 266 /* 267 ** Name: do_stop 268 ** Function: Stops network interface. 269 */ 270 static void do_stop(void) 271 { 272 dpeth_t *dep; 273 274 dep = &de_state; 275 276 /* Stop device */ 277 (dep->de_stopf)(dep); 278 } 279 280 /* 281 ** Name: do_intr 282 ** Function; Handles interrupts. 283 */ 284 static void do_intr(unsigned int __unused mask) 285 { 286 dpeth_t *dep; 287 288 dep = &de_state; 289 290 /* If device is enabled and interrupt pending */ 291 (*dep->de_interruptf)(dep); 292 sys_irqenable(&dep->de_hook); 293 } 294 295 /* 296 ** Name: do_other 297 ** Function: Processes miscellaneous messages. 298 */ 299 static void do_other(const message *m_ptr, int ipc_status) 300 { 301 302 if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) 303 do_dump(); 304 } 305 306 /* 307 ** Name: main 308 ** Function: Main entry for dp task 309 */ 310 int main(int argc, char **argv) 311 { 312 313 env_setargs(argc, argv); 314 315 netdriver_task(&dp_table); 316 317 return 0; 318 } 319