xref: /minix3/minix/drivers/net/dpeth/dp.c (revision f7df02e7476731c31f12548e38bcadbaf0233f6a)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc **  File:	dp.c	Version 1.01,	Oct. 17, 2007
3433d6423SLionel Sambuc **  Original:	eth.c	Version 1.00,	Jan. 14, 1997
4433d6423SLionel Sambuc **
5433d6423SLionel Sambuc **  Author:	Giovanni Falzoni <gfalzoni@inwind.it>
6433d6423SLionel Sambuc **
7433d6423SLionel Sambuc **  This file contains the ethernet device driver main task.
8433d6423SLionel Sambuc **  It has to be integrated with the board specific drivers.
9433d6423SLionel Sambuc **  It is a rewriting of Minix 2.0.0 ethernet driver (dp8390.c)
10433d6423SLionel Sambuc **  to remove bord specific code. It should operate (I hope)
11433d6423SLionel Sambuc **  with any board driver.
12433d6423SLionel Sambuc */
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc #include <minix/drivers.h>
15433d6423SLionel Sambuc #include <minix/netdriver.h>
16433d6423SLionel Sambuc #include <minix/endpoint.h>
1791c4db25SDavid van Moolenbroek #include <sys/mman.h>
1891c4db25SDavid van Moolenbroek #include <assert.h>
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc #include "dp.h"
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc /*
23433d6423SLionel Sambuc **  Local data
24433d6423SLionel Sambuc */
25433d6423SLionel Sambuc static dpeth_t de_state;
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc typedef struct dp_conf {	/* Configuration description structure */
28433d6423SLionel Sambuc   port_t dpc_port;
29433d6423SLionel Sambuc   int dpc_irq;
30433d6423SLionel Sambuc   phys_bytes dpc_mem;
31433d6423SLionel Sambuc } dp_conf_t;
32433d6423SLionel Sambuc 
33433d6423SLionel Sambuc /* Device default configuration */
34433d6423SLionel Sambuc #define DP_CONF_NR 3
35433d6423SLionel Sambuc static dp_conf_t dp_conf[DP_CONF_NR] = {
36433d6423SLionel Sambuc   /* I/O port, IRQ, Buff addr, Env. var */
37433d6423SLionel Sambuc   {     0x300,   5,   0xC8000,  },
38433d6423SLionel Sambuc   {     0x280,  10,   0xCC000,  },
39433d6423SLionel Sambuc   {     0x000,   0,   0x00000,  },
40433d6423SLionel Sambuc };
41433d6423SLionel Sambuc 
42*f7df02e7SDavid van Moolenbroek static int do_init(unsigned int instance, netdriver_addr_t *addr,
43*f7df02e7SDavid van Moolenbroek 	uint32_t *caps, unsigned int *ticks);
4491c4db25SDavid van Moolenbroek static void do_stop(void);
45*f7df02e7SDavid van Moolenbroek static void do_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
46*f7df02e7SDavid van Moolenbroek 	unsigned int mcast_count);
4791c4db25SDavid van Moolenbroek static int do_send(struct netdriver_data *data, size_t size);
4891c4db25SDavid van Moolenbroek static ssize_t do_recv(struct netdriver_data *data, size_t max);
4991c4db25SDavid van Moolenbroek static void do_intr(unsigned int mask);
50*f7df02e7SDavid van Moolenbroek static void do_tick(void);
5191c4db25SDavid van Moolenbroek static void do_other(const message *m_ptr, int ipc_status);
5291c4db25SDavid van Moolenbroek 
5391c4db25SDavid van Moolenbroek static const struct netdriver dp_table = {
54*f7df02e7SDavid van Moolenbroek 	.ndr_name	= "dpe",
5591c4db25SDavid van Moolenbroek 	.ndr_init	= do_init,
5691c4db25SDavid van Moolenbroek 	.ndr_stop	= do_stop,
57*f7df02e7SDavid van Moolenbroek 	.ndr_set_mode	= do_set_mode,
5891c4db25SDavid van Moolenbroek 	.ndr_recv	= do_recv,
5991c4db25SDavid van Moolenbroek 	.ndr_send	= do_send,
6091c4db25SDavid van Moolenbroek 	.ndr_intr	= do_intr,
61*f7df02e7SDavid van Moolenbroek 	.ndr_tick	= do_tick,
6291c4db25SDavid van Moolenbroek 	.ndr_other	= do_other
6391c4db25SDavid van Moolenbroek };
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc /*
6691c4db25SDavid van Moolenbroek **  Name:	update_conf
67433d6423SLionel Sambuc **  Function:	Gets the default settings from 'dp_conf' table and
68433d6423SLionel Sambuc **  		modifies them from the environment.
69433d6423SLionel Sambuc */
update_conf(dpeth_t * dep,const dp_conf_t * dcp,unsigned int instance)7091c4db25SDavid van Moolenbroek static void update_conf(dpeth_t * dep, const dp_conf_t * dcp,
7191c4db25SDavid van Moolenbroek 	unsigned int instance)
72433d6423SLionel Sambuc {
73433d6423SLionel Sambuc   static char dpc_fmt[] = "x:d:x";
74433d6423SLionel Sambuc   char ec_key[16];
75433d6423SLionel Sambuc   long val;
76433d6423SLionel Sambuc 
77433d6423SLionel Sambuc   strlcpy(ec_key, "DPETH0", sizeof(ec_key));
7891c4db25SDavid van Moolenbroek   ec_key[5] += instance;
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc   val = dcp->dpc_port;		/* Get I/O port address */
8191c4db25SDavid van Moolenbroek   env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL);
82433d6423SLionel Sambuc   dep->de_base_port = val;
83433d6423SLionel Sambuc 
84433d6423SLionel Sambuc   val = dcp->dpc_irq | DEI_DEFAULT;	/* Get Interrupt line (IRQ) */
85433d6423SLionel Sambuc   env_parse(ec_key, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1);
86433d6423SLionel Sambuc   dep->de_irq = val;
87433d6423SLionel Sambuc 
88433d6423SLionel Sambuc   val = dcp->dpc_mem;		/* Get shared memory address */
89433d6423SLionel Sambuc   env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX);
90433d6423SLionel Sambuc   dep->de_linmem = val;
91433d6423SLionel Sambuc }
92433d6423SLionel Sambuc 
93433d6423SLionel Sambuc /*
9491c4db25SDavid van Moolenbroek **  Name:	do_dump
95433d6423SLionel Sambuc **  Function:	Displays statistics on screen (SFx key from console)
96433d6423SLionel Sambuc */
do_dump(void)9791c4db25SDavid van Moolenbroek static void do_dump(void)
98433d6423SLionel Sambuc {
99433d6423SLionel Sambuc   dpeth_t *dep;
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc   dep = &de_state;
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc   printf("\n\n");
104433d6423SLionel Sambuc 
105*f7df02e7SDavid van Moolenbroek   printf("%s statistics:\t\t", netdriver_name());
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc   /* Network interface status  */
10891c4db25SDavid van Moolenbroek   printf("Status: 0x%04x\n\n", dep->de_flags);
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc   (*dep->de_dumpstatsf)(dep);
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc   /* Transmitted/received bytes */
113433d6423SLionel Sambuc   printf("Tx bytes:%10ld\t", dep->bytes_Tx);
114433d6423SLionel Sambuc   printf("Rx bytes:%10ld\n", dep->bytes_Rx);
115433d6423SLionel Sambuc }
116433d6423SLionel Sambuc 
117433d6423SLionel Sambuc /*
11891c4db25SDavid van Moolenbroek **  Name:	do_first_init
119433d6423SLionel Sambuc **  Function:	Init action to setup task
120433d6423SLionel Sambuc */
do_first_init(dpeth_t * dep,const dp_conf_t * dcp)121433d6423SLionel Sambuc static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp)
122433d6423SLionel Sambuc {
123433d6423SLionel Sambuc 
12491c4db25SDavid van Moolenbroek   dep->de_linmem = 0xFFFF0000; /* FIXME: this overrides update_conf, why? */
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc   /* Device specific initialization */
127433d6423SLionel Sambuc   (*dep->de_initf)(dep);
128433d6423SLionel Sambuc 
12991c4db25SDavid van Moolenbroek   /* Map memory if requested */
13091c4db25SDavid van Moolenbroek   if (dep->de_linmem != 0) {
13191c4db25SDavid van Moolenbroek 	assert(dep->de_ramsize > 0);
13291c4db25SDavid van Moolenbroek 	dep->de_locmem =
13391c4db25SDavid van Moolenbroek 	    vm_map_phys(SELF, (void *)dep->de_linmem, dep->de_ramsize);
13491c4db25SDavid van Moolenbroek 	if (dep->de_locmem == MAP_FAILED)
13591c4db25SDavid van Moolenbroek 		panic("unable to map memory");
13691c4db25SDavid van Moolenbroek   }
13791c4db25SDavid van Moolenbroek 
138433d6423SLionel Sambuc   /* Set the interrupt handler policy. Request interrupts not to be reenabled
139433d6423SLionel Sambuc    * automatically. Return the IRQ line number when an interrupt occurs.
140433d6423SLionel Sambuc    */
141433d6423SLionel Sambuc   dep->de_hook = dep->de_irq;
142433d6423SLionel Sambuc   if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK)
143433d6423SLionel Sambuc 	panic("unable to set IRQ policy");
144433d6423SLionel Sambuc   sys_irqenable(&dep->de_hook);
145433d6423SLionel Sambuc }
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc /*
14891c4db25SDavid van Moolenbroek **  Name:	do_init
149433d6423SLionel Sambuc **  Function:	Checks for hardware presence.
15091c4db25SDavid van Moolenbroek **  		Initialize hardware and data structures.
15191c4db25SDavid van Moolenbroek **		Return status and ethernet address.
152433d6423SLionel Sambuc */
do_init(unsigned int instance,netdriver_addr_t * addr,uint32_t * caps,unsigned int * ticks)153*f7df02e7SDavid van Moolenbroek static int do_init(unsigned int instance, netdriver_addr_t *addr,
154*f7df02e7SDavid van Moolenbroek 	uint32_t *caps, unsigned int *ticks)
155433d6423SLionel Sambuc {
156433d6423SLionel Sambuc   dpeth_t *dep;
157433d6423SLionel Sambuc   dp_conf_t *dcp;
15891c4db25SDavid van Moolenbroek   int confnr, fkeys, sfkeys;
159433d6423SLionel Sambuc 
160433d6423SLionel Sambuc   dep = &de_state;
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc   /* Pick a default configuration for this instance. */
16391c4db25SDavid van Moolenbroek   confnr = MIN(instance, DP_CONF_NR-1);
164433d6423SLionel Sambuc 
165433d6423SLionel Sambuc   dcp = &dp_conf[confnr];
166433d6423SLionel Sambuc 
16791c4db25SDavid van Moolenbroek   update_conf(dep, dcp, instance);
168433d6423SLionel Sambuc 
16991c4db25SDavid van Moolenbroek   if (!el1_probe(dep) &&	/* Probe for 3c501  */
170433d6423SLionel Sambuc     !wdeth_probe(dep) &&	/* Probe for WD80x3 */
171433d6423SLionel Sambuc     !ne_probe(dep) &&		/* Probe for NEx000 */
172433d6423SLionel Sambuc     !el2_probe(dep) &&		/* Probe for 3c503  */
173433d6423SLionel Sambuc     !el3_probe(dep)) {		/* Probe for 3c509  */
174433d6423SLionel Sambuc 	printf("%s: warning no ethernet card found at 0x%04X\n",
175*f7df02e7SDavid van Moolenbroek 	       netdriver_name(), dep->de_base_port);
17691c4db25SDavid van Moolenbroek 	return ENXIO;
177433d6423SLionel Sambuc   }
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc   do_first_init(dep, dcp);
18091c4db25SDavid van Moolenbroek 
18191c4db25SDavid van Moolenbroek   /* Request function key for debug dumps */
18291c4db25SDavid van Moolenbroek   fkeys = sfkeys = 0; bit_set(sfkeys, 7);
18391c4db25SDavid van Moolenbroek   if (fkey_map(&fkeys, &sfkeys) != OK)
184*f7df02e7SDavid van Moolenbroek 	printf("%s: couldn't bind Shift+F7 key (%d)\n",
185*f7df02e7SDavid van Moolenbroek 	    netdriver_name(), errno);
18691c4db25SDavid van Moolenbroek 
187*f7df02e7SDavid van Moolenbroek   memcpy(addr, dep->de_address.na_addr, sizeof(*addr));
188*f7df02e7SDavid van Moolenbroek   *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST; /* ..is this even accurate? */
189*f7df02e7SDavid van Moolenbroek   *ticks = sys_hz(); /* update statistics once a second */
19091c4db25SDavid van Moolenbroek   return OK;
191433d6423SLionel Sambuc }
19291c4db25SDavid van Moolenbroek 
19391c4db25SDavid van Moolenbroek /*
194*f7df02e7SDavid van Moolenbroek **  Name:	de_set_mode
19591c4db25SDavid van Moolenbroek **  Function:	Sets packet receipt mode.
19691c4db25SDavid van Moolenbroek */
do_set_mode(unsigned int mode,const netdriver_addr_t * mcast_list __unused,unsigned int mcast_count __unused)197*f7df02e7SDavid van Moolenbroek static void do_set_mode(unsigned int mode,
198*f7df02e7SDavid van Moolenbroek 	const netdriver_addr_t * mcast_list __unused,
199*f7df02e7SDavid van Moolenbroek 	unsigned int mcast_count __unused)
20091c4db25SDavid van Moolenbroek {
20191c4db25SDavid van Moolenbroek   dpeth_t *dep;
20291c4db25SDavid van Moolenbroek 
20391c4db25SDavid van Moolenbroek   dep = &de_state;
20491c4db25SDavid van Moolenbroek 
205433d6423SLionel Sambuc   dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
206*f7df02e7SDavid van Moolenbroek   if (mode & NDEV_MODE_PROMISC)
207433d6423SLionel Sambuc 	dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
208*f7df02e7SDavid van Moolenbroek   if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
209433d6423SLionel Sambuc 	dep->de_flags |= DEF_MULTI;
210*f7df02e7SDavid van Moolenbroek   if (mode & NDEV_MODE_BCAST)
211433d6423SLionel Sambuc 	dep->de_flags |= DEF_BROAD;
212433d6423SLionel Sambuc   (*dep->de_flagsf)(dep);
213433d6423SLionel Sambuc }
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc /*
21691c4db25SDavid van Moolenbroek **  Name:	do_send
21791c4db25SDavid van Moolenbroek **  Function:	Send a packet, if possible.
218433d6423SLionel Sambuc */
do_send(struct netdriver_data * data,size_t size)21991c4db25SDavid van Moolenbroek static int do_send(struct netdriver_data *data, size_t size)
220433d6423SLionel Sambuc {
221433d6423SLionel Sambuc   dpeth_t *dep;
222433d6423SLionel Sambuc 
223433d6423SLionel Sambuc   dep = &de_state;
224433d6423SLionel Sambuc 
22591c4db25SDavid van Moolenbroek   return (*dep->de_sendf)(dep, data, size);
226433d6423SLionel Sambuc }
227433d6423SLionel Sambuc 
228433d6423SLionel Sambuc /*
22991c4db25SDavid van Moolenbroek **  Name:	do_recv
23091c4db25SDavid van Moolenbroek **  Function:	Receive a packet, if possible.
231433d6423SLionel Sambuc */
do_recv(struct netdriver_data * data,size_t max)23291c4db25SDavid van Moolenbroek static ssize_t do_recv(struct netdriver_data *data, size_t max)
233433d6423SLionel Sambuc {
234433d6423SLionel Sambuc   dpeth_t *dep;
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc   dep = &de_state;
237433d6423SLionel Sambuc 
23891c4db25SDavid van Moolenbroek   return (*dep->de_recvf)(dep, data, max);
239433d6423SLionel Sambuc }
240433d6423SLionel Sambuc 
241433d6423SLionel Sambuc /*
24291c4db25SDavid van Moolenbroek **  Name:	do_stop
243433d6423SLionel Sambuc **  Function:	Stops network interface.
244433d6423SLionel Sambuc */
do_stop(void)24591c4db25SDavid van Moolenbroek static void do_stop(void)
246433d6423SLionel Sambuc {
24791c4db25SDavid van Moolenbroek   dpeth_t *dep;
248433d6423SLionel Sambuc 
24991c4db25SDavid van Moolenbroek   dep = &de_state;
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc   /* Stop device */
252433d6423SLionel Sambuc   (dep->de_stopf)(dep);
253433d6423SLionel Sambuc }
254433d6423SLionel Sambuc 
25591c4db25SDavid van Moolenbroek /*
25691c4db25SDavid van Moolenbroek **  Name:	do_intr
25791c4db25SDavid van Moolenbroek **  Function;	Handles interrupts.
25891c4db25SDavid van Moolenbroek */
do_intr(unsigned int __unused mask)25991c4db25SDavid van Moolenbroek static void do_intr(unsigned int __unused mask)
260433d6423SLionel Sambuc {
261433d6423SLionel Sambuc 	dpeth_t *dep;
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc 	dep = &de_state;
264433d6423SLionel Sambuc 
265433d6423SLionel Sambuc 	/* If device is enabled and interrupt pending */
266433d6423SLionel Sambuc 	(*dep->de_interruptf)(dep);
267433d6423SLionel Sambuc 	sys_irqenable(&dep->de_hook);
268433d6423SLionel Sambuc }
269433d6423SLionel Sambuc 
270433d6423SLionel Sambuc /*
271*f7df02e7SDavid van Moolenbroek **  Name:	do_tick
272*f7df02e7SDavid van Moolenbroek **  Function:	perform regular processing.
273*f7df02e7SDavid van Moolenbroek */
do_tick(void)274*f7df02e7SDavid van Moolenbroek static void do_tick(void)
275*f7df02e7SDavid van Moolenbroek {
276*f7df02e7SDavid van Moolenbroek 	dpeth_t *dep;
277*f7df02e7SDavid van Moolenbroek 
278*f7df02e7SDavid van Moolenbroek 	dep = &de_state;
279*f7df02e7SDavid van Moolenbroek 
280*f7df02e7SDavid van Moolenbroek 	if (dep->de_getstatsf != NULL)
281*f7df02e7SDavid van Moolenbroek 		(*dep->de_getstatsf)(dep);
282*f7df02e7SDavid van Moolenbroek }
283*f7df02e7SDavid van Moolenbroek 
284*f7df02e7SDavid van Moolenbroek /*
28591c4db25SDavid van Moolenbroek **  Name:	do_other
28691c4db25SDavid van Moolenbroek **  Function:	Processes miscellaneous messages.
28791c4db25SDavid van Moolenbroek */
do_other(const message * m_ptr,int ipc_status)28891c4db25SDavid van Moolenbroek static void do_other(const message *m_ptr, int ipc_status)
28991c4db25SDavid van Moolenbroek {
29091c4db25SDavid van Moolenbroek 
29191c4db25SDavid van Moolenbroek   if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR)
29291c4db25SDavid van Moolenbroek 	do_dump();
29391c4db25SDavid van Moolenbroek }
29491c4db25SDavid van Moolenbroek 
29591c4db25SDavid van Moolenbroek /*
29691c4db25SDavid van Moolenbroek **  Name:	main
297433d6423SLionel Sambuc **  Function:	Main entry for dp task
298433d6423SLionel Sambuc */
main(int argc,char ** argv)299433d6423SLionel Sambuc int main(int argc, char **argv)
300433d6423SLionel Sambuc {
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc   env_setargs(argc, argv);
303433d6423SLionel Sambuc 
30491c4db25SDavid van Moolenbroek   netdriver_task(&dp_table);
30591c4db25SDavid van Moolenbroek 
30691c4db25SDavid van Moolenbroek   return 0;
307433d6423SLionel Sambuc }
308