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 <sys/mman.h> 18 #include <assert.h> 19 20 #include "dp.h" 21 22 /* 23 ** Local data 24 */ 25 static dpeth_t de_state; 26 27 typedef struct dp_conf { /* Configuration description structure */ 28 port_t dpc_port; 29 int dpc_irq; 30 phys_bytes dpc_mem; 31 } dp_conf_t; 32 33 /* Device default configuration */ 34 #define DP_CONF_NR 3 35 static dp_conf_t dp_conf[DP_CONF_NR] = { 36 /* I/O port, IRQ, Buff addr, Env. var */ 37 { 0x300, 5, 0xC8000, }, 38 { 0x280, 10, 0xCC000, }, 39 { 0x000, 0, 0x00000, }, 40 }; 41 42 static int do_init(unsigned int instance, netdriver_addr_t *addr, 43 uint32_t *caps, unsigned int *ticks); 44 static void do_stop(void); 45 static void do_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list, 46 unsigned int mcast_count); 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_intr(unsigned int mask); 50 static void do_tick(void); 51 static void do_other(const message *m_ptr, int ipc_status); 52 53 static const struct netdriver dp_table = { 54 .ndr_name = "dpe", 55 .ndr_init = do_init, 56 .ndr_stop = do_stop, 57 .ndr_set_mode = do_set_mode, 58 .ndr_recv = do_recv, 59 .ndr_send = do_send, 60 .ndr_intr = do_intr, 61 .ndr_tick = do_tick, 62 .ndr_other = do_other 63 }; 64 65 /* 66 ** Name: update_conf 67 ** Function: Gets the default settings from 'dp_conf' table and 68 ** modifies them from the environment. 69 */ 70 static void update_conf(dpeth_t * dep, const dp_conf_t * dcp, 71 unsigned int instance) 72 { 73 static char dpc_fmt[] = "x:d:x"; 74 char ec_key[16]; 75 long val; 76 77 strlcpy(ec_key, "DPETH0", sizeof(ec_key)); 78 ec_key[5] += instance; 79 80 val = dcp->dpc_port; /* Get I/O port address */ 81 env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL); 82 dep->de_base_port = val; 83 84 val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */ 85 env_parse(ec_key, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1); 86 dep->de_irq = val; 87 88 val = dcp->dpc_mem; /* Get shared memory address */ 89 env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX); 90 dep->de_linmem = val; 91 } 92 93 /* 94 ** Name: do_dump 95 ** Function: Displays statistics on screen (SFx key from console) 96 */ 97 static void do_dump(void) 98 { 99 dpeth_t *dep; 100 101 dep = &de_state; 102 103 printf("\n\n"); 104 105 printf("%s statistics:\t\t", netdriver_name()); 106 107 /* Network interface status */ 108 printf("Status: 0x%04x\n\n", dep->de_flags); 109 110 (*dep->de_dumpstatsf)(dep); 111 112 /* Transmitted/received bytes */ 113 printf("Tx bytes:%10ld\t", dep->bytes_Tx); 114 printf("Rx bytes:%10ld\n", dep->bytes_Rx); 115 } 116 117 /* 118 ** Name: do_first_init 119 ** Function: Init action to setup task 120 */ 121 static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp) 122 { 123 124 dep->de_linmem = 0xFFFF0000; /* FIXME: this overrides update_conf, why? */ 125 126 /* Device specific initialization */ 127 (*dep->de_initf)(dep); 128 129 /* Map memory if requested */ 130 if (dep->de_linmem != 0) { 131 assert(dep->de_ramsize > 0); 132 dep->de_locmem = 133 vm_map_phys(SELF, (void *)dep->de_linmem, dep->de_ramsize); 134 if (dep->de_locmem == MAP_FAILED) 135 panic("unable to map memory"); 136 } 137 138 /* Set the interrupt handler policy. Request interrupts not to be reenabled 139 * automatically. Return the IRQ line number when an interrupt occurs. 140 */ 141 dep->de_hook = dep->de_irq; 142 if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK) 143 panic("unable to set IRQ policy"); 144 sys_irqenable(&dep->de_hook); 145 } 146 147 /* 148 ** Name: do_init 149 ** Function: Checks for hardware presence. 150 ** Initialize hardware and data structures. 151 ** Return status and ethernet address. 152 */ 153 static int do_init(unsigned int instance, netdriver_addr_t *addr, 154 uint32_t *caps, unsigned int *ticks) 155 { 156 dpeth_t *dep; 157 dp_conf_t *dcp; 158 int confnr, fkeys, sfkeys; 159 160 dep = &de_state; 161 162 /* Pick a default configuration for this instance. */ 163 confnr = MIN(instance, DP_CONF_NR-1); 164 165 dcp = &dp_conf[confnr]; 166 167 update_conf(dep, dcp, instance); 168 169 if (!el1_probe(dep) && /* Probe for 3c501 */ 170 !wdeth_probe(dep) && /* Probe for WD80x3 */ 171 !ne_probe(dep) && /* Probe for NEx000 */ 172 !el2_probe(dep) && /* Probe for 3c503 */ 173 !el3_probe(dep)) { /* Probe for 3c509 */ 174 printf("%s: warning no ethernet card found at 0x%04X\n", 175 netdriver_name(), dep->de_base_port); 176 return ENXIO; 177 } 178 179 do_first_init(dep, dcp); 180 181 /* Request function key for debug dumps */ 182 fkeys = sfkeys = 0; bit_set(sfkeys, 7); 183 if (fkey_map(&fkeys, &sfkeys) != OK) 184 printf("%s: couldn't bind Shift+F7 key (%d)\n", 185 netdriver_name(), errno); 186 187 memcpy(addr, dep->de_address.na_addr, sizeof(*addr)); 188 *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST; /* ..is this even accurate? */ 189 *ticks = sys_hz(); /* update statistics once a second */ 190 return OK; 191 } 192 193 /* 194 ** Name: de_set_mode 195 ** Function: Sets packet receipt mode. 196 */ 197 static void do_set_mode(unsigned int mode, 198 const netdriver_addr_t * mcast_list __unused, 199 unsigned int mcast_count __unused) 200 { 201 dpeth_t *dep; 202 203 dep = &de_state; 204 205 dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD); 206 if (mode & NDEV_MODE_PROMISC) 207 dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD; 208 if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL)) 209 dep->de_flags |= DEF_MULTI; 210 if (mode & NDEV_MODE_BCAST) 211 dep->de_flags |= DEF_BROAD; 212 (*dep->de_flagsf)(dep); 213 } 214 215 /* 216 ** Name: do_send 217 ** Function: Send a packet, if possible. 218 */ 219 static int do_send(struct netdriver_data *data, size_t size) 220 { 221 dpeth_t *dep; 222 223 dep = &de_state; 224 225 return (*dep->de_sendf)(dep, data, size); 226 } 227 228 /* 229 ** Name: do_recv 230 ** Function: Receive a packet, if possible. 231 */ 232 static ssize_t do_recv(struct netdriver_data *data, size_t max) 233 { 234 dpeth_t *dep; 235 236 dep = &de_state; 237 238 return (*dep->de_recvf)(dep, data, max); 239 } 240 241 /* 242 ** Name: do_stop 243 ** Function: Stops network interface. 244 */ 245 static void do_stop(void) 246 { 247 dpeth_t *dep; 248 249 dep = &de_state; 250 251 /* Stop device */ 252 (dep->de_stopf)(dep); 253 } 254 255 /* 256 ** Name: do_intr 257 ** Function; Handles interrupts. 258 */ 259 static void do_intr(unsigned int __unused mask) 260 { 261 dpeth_t *dep; 262 263 dep = &de_state; 264 265 /* If device is enabled and interrupt pending */ 266 (*dep->de_interruptf)(dep); 267 sys_irqenable(&dep->de_hook); 268 } 269 270 /* 271 ** Name: do_tick 272 ** Function: perform regular processing. 273 */ 274 static void do_tick(void) 275 { 276 dpeth_t *dep; 277 278 dep = &de_state; 279 280 if (dep->de_getstatsf != NULL) 281 (*dep->de_getstatsf)(dep); 282 } 283 284 /* 285 ** Name: do_other 286 ** Function: Processes miscellaneous messages. 287 */ 288 static void do_other(const message *m_ptr, int ipc_status) 289 { 290 291 if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) 292 do_dump(); 293 } 294 295 /* 296 ** Name: main 297 ** Function: Main entry for dp task 298 */ 299 int main(int argc, char **argv) 300 { 301 302 env_setargs(argc, argv); 303 304 netdriver_task(&dp_table); 305 306 return 0; 307 } 308