]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nusb/ether/url.c
nusb/ether: fix wrong size check causing odd sized packets to be discarded (thanks...
[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 static int urlread(Dev *, uchar *, int);
168 static void urlwrite(Dev *, uchar *, int);
169 int urlinit(Dev *);
170
171 static int
172 mem(Dev *d, int cmd, int off, uchar *buf, int len)
173 {
174         int r, rc;
175
176         if(d == nil)
177                 return 0;
178         r = Rvendor | Rdev;
179         if(cmd == Crm)
180                 r |= Rd2h;
181         else
182                 r |= Rh2d;
183         rc = usbcmd(d, r, Rqm, off, 0, buf, len);
184         if(rc < 0) {
185                 fprint(2, "%s: mem(%d, %#.4x) failed\n",
186                         argv0, cmd, off);
187         }
188         return rc;
189 }
190
191 static int
192 csr8r(Dev *d, int reg)
193 {
194         uchar v;
195
196         v = 0;
197         if(mem(d, Crm, reg, &v, sizeof v) < 0)
198                 return 0;
199         return v;
200 }
201
202 static int
203 csr16r(Dev *d, int reg)
204 {
205         uchar v[2];
206
207         PUT2(v, 0);
208         if(mem(d, Crm, reg, v, sizeof v) < 0)
209                 return 0;
210         return GET2(v);
211 }
212
213 static int
214 csr8w(Dev *d, int reg, int val)
215 {
216         uchar v;
217
218         v = val;
219         if(mem(d, Cwm, reg, &v, sizeof v) < 0)
220                 return -1;
221         return 0;
222 }
223
224 static int
225 csr16w(Dev *d, int reg, int val)
226 {
227         uchar v[2];
228
229         PUT2(v, val);
230         if(mem(d, Cwm, reg, v, sizeof v) < 0)
231                 return -1;
232         return 0;
233 }
234
235 static int
236 csr32w(Dev *d, int reg, int val)
237 {
238         uchar v[4];
239
240         PUT4(v, val);
241         if(mem(d, Cwm, reg, v, sizeof v) < 0)
242                 return -1;
243         return 0;
244 }
245
246 static void
247 reset(Dev *d)
248 {
249         int i, r;
250
251         r = csr8r(d, Cr) | Sr;
252         csr8w(d, Cr, r);
253
254         for(i = 0; i < Timeout; i++) {
255                 if((csr8r(d, Cr) & Sr) == 0)
256                         break;
257                 sleep(10);
258         }
259         if(i >= Timeout)
260                 fprint(2, "%s: reset failed\n", argv0);
261
262         sleep(100);
263 }
264
265 static int
266 urlread(Dev *ep, uchar *p, int plen)
267 {
268         int n;
269         uint hd;
270         uchar *q;
271
272         if(nbin < 4)
273                 nbin = read(ep->dfd, bin, sizeof bin);
274         if(nbin < 0)
275                 return -1;
276         if(nbin < 4)
277                 return 0;
278         n = nbin - 4;
279         if(n < 6) {
280                 nbin = 0;
281                 return 0;
282         }
283         q = bin + n;
284         hd = GET2(q);
285         if((hd & Vpm) == 0) {
286                 fprint(2, "url: rx error: %#.4ux\n", hd);
287                 n = 0;
288         } else {
289                 if(n > plen)
290                         n = plen;
291                 if(n > 0)
292                         memmove(p, bin, n);
293         }
294         nbin = 0;
295         return n;
296 }
297
298 static void
299 urlwrite(Dev *ep, uchar *p, int n)
300 {
301         if(n > sizeof bout)
302                 n = sizeof bout;
303         memmove(bout, p, n);
304         if(n < Mfl) {
305                 memset(bout+n, 0, Mfl-n);
306                 n = Mfl;
307         }
308         write(ep->dfd, bout, n);
309 }
310
311 int
312 urlinit(Dev *d)
313 {
314         int i, r;
315
316         reset(d);
317         if(mem(d, Crm, Idr0, macaddr, sizeof macaddr) < 0)
318                 return -1;
319
320         reset(d);
321         for(i = 0; i < sizeof macaddr; i++)
322                 csr8w(d, Idr0+i, macaddr[i]);
323
324         csr8w(d, Tcr, Tr1|Tr0|Ifg1|Ifg0);
325         csr16w(d, Rcr, Tail|Ad|Ab);
326
327         r = csr16r(d, Rcr) & ~(Am | Aam | Aap);
328         csr16w(d, Rcr, r);
329         csr32w(d, Mar0, 0);
330         csr32w(d, Mar4, 0);
331
332         csr8w(d, Cr, Te|Re);
333
334         epwrite = urlwrite;
335         epread = urlread;
336         return 0;
337 }