]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nusb/ether/url.c
nusb/ether: mux bridges, bring in line with devether
[plan9front.git] / sys / src / cmd / nusb / ether / url.c
1 /*
2 * realtek rtl8150 10/100 usb ethernet device driver
3 *
4 * copy-pasted from shingo watanabe's openbsd url(4) driver
5 * and bill paul's and shunsuke akiyama's freebsd rue(4) driver
6 */
7 #include <u.h>
8 #include <libc.h>
9 #include <thread.h>
10
11 #include "usb.h"
12 #include "dat.h"
13
14 enum {
15         Timeout = 50,
16         Mfl = 60, /* min frame len */
17 };
18
19 enum { /* requests */
20         Rqm = 0x05, /* request mem */
21         Crm = 1, /* command read mem */
22         Cwm = 2, /* command write mem */
23 };
24
25 enum { /* registers */
26         Idr0 = 0x120, /* ether addr, load from 93c46 */
27         Idr1 = 0x121,
28         Idr2 = 0x122,
29         Idr3 = 0x123,
30         Idr4 = 0x124,
31         Idr5 = 0x125,
32
33         Mar0 = 0x126, /* multicast addr */
34         Mar1 = 0x127,
35         Mar2 = 0x128,
36         Mar3 = 0x129,
37         Mar4 = 0x12a,
38         Mar5 = 0x12b,
39         Mar6 = 0x12c,
40         Mar7 = 0x12d,
41
42         Cr = 0x12e, /* command */
43         Tcr = 0x12f, /* transmit control */
44         Rcr = 0x130, /* receive configuration */
45         Tsr = 0x132,
46         Rsr = 0x133,
47         Con0 = 0x135,
48         Con1 = 0x136,
49         Msr = 0x137, /* media status */
50         Phyar = 0x138, /* mii phy addr select */
51         Phydr = 0x139, /* mii phy data */
52         Phycr = 0x13b, /* mii phy control */
53         Gppc = 0x13d,
54         Wcr = 0x13e, /* wake count */
55         Bmcr = 0x140, /* basic mode control */
56         Bmsr = 0x142, /* basic mode status */
57         Anar = 0x144, /* an advertisement */
58         Anlp = 0x146, /* an link partner ability */
59         Aner = 0x148,
60         Nwtr = 0x14a, /* nway test */
61         Cscr = 0x14c,
62
63         Crc0 = 0x14e,
64         Crc1 = 0x150,
65         Crc2 = 0x152,
66         Crc3 = 0x154,
67         Crc4 = 0x156,
68
69         Bm0 = 0x158, /* byte mask */
70         Bm1 = 0x160,
71         Bm2 = 0x168,
72         Bm3 = 0x170,
73         Bm4 = 0x178,
74         
75         Phy1 = 0x180,
76         Phy2 = 0x184,
77         Tw1 = 0x186
78 };
79
80 enum { /* Cr */
81         We = 1 << 5, /* eeprom write enable */
82         Sr = 1 << 4, /* software reset */
83         Re = 1 << 3, /* ethernet receive enable */
84         Te = 1 << 2, /* ethernet transmit enable */
85         Ep3ce = 1 << 1, /* enable clr of perf counter */
86         Al = 1 << 0 /* auto-load contents of 93c46 */
87 };
88
89 enum { /* Tcr */
90         Tr1 = 1 << 7, /* tx retry count */
91         Tr0 = 1 << 6,
92         Ifg1 = 1 << 4, /* interframe gap time */
93         Ifg0 = 1 << 3,
94         Nocrc = 1 << 0 /* no crc appended */
95 };
96
97 enum { /* Rcr */
98         Tail = 1 << 7,
99         Aer = 1 << 6,
100         Ar = 1 << 5,
101         Am = 1 << 4,
102         Ab = 1 << 3,
103         Ad = 1 << 2,
104         Aam = 1 << 1,
105         Aap = 1 << 0
106 };
107
108 enum { /* Msr */
109         Tfce = 1 << 7,
110         Rfce = 1 << 6,
111         Mdx = 1 << 4, /* duplex */
112         S100 = 1 << 3, /* speed 100 */
113         Lnk = 1 << 2,
114         Tpf = 1 << 1,
115         Rpf = 1 << 0
116 };
117
118 enum { /* Phyar */
119         Phyamsk = 0x1f
120 };
121
122 enum { /* Phycr */
123         Phyown = 1 << 6, /* own bit */
124         Rwcr = 1 << 5, /* mii mgmt data r/w control */
125         Phyoffmsk = 0x1f /* phy register offset */
126 };
127
128 enum { /* Bmcr */
129         Spd = 0x2000, /* speed set */
130         Bdx = 0x0100 /* duplex */
131 };
132
133 enum { /* Anar */
134         Ap = 0x0400 /* pause */
135 };
136
137 enum { /* Anlp */
138         Lpp = 0x0400 /* pause */
139 };
140
141 enum { /* eeprom address declarations */
142         Ebase = 0x1200,
143         Eidr0 = Ebase + 0x02,
144         Eidr1 = Ebase + 0x03,
145         Eidr2 = Ebase + 0x03,
146         Eidr3 = Ebase + 0x03,
147         Eidr4 = Ebase + 0x03,
148         Eidr5 = Ebase + 0x03,
149         Eint = Ebase + 0x17 /* interval */
150 };
151
152 enum { /* receive header */
153         Bcm = 0x0fff, /* rx bytes count mask */
154         Vpm = 0x1000, /* valid packet mask */
155         Rpm = 0x2000, /* runt packet mask */
156         Ppm = 0x4000, /* physical match packet mask */
157         Mpm = 0x8000 /* multicast packet mask */
158 };
159
160 static int mem(Dev *, int, int, uchar *, int);
161 static int csr8r(Dev *, int);
162 static int csr16r(Dev *, int);
163 static int csr8w(Dev *, int, int);
164 static int csr16w(Dev *, int, int);
165 static int csr32w(Dev *, int, int);
166 static void reset(Dev *);
167 int urlinit(Dev *);
168
169 static int
170 mem(Dev *d, int cmd, int off, uchar *buf, int len)
171 {
172         int r, rc;
173
174         if(d == nil)
175                 return 0;
176         r = Rvendor | Rdev;
177         if(cmd == Crm)
178                 r |= Rd2h;
179         else
180                 r |= Rh2d;
181         rc = usbcmd(d, r, Rqm, off, 0, buf, len);
182         if(rc < 0) {
183                 fprint(2, "%s: mem(%d, %#.4x) failed\n",
184                         argv0, cmd, off);
185         }
186         return rc;
187 }
188
189 static int
190 csr8r(Dev *d, int reg)
191 {
192         uchar v;
193
194         v = 0;
195         if(mem(d, Crm, reg, &v, sizeof v) < 0)
196                 return 0;
197         return v;
198 }
199
200 static int
201 csr16r(Dev *d, int reg)
202 {
203         uchar v[2];
204
205         PUT2(v, 0);
206         if(mem(d, Crm, reg, v, sizeof v) < 0)
207                 return 0;
208         return GET2(v);
209 }
210
211 static int
212 csr8w(Dev *d, int reg, int val)
213 {
214         uchar v;
215
216         v = val;
217         if(mem(d, Cwm, reg, &v, sizeof v) < 0)
218                 return -1;
219         return 0;
220 }
221
222 static int
223 csr16w(Dev *d, int reg, int val)
224 {
225         uchar v[2];
226
227         PUT2(v, val);
228         if(mem(d, Cwm, reg, v, sizeof v) < 0)
229                 return -1;
230         return 0;
231 }
232
233 static int
234 csr32w(Dev *d, int reg, int val)
235 {
236         uchar v[4];
237
238         PUT4(v, val);
239         if(mem(d, Cwm, reg, v, sizeof v) < 0)
240                 return -1;
241         return 0;
242 }
243
244 static void
245 reset(Dev *d)
246 {
247         int i, r;
248
249         r = csr8r(d, Cr) | Sr;
250         csr8w(d, Cr, r);
251
252         for(i = 0; i < Timeout; i++) {
253                 if((csr8r(d, Cr) & Sr) == 0)
254                         break;
255                 sleep(10);
256         }
257         if(i >= Timeout)
258                 fprint(2, "%s: reset failed\n", argv0);
259
260         sleep(100);
261 }
262
263 static int
264 urlreceive(Dev *ep)
265 {
266         Block *b;
267         uint hd;
268         int n;
269
270         b = allocb(Maxpkt+4);
271         if((n = read(ep->dfd, b->wp, b->lim - b->base)) < 0){
272                 freeb(b);
273                 return -1;
274         }
275         if(n < 4){
276                 freeb(b);
277                 return 0;
278         }
279         n -= 4;
280         b->wp += n;
281         hd = GET2(b->wp);
282         if((hd & Vpm) == 0)
283                 freeb(b);
284         else
285                 etheriq(b);
286         return 0;
287 }
288
289 static void
290 urltransmit(Dev *ep, Block *b)
291 {
292         int n;
293
294         n = BLEN(b);
295         if(n < Mfl){
296                 memset(b->wp, 0, Mfl-n);
297                 b->wp += (Mfl-n);
298         }
299         write(ep->dfd, b->rp, BLEN(b));
300         freeb(b);
301 }
302
303 static int
304 urlpromiscuous(Dev *d, int on)
305 {
306         int r;
307
308         r = csr16r(d, Rcr);
309         if(on)
310                 r |= Aam|Aap;
311         else {
312                 r &= ~Aap;
313                 if(nmulti == 0)
314                         r &= ~Aam;
315         }
316         return csr16w(d, Rcr, r);
317 }
318
319 static int
320 urlmulticast(Dev *d, uchar*, int)
321 {
322         int r;
323
324         r = csr16r(d, Rcr);
325         if(nmulti)
326                 r |= Aam;
327         else {
328                 if(nprom == 0)
329                         r &= ~Aam;
330         }
331         return csr16w(d, Rcr, r);
332 }
333
334 int
335 urlinit(Dev *d)
336 {
337         int i, r;
338
339         reset(d);
340         if(mem(d, Crm, Idr0, macaddr, sizeof macaddr) < 0)
341                 return -1;
342
343         reset(d);
344         for(i = 0; i < sizeof macaddr; i++)
345                 csr8w(d, Idr0+i, macaddr[i]);
346
347         csr8w(d, Tcr, Tr1|Tr0|Ifg1|Ifg0);
348         csr16w(d, Rcr, Tail|Ad|Ab);
349
350         r = csr16r(d, Rcr) & ~(Am | Aam | Aap);
351         csr16w(d, Rcr, r);
352         csr32w(d, Mar0, 0);
353         csr32w(d, Mar4, 0);
354
355         csr8w(d, Cr, Te|Re);
356
357         epreceive = urlreceive;
358         eptransmit = urltransmit;
359         eppromiscuous = urlpromiscuous;
360         epmulticast = urlmulticast;
361
362         return 0;
363 }