xref: /plan9/sys/src/9/pc/etherwavelan.c (revision e06f534bbaa4097bc6f4764ef1dd2dc3338fbd40)
1 /* Pci/pcmcia code for wavelan.c */
2 
3 #include "u.h"
4 #include "../port/lib.h"
5 #include "mem.h"
6 #include "dat.h"
7 #include "fns.h"
8 #include "io.h"
9 #include "../port/error.h"
10 #include "../port/netif.h"
11 #include "etherif.h"
12 
13 #include "wavelan.h"
14 
15 static int
16 wavelanpcmciareset(Ether *ether)
17 {
18 	int i;
19 	char *p;
20 	Ctlr *ctlr;
21 
22 	if((ctlr = malloc(sizeof(Ctlr))) == nil)
23 		return -1;
24 
25 	ilock(ctlr);
26 	ctlr->ctlrno = ether->ctlrno;
27 
28 	if (ether->port==0)
29 		ether->port=WDfltIOB;
30 	ctlr->iob = ether->port;
31 
32 	if (ether->irq==0)
33 		ether->irq=WDfltIRQ;
34 
35 	if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){
36 	//	print("#l%d: port 0x%lx in use\n",
37 	//			ether->ctlrno, ether->port);
38 		goto abort1;
39 	}
40 
41 	/*
42 	 * If id= is specified, card must match.  Otherwise try generic.
43 	 */
44 	ctlr->slot = -1;
45 	for(i=0; i<ether->nopt; i++){
46 		if(cistrncmp(ether->opt[i], "id=", 3) == 0){
47 			if((ctlr->slot = pcmspecial(&ether->opt[i][3], ether)) < 0)
48 				goto abort;
49 			break;
50 		}
51 	}
52 	if(ctlr->slot == -1){
53 		for (i=0; wavenames[i]; i++)
54 			if((ctlr->slot = pcmspecial(wavenames[i], ether))>=0)
55 				break;
56 		if(!wavenames[i]){
57 			DEBUG("no wavelan found\n");
58 			goto abort;
59 		}
60 	}
61 
62 	// DEBUG("#l%d: port=0x%lx irq=%ld\n",
63 	//		ether->ctlrno, ether->port, ether->irq);
64 
65 	if(wavelanreset(ether, ctlr) < 0){
66 	abort:
67 		iofree(ether->port);
68 	abort1:
69 		iunlock(ctlr);
70 		free(ctlr);
71 		ether->ctlr = nil;
72 		return -1;
73 	}
74 
75 	for(i = 0; i < ether->nopt; i++){
76 		if(p = strchr(ether->opt[i], '='))
77 			*p = ' ';
78 		w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
79 	}
80 
81 	iunlock(ctlr);
82 	return 0;
83 }
84 
85 static struct {
86 	int vid;
87 	int did;
88 } wavelanpci[] = {
89 	0x1260, 0x3873,	/* Intersil Prism2.5 */
90 	0x1737,	0x0019,	/* Linksys WPC-11 untested */
91 };
92 
93 static Ctlr *ctlrhead, *ctlrtail;
94 
95 static void
96 wavelanpciscan(void)
97 {
98 	int i;
99 	void *mem;
100 	Pcidev *p;
101 	Ctlr *ctlr;
102 
103 	p = nil;
104 	while(p = pcimatch(p, 0, 0)){
105 		for(i=0; i<nelem(wavelanpci); i++)
106 			if(p->vid == wavelanpci[i].vid && p->did == wavelanpci[i].did)
107 				break;
108 		if(i==nelem(wavelanpci))
109 			continue;
110 
111 		/*
112 		 * On the Prism, bar[0] is the memory-mapped register address (4KB),
113 		 */
114 		if(p->mem[0].size != 4096){
115 			print("wavelanpci: %.4ux %.4ux: unlikely mmio size\n", p->vid, p->did);
116 			continue;
117 		}
118 
119 		ctlr = malloc(sizeof(Ctlr));
120 		ctlr->pcidev = p;
121 		mem = vmap(p->mem[0].bar&~0xF, p->mem[0].size);
122 		if(mem == nil){
123 			print("wavelanpci: %.4ux %.4ux: vmap 0x%.8lux %d failed\n", p->vid, p->did, p->mem[0].bar&~0xF, p->mem[0].size);
124 			free(ctlr);
125 			continue;
126 		}
127 		ctlr->mmb = mem;
128 		if(ctlrhead != nil)
129 			ctlrtail->next = ctlr;
130 		else
131 			ctlrhead = ctlr;
132 		ctlrtail = ctlr;
133 		pcisetbme(p);
134 	}
135 }
136 
137 static int
138 wavelanpcireset(Ether *ether)
139 {
140 	int i;
141 	char *p;
142 	Ctlr *ctlr;
143 
144 	if(ctlrhead == nil)
145 		wavelanpciscan();
146 
147 	/*
148 	 * Allow plan9.ini to set vid, did?
149 	 */
150 	for(ctlr=ctlrhead; ctlr!=nil; ctlr=ctlr->next)
151 		if(ctlr->active == 0)
152 			break;
153 	if(ctlr == nil)
154 		return -1;
155 
156 	ctlr->active = 1;
157 	ilock(ctlr);
158 	ether->irq = ctlr->pcidev->intl;
159 	ether->tbdf = ctlr->pcidev->tbdf;
160 
161 	/*
162 	 * Really hard reset.
163 	 */
164 	csr_outs(ctlr, WR_PciCor, 0x0080);
165 	delay(250);
166 	csr_outs(ctlr, WR_PciCor, 0x0000);
167 	delay(500);
168 	for(i=0; i<2*10; i++){
169 		if(!(csr_ins(ctlr, WR_Cmd)&WCmdBusy))
170 			break;
171 		delay(100);
172 	}
173 	if(i >= 2*10)
174 		print("wavelan pci %.4ux %.4ux: reset timeout %.4ux\n",
175 			ctlr->pcidev->vid, ctlr->pcidev->did, csr_ins(ctlr, WR_Cmd));
176 
177 	if(wavelanreset(ether, ctlr) < 0){
178 		iunlock(ctlr);
179 		ether->ctlr = nil;
180 		return -1;
181 	}
182 
183 	for(i = 0; i < ether->nopt; i++){
184 		if(p = strchr(ether->opt[i], '='))
185 			*p = ' ';
186 		w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
187 	}
188 	iunlock(ctlr);
189 	return 0;
190 }
191 
192 void
193 etherwavelanlink(void)
194 {
195 	addethercard("wavelan", wavelanpcmciareset);
196 	addethercard("wavelanpci", wavelanpcireset);
197 }
198