usbnet drivers: Prune dead IFF_RUNNING branches in *_uno_init. usbnet(9) guarantees !IFF_RUNNING now before calling it.diff -r1.187 -r1.188 src/sys/dev/usb/if_aue.c
(riastradh)
--- src/sys/dev/usb/if_aue.c 2022/03/03 05:55:01 1.187
+++ src/sys/dev/usb/if_aue.c 2022/03/03 05:55:19 1.188
@@ -1,1000 +1,996 @@ | @@ -1,1000 +1,996 @@ | |||
1 | /* $NetBSD: if_aue.c,v 1.187 2022/03/03 05:55:01 riastradh Exp $ */ | 1 | /* $NetBSD: if_aue.c,v 1.188 2022/03/03 05:55:19 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1997, 1998, 1999, 2000 | 4 | * Copyright (c) 1997, 1998, 1999, 2000 | |
5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | 5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. All advertising materials mentioning features or use of this software | 15 | * 3. All advertising materials mentioning features or use of this software | |
16 | * must display the following acknowledgement: | 16 | * must display the following acknowledgement: | |
17 | * This product includes software developed by Bill Paul. | 17 | * This product includes software developed by Bill Paul. | |
18 | * 4. Neither the name of the author nor the names of any co-contributors | 18 | * 4. Neither the name of the author nor the names of any co-contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
32 | * THE POSSIBILITY OF SUCH DAMAGE. | 32 | * THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * $FreeBSD: src/sys/dev/usb/if_aue.c,v 1.11 2000/01/14 01:36:14 wpaul Exp $ | 34 | * $FreeBSD: src/sys/dev/usb/if_aue.c,v 1.11 2000/01/14 01:36:14 wpaul Exp $ | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | /* | 37 | /* | |
38 | * ADMtek AN986 Pegasus and AN8511 Pegasus II USB to ethernet driver. | 38 | * ADMtek AN986 Pegasus and AN8511 Pegasus II USB to ethernet driver. | |
39 | * Datasheet is available from http://www.admtek.com.tw. | 39 | * Datasheet is available from http://www.admtek.com.tw. | |
40 | * | 40 | * | |
41 | * Written by Bill Paul <wpaul@ee.columbia.edu> | 41 | * Written by Bill Paul <wpaul@ee.columbia.edu> | |
42 | * Electrical Engineering Department | 42 | * Electrical Engineering Department | |
43 | * Columbia University, New York City | 43 | * Columbia University, New York City | |
44 | */ | 44 | */ | |
45 | 45 | |||
46 | /* | 46 | /* | |
47 | * The Pegasus chip uses four USB "endpoints" to provide 10/100 ethernet | 47 | * The Pegasus chip uses four USB "endpoints" to provide 10/100 ethernet | |
48 | * support: the control endpoint for reading/writing registers, burst | 48 | * support: the control endpoint for reading/writing registers, burst | |
49 | * read endpoint for packet reception, burst write for packet transmission | 49 | * read endpoint for packet reception, burst write for packet transmission | |
50 | * and one for "interrupts." The chip uses the same RX filter scheme | 50 | * and one for "interrupts." The chip uses the same RX filter scheme | |
51 | * as the other ADMtek ethernet parts: one perfect filter entry for the | 51 | * as the other ADMtek ethernet parts: one perfect filter entry for the | |
52 | * the station address and a 64-bit multicast hash table. The chip supports | 52 | * the station address and a 64-bit multicast hash table. The chip supports | |
53 | * both MII and HomePNA attachments. | 53 | * both MII and HomePNA attachments. | |
54 | * | 54 | * | |
55 | * Since the maximum data transfer speed of USB is supposed to be 12Mbps, | 55 | * Since the maximum data transfer speed of USB is supposed to be 12Mbps, | |
56 | * you're never really going to get 100Mbps speeds from this device. I | 56 | * you're never really going to get 100Mbps speeds from this device. I | |
57 | * think the idea is to allow the device to connect to 10 or 100Mbps | 57 | * think the idea is to allow the device to connect to 10 or 100Mbps | |
58 | * networks, not necessarily to provide 100Mbps performance. Also, since | 58 | * networks, not necessarily to provide 100Mbps performance. Also, since | |
59 | * the controller uses an external PHY chip, it's possible that board | 59 | * the controller uses an external PHY chip, it's possible that board | |
60 | * designers might simply choose a 10Mbps PHY. | 60 | * designers might simply choose a 10Mbps PHY. | |
61 | * | 61 | * | |
62 | * Registers are accessed using usbd_do_request(). Packet transfers are | 62 | * Registers are accessed using usbd_do_request(). Packet transfers are | |
63 | * done using usbd_transfer() and friends. | 63 | * done using usbd_transfer() and friends. | |
64 | */ | 64 | */ | |
65 | 65 | |||
66 | /* | 66 | /* | |
67 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | 67 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | |
68 | */ | 68 | */ | |
69 | 69 | |||
70 | /* | 70 | /* | |
71 | * TODO: | 71 | * TODO: | |
72 | * better error messages from rxstat | 72 | * better error messages from rxstat | |
73 | * more error checks | 73 | * more error checks | |
74 | * investigate short rx problem | 74 | * investigate short rx problem | |
75 | * proper cleanup on errors | 75 | * proper cleanup on errors | |
76 | */ | 76 | */ | |
77 | 77 | |||
78 | #include <sys/cdefs.h> | 78 | #include <sys/cdefs.h> | |
79 | __KERNEL_RCSID(0, "$NetBSD: if_aue.c,v 1.187 2022/03/03 05:55:01 riastradh Exp $"); | 79 | __KERNEL_RCSID(0, "$NetBSD: if_aue.c,v 1.188 2022/03/03 05:55:19 riastradh Exp $"); | |
80 | 80 | |||
81 | #ifdef _KERNEL_OPT | 81 | #ifdef _KERNEL_OPT | |
82 | #include "opt_usb.h" | 82 | #include "opt_usb.h" | |
83 | #include "opt_inet.h" | 83 | #include "opt_inet.h" | |
84 | #endif | 84 | #endif | |
85 | 85 | |||
86 | #include <sys/param.h> | 86 | #include <sys/param.h> | |
87 | 87 | |||
88 | #include <dev/usb/usbnet.h> | 88 | #include <dev/usb/usbnet.h> | |
89 | #include <dev/usb/usbhist.h> | 89 | #include <dev/usb/usbhist.h> | |
90 | #include <dev/usb/if_auereg.h> | 90 | #include <dev/usb/if_auereg.h> | |
91 | 91 | |||
92 | #ifdef INET | 92 | #ifdef INET | |
93 | #include <netinet/in.h> | 93 | #include <netinet/in.h> | |
94 | #include <netinet/if_inarp.h> | 94 | #include <netinet/if_inarp.h> | |
95 | #endif | 95 | #endif | |
96 | 96 | |||
97 | #ifdef USB_DEBUG | 97 | #ifdef USB_DEBUG | |
98 | #ifndef AUE_DEBUG | 98 | #ifndef AUE_DEBUG | |
99 | #define auedebug 0 | 99 | #define auedebug 0 | |
100 | #else | 100 | #else | |
101 | static int auedebug = 10; | 101 | static int auedebug = 10; | |
102 | 102 | |||
103 | SYSCTL_SETUP(sysctl_hw_aue_setup, "sysctl hw.aue setup") | 103 | SYSCTL_SETUP(sysctl_hw_aue_setup, "sysctl hw.aue setup") | |
104 | { | 104 | { | |
105 | int err; | 105 | int err; | |
106 | const struct sysctlnode *rnode; | 106 | const struct sysctlnode *rnode; | |
107 | const struct sysctlnode *cnode; | 107 | const struct sysctlnode *cnode; | |
108 | 108 | |||
109 | err = sysctl_createv(clog, 0, NULL, &rnode, | 109 | err = sysctl_createv(clog, 0, NULL, &rnode, | |
110 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "aue", | 110 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "aue", | |
111 | SYSCTL_DESCR("aue global controls"), | 111 | SYSCTL_DESCR("aue global controls"), | |
112 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | 112 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | |
113 | 113 | |||
114 | if (err) | 114 | if (err) | |
115 | goto fail; | 115 | goto fail; | |
116 | 116 | |||
117 | /* control debugging printfs */ | 117 | /* control debugging printfs */ | |
118 | err = sysctl_createv(clog, 0, &rnode, &cnode, | 118 | err = sysctl_createv(clog, 0, &rnode, &cnode, | |
119 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | 119 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | |
120 | "debug", SYSCTL_DESCR("Enable debugging output"), | 120 | "debug", SYSCTL_DESCR("Enable debugging output"), | |
121 | NULL, 0, &auedebug, sizeof(auedebug), CTL_CREATE, CTL_EOL); | 121 | NULL, 0, &auedebug, sizeof(auedebug), CTL_CREATE, CTL_EOL); | |
122 | if (err) | 122 | if (err) | |
123 | goto fail; | 123 | goto fail; | |
124 | 124 | |||
125 | return; | 125 | return; | |
126 | fail: | 126 | fail: | |
127 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | 127 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | |
128 | } | 128 | } | |
129 | 129 | |||
130 | #endif /* AUE_DEBUG */ | 130 | #endif /* AUE_DEBUG */ | |
131 | #endif /* USB_DEBUG */ | 131 | #endif /* USB_DEBUG */ | |
132 | 132 | |||
133 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(auedebug,1,FMT,A,B,C,D) | 133 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(auedebug,1,FMT,A,B,C,D) | |
134 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(auedebug,N,FMT,A,B,C,D) | 134 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(auedebug,N,FMT,A,B,C,D) | |
135 | #define AUEHIST_FUNC() USBHIST_FUNC() | 135 | #define AUEHIST_FUNC() USBHIST_FUNC() | |
136 | #define AUEHIST_CALLED(name) USBHIST_CALLED(auedebug) | 136 | #define AUEHIST_CALLED(name) USBHIST_CALLED(auedebug) | |
137 | #define AUEHIST_CALLARGS(FMT,A,B,C,D) \ | 137 | #define AUEHIST_CALLARGS(FMT,A,B,C,D) \ | |
138 | USBHIST_CALLARGS(auedebug,FMT,A,B,C,D) | 138 | USBHIST_CALLARGS(auedebug,FMT,A,B,C,D) | |
139 | #define AUEHIST_CALLARGSN(N,FMT,A,B,C,D) \ | 139 | #define AUEHIST_CALLARGSN(N,FMT,A,B,C,D) \ | |
140 | USBHIST_CALLARGSN(auedebug,N,FMT,A,B,C,D) | 140 | USBHIST_CALLARGSN(auedebug,N,FMT,A,B,C,D) | |
141 | 141 | |||
142 | #define AUE_TX_LIST_CNT 1 | 142 | #define AUE_TX_LIST_CNT 1 | |
143 | #define AUE_RX_LIST_CNT 1 | 143 | #define AUE_RX_LIST_CNT 1 | |
144 | 144 | |||
145 | struct aue_softc { | 145 | struct aue_softc { | |
146 | struct usbnet aue_un; | 146 | struct usbnet aue_un; | |
147 | struct usbnet_intr aue_intr; | 147 | struct usbnet_intr aue_intr; | |
148 | struct aue_intrpkt aue_ibuf; | 148 | struct aue_intrpkt aue_ibuf; | |
149 | }; | 149 | }; | |
150 | 150 | |||
151 | #define AUE_TIMEOUT 1000 | 151 | #define AUE_TIMEOUT 1000 | |
152 | #define AUE_BUFSZ 1536 | 152 | #define AUE_BUFSZ 1536 | |
153 | #define AUE_MIN_FRAMELEN 60 | 153 | #define AUE_MIN_FRAMELEN 60 | |
154 | #define AUE_TX_TIMEOUT 10000 /* ms */ | 154 | #define AUE_TX_TIMEOUT 10000 /* ms */ | |
155 | #define AUE_INTR_INTERVAL 100 /* ms */ | 155 | #define AUE_INTR_INTERVAL 100 /* ms */ | |
156 | 156 | |||
157 | /* | 157 | /* | |
158 | * Various supported device vendors/products. | 158 | * Various supported device vendors/products. | |
159 | */ | 159 | */ | |
160 | struct aue_type { | 160 | struct aue_type { | |
161 | struct usb_devno aue_dev; | 161 | struct usb_devno aue_dev; | |
162 | uint16_t aue_flags; | 162 | uint16_t aue_flags; | |
163 | #define LSYS 0x0001 /* use Linksys reset */ | 163 | #define LSYS 0x0001 /* use Linksys reset */ | |
164 | #define PNA 0x0002 /* has Home PNA */ | 164 | #define PNA 0x0002 /* has Home PNA */ | |
165 | #define PII 0x0004 /* Pegasus II chip */ | 165 | #define PII 0x0004 /* Pegasus II chip */ | |
166 | }; | 166 | }; | |
167 | 167 | |||
168 | static const struct aue_type aue_devs[] = { | 168 | static const struct aue_type aue_devs[] = { | |
169 | {{ USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460B}, PII }, | 169 | {{ USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460B}, PII }, | |
170 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1}, PNA | PII }, | 170 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1}, PNA | PII }, | |
171 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2}, PII }, | 171 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2}, PII }, | |
172 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000}, LSYS }, | 172 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000}, LSYS }, | |
173 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4}, PNA }, | 173 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4}, PNA }, | |
174 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5}, PNA }, | 174 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5}, PNA }, | |
175 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6}, PII }, | 175 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6}, PII }, | |
176 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7}, PII }, | 176 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7}, PII }, | |
177 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8}, PII }, | 177 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8}, PII }, | |
178 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9}, PNA }, | 178 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9}, PNA }, | |
179 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10}, 0 }, | 179 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10}, 0 }, | |
180 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA}, 0 }, | 180 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA}, 0 }, | |
181 | {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC}, 0 }, | 181 | {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC}, 0 }, | |
182 | {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001}, PII }, | 182 | {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001}, PII }, | |
183 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS}, PNA }, | 183 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS}, PNA }, | |
184 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII}, PII }, | 184 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII}, PII }, | |
185 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_2}, PII }, | 185 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_2}, PII }, | |
186 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_3}, PII }, | 186 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_3}, PII }, | |
187 | {{ USB_VENDOR_AEI, USB_PRODUCT_AEI_USBTOLAN}, PII }, | 187 | {{ USB_VENDOR_AEI, USB_PRODUCT_AEI_USBTOLAN}, PII }, | |
188 | {{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2LAN}, PII }, | 188 | {{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2LAN}, PII }, | |
189 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100}, 0 }, | 189 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100}, 0 }, | |
190 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100}, PNA }, | 190 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100}, PNA }, | |
191 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100}, 0 }, | 191 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100}, 0 }, | |
192 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100}, PII }, | 192 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100}, PII }, | |
193 | {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_HNE200}, PII }, | 193 | {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_HNE200}, PII }, | |
194 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX}, 0 }, | 194 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX}, 0 }, | |
195 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS},PII }, | 195 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS},PII }, | |
196 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4}, LSYS | PII }, | 196 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4}, LSYS | PII }, | |
197 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1}, LSYS }, | 197 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1}, LSYS }, | |
198 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX}, LSYS }, | 198 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX}, LSYS }, | |
199 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA}, PNA }, | 199 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA}, PNA }, | |
200 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3}, LSYS | PII }, | 200 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3}, LSYS | PII }, | |
201 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2}, LSYS | PII }, | 201 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2}, LSYS | PII }, | |
202 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650}, 0 }, | 202 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650}, 0 }, | |
203 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0}, 0 }, | 203 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0}, 0 }, | |
204 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1}, LSYS }, | 204 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1}, LSYS }, | |
205 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2}, 0 }, | 205 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2}, 0 }, | |
206 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3}, LSYS }, | 206 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3}, LSYS }, | |
207 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX}, PII }, | 207 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX}, PII }, | |
208 | {{ USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET}, 0 }, | 208 | {{ USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET}, 0 }, | |
209 | {{ USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100}, PII }, | 209 | {{ USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100}, PII }, | |
210 | {{ USB_VENDOR_HP, USB_PRODUCT_HP_HN210E}, PII }, | 210 | {{ USB_VENDOR_HP, USB_PRODUCT_HP_HN210E}, PII }, | |
211 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX}, 0 }, | 211 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX}, 0 }, | |
212 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS}, PII }, | 212 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS}, PII }, | |
213 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETXUS2}, PII }, | 213 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETXUS2}, PII }, | |
214 | {{ USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX}, 0 }, | 214 | {{ USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX}, 0 }, | |
215 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1}, LSYS | PII }, | 215 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1}, LSYS | PII }, | |
216 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T}, LSYS }, | 216 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T}, LSYS }, | |
217 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX}, LSYS }, | 217 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX}, LSYS }, | |
218 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1}, LSYS | PNA }, | 218 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1}, LSYS | PNA }, | |
219 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA}, LSYS }, | 219 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA}, LSYS }, | |
220 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2}, LSYS | PII }, | 220 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2}, LSYS | PII }, | |
221 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1}, 0 }, | 221 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1}, 0 }, | |
222 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5}, 0 }, | 222 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5}, 0 }, | |
223 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5}, PII }, | 223 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5}, PII }, | |
224 | {{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110}, PII }, | 224 | {{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110}, PII }, | |
225 | {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA101}, PII }, | 225 | {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA101}, PII }, | |
226 | {{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM}, PII }, | 226 | {{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM}, PII }, | |
227 | {{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC},PII }, | 227 | {{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC},PII }, | |
228 | {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB}, 0 }, | 228 | {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB}, 0 }, | |
229 | {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB}, PII }, | 229 | {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB}, PII }, | |
230 | {{ USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100}, 0 }, | 230 | {{ USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100}, 0 }, | |
231 | }; | 231 | }; | |
232 | #define aue_lookup(v, p) ((const struct aue_type *)usb_lookup(aue_devs, v, p)) | 232 | #define aue_lookup(v, p) ((const struct aue_type *)usb_lookup(aue_devs, v, p)) | |
233 | 233 | |||
234 | static int aue_match(device_t, cfdata_t, void *); | 234 | static int aue_match(device_t, cfdata_t, void *); | |
235 | static void aue_attach(device_t, device_t, void *); | 235 | static void aue_attach(device_t, device_t, void *); | |
236 | 236 | |||
237 | CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach, | 237 | CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach, | |
238 | usbnet_detach, usbnet_activate); | 238 | usbnet_detach, usbnet_activate); | |
239 | 239 | |||
240 | static void aue_reset_pegasus_II(struct aue_softc *); | 240 | static void aue_reset_pegasus_II(struct aue_softc *); | |
241 | 241 | |||
242 | static void aue_uno_stop(struct ifnet *, int); | 242 | static void aue_uno_stop(struct ifnet *, int); | |
243 | static void aue_uno_mcast(struct ifnet *); | 243 | static void aue_uno_mcast(struct ifnet *); | |
244 | static int aue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 244 | static int aue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
245 | static int aue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 245 | static int aue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
246 | static void aue_uno_mii_statchg(struct ifnet *); | 246 | static void aue_uno_mii_statchg(struct ifnet *); | |
247 | static unsigned aue_uno_tx_prepare(struct usbnet *, struct mbuf *, | 247 | static unsigned aue_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
248 | struct usbnet_chain *); | 248 | struct usbnet_chain *); | |
249 | static void aue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 249 | static void aue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
250 | static int aue_uno_init(struct ifnet *); | 250 | static int aue_uno_init(struct ifnet *); | |
251 | static void aue_uno_intr(struct usbnet *, usbd_status); | 251 | static void aue_uno_intr(struct usbnet *, usbd_status); | |
252 | 252 | |||
253 | static const struct usbnet_ops aue_ops = { | 253 | static const struct usbnet_ops aue_ops = { | |
254 | .uno_stop = aue_uno_stop, | 254 | .uno_stop = aue_uno_stop, | |
255 | .uno_mcast = aue_uno_mcast, | 255 | .uno_mcast = aue_uno_mcast, | |
256 | .uno_read_reg = aue_uno_mii_read_reg, | 256 | .uno_read_reg = aue_uno_mii_read_reg, | |
257 | .uno_write_reg = aue_uno_mii_write_reg, | 257 | .uno_write_reg = aue_uno_mii_write_reg, | |
258 | .uno_statchg = aue_uno_mii_statchg, | 258 | .uno_statchg = aue_uno_mii_statchg, | |
259 | .uno_tx_prepare = aue_uno_tx_prepare, | 259 | .uno_tx_prepare = aue_uno_tx_prepare, | |
260 | .uno_rx_loop = aue_uno_rx_loop, | 260 | .uno_rx_loop = aue_uno_rx_loop, | |
261 | .uno_init = aue_uno_init, | 261 | .uno_init = aue_uno_init, | |
262 | .uno_intr = aue_uno_intr, | 262 | .uno_intr = aue_uno_intr, | |
263 | }; | 263 | }; | |
264 | 264 | |||
265 | static uint32_t aue_crc(void *); | 265 | static uint32_t aue_crc(void *); | |
266 | static void aue_reset(struct aue_softc *); | 266 | static void aue_reset(struct aue_softc *); | |
267 | 267 | |||
268 | static int aue_csr_read_1(struct aue_softc *, int); | 268 | static int aue_csr_read_1(struct aue_softc *, int); | |
269 | static int aue_csr_write_1(struct aue_softc *, int, int); | 269 | static int aue_csr_write_1(struct aue_softc *, int, int); | |
270 | static int aue_csr_read_2(struct aue_softc *, int); | 270 | static int aue_csr_read_2(struct aue_softc *, int); | |
271 | static int aue_csr_write_2(struct aue_softc *, int, int); | 271 | static int aue_csr_write_2(struct aue_softc *, int, int); | |
272 | 272 | |||
273 | #define AUE_SETBIT(sc, reg, x) \ | 273 | #define AUE_SETBIT(sc, reg, x) \ | |
274 | aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x)) | 274 | aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x)) | |
275 | 275 | |||
276 | #define AUE_CLRBIT(sc, reg, x) \ | 276 | #define AUE_CLRBIT(sc, reg, x) \ | |
277 | aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x)) | 277 | aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x)) | |
278 | 278 | |||
279 | static int | 279 | static int | |
280 | aue_csr_read_1(struct aue_softc *sc, int reg) | 280 | aue_csr_read_1(struct aue_softc *sc, int reg) | |
281 | { | 281 | { | |
282 | struct usbnet * const un = &sc->aue_un; | 282 | struct usbnet * const un = &sc->aue_un; | |
283 | usb_device_request_t req; | 283 | usb_device_request_t req; | |
284 | usbd_status err; | 284 | usbd_status err; | |
285 | uByte val = 0; | 285 | uByte val = 0; | |
286 | 286 | |||
287 | if (usbnet_isdying(un)) | 287 | if (usbnet_isdying(un)) | |
288 | return 0; | 288 | return 0; | |
289 | 289 | |||
290 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 290 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
291 | req.bRequest = AUE_UR_READREG; | 291 | req.bRequest = AUE_UR_READREG; | |
292 | USETW(req.wValue, 0); | 292 | USETW(req.wValue, 0); | |
293 | USETW(req.wIndex, reg); | 293 | USETW(req.wIndex, reg); | |
294 | USETW(req.wLength, 1); | 294 | USETW(req.wLength, 1); | |
295 | 295 | |||
296 | err = usbd_do_request(un->un_udev, &req, &val); | 296 | err = usbd_do_request(un->un_udev, &req, &val); | |
297 | 297 | |||
298 | if (err) { | 298 | if (err) { | |
299 | AUEHIST_FUNC(); | 299 | AUEHIST_FUNC(); | |
300 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 300 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
301 | device_unit(un->un_dev), reg, err, 0); | 301 | device_unit(un->un_dev), reg, err, 0); | |
302 | return 0; | 302 | return 0; | |
303 | } | 303 | } | |
304 | 304 | |||
305 | return val; | 305 | return val; | |
306 | } | 306 | } | |
307 | 307 | |||
308 | static int | 308 | static int | |
309 | aue_csr_read_2(struct aue_softc *sc, int reg) | 309 | aue_csr_read_2(struct aue_softc *sc, int reg) | |
310 | { | 310 | { | |
311 | struct usbnet * const un = &sc->aue_un; | 311 | struct usbnet * const un = &sc->aue_un; | |
312 | usb_device_request_t req; | 312 | usb_device_request_t req; | |
313 | usbd_status err; | 313 | usbd_status err; | |
314 | uWord val; | 314 | uWord val; | |
315 | 315 | |||
316 | if (usbnet_isdying(un)) | 316 | if (usbnet_isdying(un)) | |
317 | return 0; | 317 | return 0; | |
318 | 318 | |||
319 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 319 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
320 | req.bRequest = AUE_UR_READREG; | 320 | req.bRequest = AUE_UR_READREG; | |
321 | USETW(req.wValue, 0); | 321 | USETW(req.wValue, 0); | |
322 | USETW(req.wIndex, reg); | 322 | USETW(req.wIndex, reg); | |
323 | USETW(req.wLength, 2); | 323 | USETW(req.wLength, 2); | |
324 | 324 | |||
325 | err = usbd_do_request(un->un_udev, &req, &val); | 325 | err = usbd_do_request(un->un_udev, &req, &val); | |
326 | 326 | |||
327 | if (err) { | 327 | if (err) { | |
328 | AUEHIST_FUNC(); | 328 | AUEHIST_FUNC(); | |
329 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 329 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
330 | device_unit(un->un_dev), reg, err, 0); | 330 | device_unit(un->un_dev), reg, err, 0); | |
331 | return 0; | 331 | return 0; | |
332 | } | 332 | } | |
333 | 333 | |||
334 | return UGETW(val); | 334 | return UGETW(val); | |
335 | } | 335 | } | |
336 | 336 | |||
337 | static int | 337 | static int | |
338 | aue_csr_write_1(struct aue_softc *sc, int reg, int aval) | 338 | aue_csr_write_1(struct aue_softc *sc, int reg, int aval) | |
339 | { | 339 | { | |
340 | struct usbnet * const un = &sc->aue_un; | 340 | struct usbnet * const un = &sc->aue_un; | |
341 | usb_device_request_t req; | 341 | usb_device_request_t req; | |
342 | usbd_status err; | 342 | usbd_status err; | |
343 | uByte val; | 343 | uByte val; | |
344 | 344 | |||
345 | if (usbnet_isdying(un)) | 345 | if (usbnet_isdying(un)) | |
346 | return 0; | 346 | return 0; | |
347 | 347 | |||
348 | val = aval; | 348 | val = aval; | |
349 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 349 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
350 | req.bRequest = AUE_UR_WRITEREG; | 350 | req.bRequest = AUE_UR_WRITEREG; | |
351 | USETW(req.wValue, val); | 351 | USETW(req.wValue, val); | |
352 | USETW(req.wIndex, reg); | 352 | USETW(req.wIndex, reg); | |
353 | USETW(req.wLength, 1); | 353 | USETW(req.wLength, 1); | |
354 | 354 | |||
355 | err = usbd_do_request(un->un_udev, &req, &val); | 355 | err = usbd_do_request(un->un_udev, &req, &val); | |
356 | 356 | |||
357 | if (err) { | 357 | if (err) { | |
358 | AUEHIST_FUNC(); | 358 | AUEHIST_FUNC(); | |
359 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 359 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
360 | device_unit(un->un_dev), reg, err, 0); | 360 | device_unit(un->un_dev), reg, err, 0); | |
361 | return -1; | 361 | return -1; | |
362 | } | 362 | } | |
363 | 363 | |||
364 | return 0; | 364 | return 0; | |
365 | } | 365 | } | |
366 | 366 | |||
367 | static int | 367 | static int | |
368 | aue_csr_write_2(struct aue_softc *sc, int reg, int aval) | 368 | aue_csr_write_2(struct aue_softc *sc, int reg, int aval) | |
369 | { | 369 | { | |
370 | struct usbnet * const un = &sc->aue_un; | 370 | struct usbnet * const un = &sc->aue_un; | |
371 | usb_device_request_t req; | 371 | usb_device_request_t req; | |
372 | usbd_status err; | 372 | usbd_status err; | |
373 | uWord val; | 373 | uWord val; | |
374 | 374 | |||
375 | if (usbnet_isdying(un)) | 375 | if (usbnet_isdying(un)) | |
376 | return 0; | 376 | return 0; | |
377 | 377 | |||
378 | USETW(val, aval); | 378 | USETW(val, aval); | |
379 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 379 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
380 | req.bRequest = AUE_UR_WRITEREG; | 380 | req.bRequest = AUE_UR_WRITEREG; | |
381 | USETW(req.wValue, aval); | 381 | USETW(req.wValue, aval); | |
382 | USETW(req.wIndex, reg); | 382 | USETW(req.wIndex, reg); | |
383 | USETW(req.wLength, 2); | 383 | USETW(req.wLength, 2); | |
384 | 384 | |||
385 | err = usbd_do_request(un->un_udev, &req, &val); | 385 | err = usbd_do_request(un->un_udev, &req, &val); | |
386 | 386 | |||
387 | if (err) { | 387 | if (err) { | |
388 | AUEHIST_FUNC(); | 388 | AUEHIST_FUNC(); | |
389 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 389 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
390 | device_unit(un->un_dev), reg, err, 0); | 390 | device_unit(un->un_dev), reg, err, 0); | |
391 | return -1; | 391 | return -1; | |
392 | } | 392 | } | |
393 | 393 | |||
394 | return 0; | 394 | return 0; | |
395 | } | 395 | } | |
396 | 396 | |||
397 | /* | 397 | /* | |
398 | * Read a word of data stored in the EEPROM at address 'addr.' | 398 | * Read a word of data stored in the EEPROM at address 'addr.' | |
399 | */ | 399 | */ | |
400 | static int | 400 | static int | |
401 | aue_eeprom_getword(struct aue_softc *sc, int addr) | 401 | aue_eeprom_getword(struct aue_softc *sc, int addr) | |
402 | { | 402 | { | |
403 | struct usbnet * const un = &sc->aue_un; | 403 | struct usbnet * const un = &sc->aue_un; | |
404 | int i; | 404 | int i; | |
405 | 405 | |||
406 | AUEHIST_FUNC(); AUEHIST_CALLED(); | 406 | AUEHIST_FUNC(); AUEHIST_CALLED(); | |
407 | 407 | |||
408 | aue_csr_write_1(sc, AUE_EE_REG, addr); | 408 | aue_csr_write_1(sc, AUE_EE_REG, addr); | |
409 | aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ); | 409 | aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ); | |
410 | 410 | |||
411 | for (i = 0; i < AUE_TIMEOUT; i++) { | 411 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
412 | if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE) | 412 | if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE) | |
413 | break; | 413 | break; | |
414 | } | 414 | } | |
415 | 415 | |||
416 | if (i == AUE_TIMEOUT) { | 416 | if (i == AUE_TIMEOUT) { | |
417 | printf("%s: EEPROM read timed out\n", | 417 | printf("%s: EEPROM read timed out\n", | |
418 | device_xname(un->un_dev)); | 418 | device_xname(un->un_dev)); | |
419 | } | 419 | } | |
420 | 420 | |||
421 | return aue_csr_read_2(sc, AUE_EE_DATA); | 421 | return aue_csr_read_2(sc, AUE_EE_DATA); | |
422 | } | 422 | } | |
423 | 423 | |||
424 | /* | 424 | /* | |
425 | * Read the MAC from the EEPROM. It's at offset 0. | 425 | * Read the MAC from the EEPROM. It's at offset 0. | |
426 | */ | 426 | */ | |
427 | static void | 427 | static void | |
428 | aue_read_mac(struct usbnet *un) | 428 | aue_read_mac(struct usbnet *un) | |
429 | { | 429 | { | |
430 | struct aue_softc *sc = usbnet_softc(un); | 430 | struct aue_softc *sc = usbnet_softc(un); | |
431 | int i; | 431 | int i; | |
432 | int off = 0; | 432 | int off = 0; | |
433 | int word; | 433 | int word; | |
434 | 434 | |||
435 | AUEHIST_FUNC(); | 435 | AUEHIST_FUNC(); | |
436 | AUEHIST_CALLARGS("aue%jd: enter", | 436 | AUEHIST_CALLARGS("aue%jd: enter", | |
437 | device_unit(un->un_dev), 0, 0, 0); | 437 | device_unit(un->un_dev), 0, 0, 0); | |
438 | 438 | |||
439 | for (i = 0; i < 3; i++) { | 439 | for (i = 0; i < 3; i++) { | |
440 | word = aue_eeprom_getword(sc, off + i); | 440 | word = aue_eeprom_getword(sc, off + i); | |
441 | un->un_eaddr[2 * i] = (u_char)word; | 441 | un->un_eaddr[2 * i] = (u_char)word; | |
442 | un->un_eaddr[2 * i + 1] = (u_char)(word >> 8); | 442 | un->un_eaddr[2 * i + 1] = (u_char)(word >> 8); | |
443 | } | 443 | } | |
444 | } | 444 | } | |
445 | 445 | |||
446 | static int | 446 | static int | |
447 | aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 447 | aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
448 | { | 448 | { | |
449 | struct aue_softc *sc = usbnet_softc(un); | 449 | struct aue_softc *sc = usbnet_softc(un); | |
450 | int i; | 450 | int i; | |
451 | 451 | |||
452 | AUEHIST_FUNC(); | 452 | AUEHIST_FUNC(); | |
453 | 453 | |||
454 | #if 0 | 454 | #if 0 | |
455 | /* | 455 | /* | |
456 | * The Am79C901 HomePNA PHY actually contains | 456 | * The Am79C901 HomePNA PHY actually contains | |
457 | * two transceivers: a 1Mbps HomePNA PHY and a | 457 | * two transceivers: a 1Mbps HomePNA PHY and a | |
458 | * 10Mbps full/half duplex ethernet PHY with | 458 | * 10Mbps full/half duplex ethernet PHY with | |
459 | * NWAY autoneg. However in the ADMtek adapter, | 459 | * NWAY autoneg. However in the ADMtek adapter, | |
460 | * only the 1Mbps PHY is actually connected to | 460 | * only the 1Mbps PHY is actually connected to | |
461 | * anything, so we ignore the 10Mbps one. It | 461 | * anything, so we ignore the 10Mbps one. It | |
462 | * happens to be configured for MII address 3, | 462 | * happens to be configured for MII address 3, | |
463 | * so we filter that out. | 463 | * so we filter that out. | |
464 | */ | 464 | */ | |
465 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | 465 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | |
466 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | 466 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | |
467 | if (phy == 3) { | 467 | if (phy == 3) { | |
468 | *val = 0; | 468 | *val = 0; | |
469 | return EINVAL; | 469 | return EINVAL; | |
470 | } | 470 | } | |
471 | } | 471 | } | |
472 | #endif | 472 | #endif | |
473 | 473 | |||
474 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | 474 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | |
475 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ); | 475 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ); | |
476 | 476 | |||
477 | for (i = 0; i < AUE_TIMEOUT; i++) { | 477 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
478 | if (usbnet_isdying(un)) { | 478 | if (usbnet_isdying(un)) { | |
479 | *val = 0; | 479 | *val = 0; | |
480 | return ENXIO; | 480 | return ENXIO; | |
481 | } | 481 | } | |
482 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | 482 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | |
483 | break; | 483 | break; | |
484 | } | 484 | } | |
485 | 485 | |||
486 | if (i == AUE_TIMEOUT) { | 486 | if (i == AUE_TIMEOUT) { | |
487 | AUEHIST_CALLARGS("aue%jd: phy=%#jx reg=%#jx read timed out", | 487 | AUEHIST_CALLARGS("aue%jd: phy=%#jx reg=%#jx read timed out", | |
488 | device_unit(un->un_dev), phy, reg, 0); | 488 | device_unit(un->un_dev), phy, reg, 0); | |
489 | *val = 0; | 489 | *val = 0; | |
490 | return ETIMEDOUT; | 490 | return ETIMEDOUT; | |
491 | } | 491 | } | |
492 | 492 | |||
493 | *val = aue_csr_read_2(sc, AUE_PHY_DATA); | 493 | *val = aue_csr_read_2(sc, AUE_PHY_DATA); | |
494 | 494 | |||
495 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%#jx reg=%#jx => 0x%04jx", | 495 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%#jx reg=%#jx => 0x%04jx", | |
496 | device_unit(un->un_dev), phy, reg, *val); | 496 | device_unit(un->un_dev), phy, reg, *val); | |
497 | 497 | |||
498 | return 0; | 498 | return 0; | |
499 | } | 499 | } | |
500 | 500 | |||
501 | static int | 501 | static int | |
502 | aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 502 | aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
503 | { | 503 | { | |
504 | struct aue_softc *sc = usbnet_softc(un); | 504 | struct aue_softc *sc = usbnet_softc(un); | |
505 | int i; | 505 | int i; | |
506 | 506 | |||
507 | AUEHIST_FUNC(); | 507 | AUEHIST_FUNC(); | |
508 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%jd reg=%jd data=0x%04jx", | 508 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%jd reg=%jd data=0x%04jx", | |
509 | device_unit(un->un_dev), phy, reg, val); | 509 | device_unit(un->un_dev), phy, reg, val); | |
510 | 510 | |||
511 | #if 0 | 511 | #if 0 | |
512 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | 512 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | |
513 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | 513 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | |
514 | if (phy == 3) | 514 | if (phy == 3) | |
515 | return EINVAL; | 515 | return EINVAL; | |
516 | } | 516 | } | |
517 | #endif | 517 | #endif | |
518 | 518 | |||
519 | aue_csr_write_2(sc, AUE_PHY_DATA, val); | 519 | aue_csr_write_2(sc, AUE_PHY_DATA, val); | |
520 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | 520 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | |
521 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE); | 521 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE); | |
522 | 522 | |||
523 | for (i = 0; i < AUE_TIMEOUT; i++) { | 523 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
524 | if (usbnet_isdying(un)) | 524 | if (usbnet_isdying(un)) | |
525 | return ENXIO; | 525 | return ENXIO; | |
526 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | 526 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | |
527 | break; | 527 | break; | |
528 | } | 528 | } | |
529 | 529 | |||
530 | if (i == AUE_TIMEOUT) { | 530 | if (i == AUE_TIMEOUT) { | |
531 | DPRINTF("aue%jd: phy=%#jx reg=%#jx val=%#jx write timed out", | 531 | DPRINTF("aue%jd: phy=%#jx reg=%#jx val=%#jx write timed out", | |
532 | device_unit(un->un_dev), phy, reg, val); | 532 | device_unit(un->un_dev), phy, reg, val); | |
533 | return ETIMEDOUT; | 533 | return ETIMEDOUT; | |
534 | } | 534 | } | |
535 | 535 | |||
536 | return 0; | 536 | return 0; | |
537 | } | 537 | } | |
538 | 538 | |||
539 | static void | 539 | static void | |
540 | aue_uno_mii_statchg(struct ifnet *ifp) | 540 | aue_uno_mii_statchg(struct ifnet *ifp) | |
541 | { | 541 | { | |
542 | struct usbnet *un = ifp->if_softc; | 542 | struct usbnet *un = ifp->if_softc; | |
543 | struct aue_softc *sc = usbnet_softc(un); | 543 | struct aue_softc *sc = usbnet_softc(un); | |
544 | struct mii_data *mii = usbnet_mii(un); | 544 | struct mii_data *mii = usbnet_mii(un); | |
545 | const bool hadlink __diagused = usbnet_havelink(un); | 545 | const bool hadlink __diagused = usbnet_havelink(un); | |
546 | 546 | |||
547 | AUEHIST_FUNC(); AUEHIST_CALLED(); | 547 | AUEHIST_FUNC(); AUEHIST_CALLED(); | |
548 | AUEHIST_CALLARGSN(5, "aue%jd: ifp=%#jx link=%jd", | 548 | AUEHIST_CALLARGSN(5, "aue%jd: ifp=%#jx link=%jd", | |
549 | device_unit(un->un_dev), (uintptr_t)ifp, hadlink, 0); | 549 | device_unit(un->un_dev), (uintptr_t)ifp, hadlink, 0); | |
550 | 550 | |||
551 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | 551 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | |
552 | 552 | |||
553 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { | 553 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { | |
554 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | 554 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | |
555 | } else { | 555 | } else { | |
556 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | 556 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | |
557 | } | 557 | } | |
558 | 558 | |||
559 | if ((mii->mii_media_active & IFM_FDX) != 0) | 559 | if ((mii->mii_media_active & IFM_FDX) != 0) | |
560 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | 560 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | |
561 | else | 561 | else | |
562 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | 562 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | |
563 | 563 | |||
564 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | 564 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | |
565 | 565 | |||
566 | if (mii->mii_media_status & IFM_ACTIVE && | 566 | if (mii->mii_media_status & IFM_ACTIVE && | |
567 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | 567 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | |
568 | usbnet_set_link(un, true); | 568 | usbnet_set_link(un, true); | |
569 | } | 569 | } | |
570 | 570 | |||
571 | /* | 571 | /* | |
572 | * Set the LED modes on the LinkSys adapter. | 572 | * Set the LED modes on the LinkSys adapter. | |
573 | * This turns on the 'dual link LED' bin in the auxmode | 573 | * This turns on the 'dual link LED' bin in the auxmode | |
574 | * register of the Broadcom PHY. | 574 | * register of the Broadcom PHY. | |
575 | */ | 575 | */ | |
576 | if (!usbnet_isdying(un) && (un->un_flags & LSYS)) { | 576 | if (!usbnet_isdying(un) && (un->un_flags & LSYS)) { | |
577 | uint16_t auxmode; | 577 | uint16_t auxmode; | |
578 | aue_uno_mii_read_reg(un, 0, 0x1b, &auxmode); | 578 | aue_uno_mii_read_reg(un, 0, 0x1b, &auxmode); | |
579 | aue_uno_mii_write_reg(un, 0, 0x1b, auxmode | 0x04); | 579 | aue_uno_mii_write_reg(un, 0, 0x1b, auxmode | 0x04); | |
580 | } | 580 | } | |
581 | 581 | |||
582 | if (usbnet_havelink(un) != hadlink) { | 582 | if (usbnet_havelink(un) != hadlink) { | |
583 | DPRINTFN(5, "aue%jd: exit link %jd", | 583 | DPRINTFN(5, "aue%jd: exit link %jd", | |
584 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | 584 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | |
585 | } | 585 | } | |
586 | } | 586 | } | |
587 | 587 | |||
588 | #define AUE_POLY 0xEDB88320 | 588 | #define AUE_POLY 0xEDB88320 | |
589 | #define AUE_BITS 6 | 589 | #define AUE_BITS 6 | |
590 | 590 | |||
591 | static uint32_t | 591 | static uint32_t | |
592 | aue_crc(void *addrv) | 592 | aue_crc(void *addrv) | |
593 | { | 593 | { | |
594 | uint32_t idx, bit, data, crc; | 594 | uint32_t idx, bit, data, crc; | |
595 | char *addr = addrv; | 595 | char *addr = addrv; | |
596 | 596 | |||
597 | /* Compute CRC for the address value. */ | 597 | /* Compute CRC for the address value. */ | |
598 | crc = 0xFFFFFFFF; /* initial value */ | 598 | crc = 0xFFFFFFFF; /* initial value */ | |
599 | 599 | |||
600 | for (idx = 0; idx < 6; idx++) { | 600 | for (idx = 0; idx < 6; idx++) { | |
601 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | 601 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | |
602 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? AUE_POLY : 0); | 602 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? AUE_POLY : 0); | |
603 | } | 603 | } | |
604 | 604 | |||
605 | return crc & ((1 << AUE_BITS) - 1); | 605 | return crc & ((1 << AUE_BITS) - 1); | |
606 | } | 606 | } | |
607 | 607 | |||
608 | static void | 608 | static void | |
609 | aue_uno_mcast(struct ifnet *ifp) | 609 | aue_uno_mcast(struct ifnet *ifp) | |
610 | { | 610 | { | |
611 | struct usbnet * const un = ifp->if_softc; | 611 | struct usbnet * const un = ifp->if_softc; | |
612 | struct aue_softc * const sc = usbnet_softc(un); | 612 | struct aue_softc * const sc = usbnet_softc(un); | |
613 | struct ethercom * ec = usbnet_ec(un); | 613 | struct ethercom * ec = usbnet_ec(un); | |
614 | struct ether_multi *enm; | 614 | struct ether_multi *enm; | |
615 | struct ether_multistep step; | 615 | struct ether_multistep step; | |
616 | uint32_t h = 0, i; | 616 | uint32_t h = 0, i; | |
617 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 617 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
618 | 618 | |||
619 | AUEHIST_FUNC(); | 619 | AUEHIST_FUNC(); | |
620 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | 620 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | |
621 | 621 | |||
622 | if (ifp->if_flags & IFF_PROMISC) { | 622 | if (ifp->if_flags & IFF_PROMISC) { | |
623 | ETHER_LOCK(ec); | 623 | ETHER_LOCK(ec); | |
624 | allmulti: | 624 | allmulti: | |
625 | ec->ec_flags |= ETHER_F_ALLMULTI; | 625 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
626 | ETHER_UNLOCK(ec); | 626 | ETHER_UNLOCK(ec); | |
627 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | 627 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | |
628 | return; | 628 | return; | |
629 | } | 629 | } | |
630 | 630 | |||
631 | /* now program new ones */ | 631 | /* now program new ones */ | |
632 | ETHER_LOCK(ec); | 632 | ETHER_LOCK(ec); | |
633 | ETHER_FIRST_MULTI(step, ec, enm); | 633 | ETHER_FIRST_MULTI(step, ec, enm); | |
634 | while (enm != NULL) { | 634 | while (enm != NULL) { | |
635 | if (memcmp(enm->enm_addrlo, | 635 | if (memcmp(enm->enm_addrlo, | |
636 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | 636 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | |
637 | goto allmulti; | 637 | goto allmulti; | |
638 | } | 638 | } | |
639 | 639 | |||
640 | h = aue_crc(enm->enm_addrlo); | 640 | h = aue_crc(enm->enm_addrlo); | |
641 | hashtbl[h >> 3] |= 1 << (h & 0x7); | 641 | hashtbl[h >> 3] |= 1 << (h & 0x7); | |
642 | ETHER_NEXT_MULTI(step, enm); | 642 | ETHER_NEXT_MULTI(step, enm); | |
643 | } | 643 | } | |
644 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 644 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
645 | ETHER_UNLOCK(ec); | 645 | ETHER_UNLOCK(ec); | |
646 | 646 | |||
647 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | 647 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | |
648 | 648 | |||
649 | /* write the hashtable */ | 649 | /* write the hashtable */ | |
650 | for (i = 0; i < 8; i++) | 650 | for (i = 0; i < 8; i++) | |
651 | aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]); | 651 | aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]); | |
652 | } | 652 | } | |
653 | 653 | |||
654 | static void | 654 | static void | |
655 | aue_reset_pegasus_II(struct aue_softc *sc) | 655 | aue_reset_pegasus_II(struct aue_softc *sc) | |
656 | { | 656 | { | |
657 | /* Magic constants taken from Linux driver. */ | 657 | /* Magic constants taken from Linux driver. */ | |
658 | aue_csr_write_1(sc, AUE_REG_1D, 0); | 658 | aue_csr_write_1(sc, AUE_REG_1D, 0); | |
659 | aue_csr_write_1(sc, AUE_REG_7B, 2); | 659 | aue_csr_write_1(sc, AUE_REG_7B, 2); | |
660 | #if 0 | 660 | #if 0 | |
661 | if ((un->un_flags & PNA) && mii_mode) | 661 | if ((un->un_flags & PNA) && mii_mode) | |
662 | aue_csr_write_1(sc, AUE_REG_81, 6); | 662 | aue_csr_write_1(sc, AUE_REG_81, 6); | |
663 | else | 663 | else | |
664 | #endif | 664 | #endif | |
665 | aue_csr_write_1(sc, AUE_REG_81, 2); | 665 | aue_csr_write_1(sc, AUE_REG_81, 2); | |
666 | } | 666 | } | |
667 | 667 | |||
668 | static void | 668 | static void | |
669 | aue_reset(struct aue_softc *sc) | 669 | aue_reset(struct aue_softc *sc) | |
670 | { | 670 | { | |
671 | struct usbnet * const un = &sc->aue_un; | 671 | struct usbnet * const un = &sc->aue_un; | |
672 | int i; | 672 | int i; | |
673 | 673 | |||
674 | AUEHIST_FUNC(); | 674 | AUEHIST_FUNC(); | |
675 | AUEHIST_CALLARGSN(2, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | 675 | AUEHIST_CALLARGSN(2, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | |
676 | 676 | |||
677 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC); | 677 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC); | |
678 | 678 | |||
679 | for (i = 0; i < AUE_TIMEOUT; i++) { | 679 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
680 | if (usbnet_isdying(un)) | 680 | if (usbnet_isdying(un)) | |
681 | return; | 681 | return; | |
682 | if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) | 682 | if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) | |
683 | break; | 683 | break; | |
684 | } | 684 | } | |
685 | 685 | |||
686 | if (i == AUE_TIMEOUT) | 686 | if (i == AUE_TIMEOUT) | |
687 | printf("%s: reset failed\n", device_xname(un->un_dev)); | 687 | printf("%s: reset failed\n", device_xname(un->un_dev)); | |
688 | 688 | |||
689 | #if 0 | 689 | #if 0 | |
690 | /* XXX what is mii_mode supposed to be */ | 690 | /* XXX what is mii_mode supposed to be */ | |
691 | if (sc->sc_mii_mode && (un->un_flags & PNA)) | 691 | if (sc->sc_mii_mode && (un->un_flags & PNA)) | |
692 | aue_csr_write_1(sc, AUE_GPIO1, 0x34); | 692 | aue_csr_write_1(sc, AUE_GPIO1, 0x34); | |
693 | else | 693 | else | |
694 | aue_csr_write_1(sc, AUE_GPIO1, 0x26); | 694 | aue_csr_write_1(sc, AUE_GPIO1, 0x26); | |
695 | #endif | 695 | #endif | |
696 | 696 | |||
697 | /* | 697 | /* | |
698 | * The PHY(s) attached to the Pegasus chip may be held | 698 | * The PHY(s) attached to the Pegasus chip may be held | |
699 | * in reset until we flip on the GPIO outputs. Make sure | 699 | * in reset until we flip on the GPIO outputs. Make sure | |
700 | * to set the GPIO pins high so that the PHY(s) will | 700 | * to set the GPIO pins high so that the PHY(s) will | |
701 | * be enabled. | 701 | * be enabled. | |
702 | * | 702 | * | |
703 | * Note: We force all of the GPIO pins low first, *then* | 703 | * Note: We force all of the GPIO pins low first, *then* | |
704 | * enable the ones we want. | 704 | * enable the ones we want. | |
705 | */ | 705 | */ | |
706 | if (un->un_flags & LSYS) { | 706 | if (un->un_flags & LSYS) { | |
707 | /* Grrr. LinkSys has to be different from everyone else. */ | 707 | /* Grrr. LinkSys has to be different from everyone else. */ | |
708 | aue_csr_write_1(sc, AUE_GPIO0, | 708 | aue_csr_write_1(sc, AUE_GPIO0, | |
709 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | 709 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | |
710 | } else { | 710 | } else { | |
711 | aue_csr_write_1(sc, AUE_GPIO0, | 711 | aue_csr_write_1(sc, AUE_GPIO0, | |
712 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0); | 712 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0); | |
713 | } | 713 | } | |
714 | aue_csr_write_1(sc, AUE_GPIO0, | 714 | aue_csr_write_1(sc, AUE_GPIO0, | |
715 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | 715 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | |
716 | 716 | |||
717 | if (un->un_flags & PII) | 717 | if (un->un_flags & PII) | |
718 | aue_reset_pegasus_II(sc); | 718 | aue_reset_pegasus_II(sc); | |
719 | 719 | |||
720 | /* Wait a little while for the chip to get its brains in order. */ | 720 | /* Wait a little while for the chip to get its brains in order. */ | |
721 | delay(10000); /* XXX */ | 721 | delay(10000); /* XXX */ | |
722 | //usbd_delay_ms(un->un_udev, 10); /* XXX */ | 722 | //usbd_delay_ms(un->un_udev, 10); /* XXX */ | |
723 | 723 | |||
724 | DPRINTFN(2, "aue%jd: exit", device_unit(un->un_dev), 0, 0, 0); | 724 | DPRINTFN(2, "aue%jd: exit", device_unit(un->un_dev), 0, 0, 0); | |
725 | } | 725 | } | |
726 | 726 | |||
727 | /* | 727 | /* | |
728 | * Probe for a Pegasus chip. | 728 | * Probe for a Pegasus chip. | |
729 | */ | 729 | */ | |
730 | static int | 730 | static int | |
731 | aue_match(device_t parent, cfdata_t match, void *aux) | 731 | aue_match(device_t parent, cfdata_t match, void *aux) | |
732 | { | 732 | { | |
733 | struct usb_attach_arg *uaa = aux; | 733 | struct usb_attach_arg *uaa = aux; | |
734 | 734 | |||
735 | /* | 735 | /* | |
736 | * Some manufacturers use the same vendor and product id for | 736 | * Some manufacturers use the same vendor and product id for | |
737 | * different devices. We need to sanity check the DeviceClass | 737 | * different devices. We need to sanity check the DeviceClass | |
738 | * in this case | 738 | * in this case | |
739 | * Currently known guilty products: | 739 | * Currently known guilty products: | |
740 | * 0x050d/0x0121 Belkin Bluetooth and USB2LAN | 740 | * 0x050d/0x0121 Belkin Bluetooth and USB2LAN | |
741 | * | 741 | * | |
742 | * If this turns out to be more common, we could use a quirk | 742 | * If this turns out to be more common, we could use a quirk | |
743 | * table. | 743 | * table. | |
744 | */ | 744 | */ | |
745 | if (uaa->uaa_vendor == USB_VENDOR_BELKIN && | 745 | if (uaa->uaa_vendor == USB_VENDOR_BELKIN && | |
746 | uaa->uaa_product == USB_PRODUCT_BELKIN_USB2LAN) { | 746 | uaa->uaa_product == USB_PRODUCT_BELKIN_USB2LAN) { | |
747 | usb_device_descriptor_t *dd; | 747 | usb_device_descriptor_t *dd; | |
748 | 748 | |||
749 | dd = usbd_get_device_descriptor(uaa->uaa_device); | 749 | dd = usbd_get_device_descriptor(uaa->uaa_device); | |
750 | if (dd != NULL && | 750 | if (dd != NULL && | |
751 | dd->bDeviceClass != UDCLASS_IN_INTERFACE) | 751 | dd->bDeviceClass != UDCLASS_IN_INTERFACE) | |
752 | return UMATCH_NONE; | 752 | return UMATCH_NONE; | |
753 | } | 753 | } | |
754 | 754 | |||
755 | return aue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 755 | return aue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
756 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 756 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
757 | } | 757 | } | |
758 | 758 | |||
759 | /* | 759 | /* | |
760 | * Attach the interface. Allocate softc structures, do ifmedia | 760 | * Attach the interface. Allocate softc structures, do ifmedia | |
761 | * setup and ethernet/BPF attach. | 761 | * setup and ethernet/BPF attach. | |
762 | */ | 762 | */ | |
763 | static void | 763 | static void | |
764 | aue_attach(device_t parent, device_t self, void *aux) | 764 | aue_attach(device_t parent, device_t self, void *aux) | |
765 | { | 765 | { | |
766 | USBNET_MII_DECL_DEFAULT(unm); | 766 | USBNET_MII_DECL_DEFAULT(unm); | |
767 | struct aue_softc * const sc = device_private(self); | 767 | struct aue_softc * const sc = device_private(self); | |
768 | struct usbnet * const un = &sc->aue_un; | 768 | struct usbnet * const un = &sc->aue_un; | |
769 | struct usb_attach_arg *uaa = aux; | 769 | struct usb_attach_arg *uaa = aux; | |
770 | char *devinfop; | 770 | char *devinfop; | |
771 | struct usbd_device *dev = uaa->uaa_device; | 771 | struct usbd_device *dev = uaa->uaa_device; | |
772 | usbd_status err; | 772 | usbd_status err; | |
773 | usb_interface_descriptor_t *id; | 773 | usb_interface_descriptor_t *id; | |
774 | usb_endpoint_descriptor_t *ed; | 774 | usb_endpoint_descriptor_t *ed; | |
775 | int i; | 775 | int i; | |
776 | 776 | |||
777 | AUEHIST_FUNC(); | 777 | AUEHIST_FUNC(); | |
778 | AUEHIST_CALLARGSN(2, "aue%jd: enter sc=%#jx", | 778 | AUEHIST_CALLARGSN(2, "aue%jd: enter sc=%#jx", | |
779 | device_unit(self), (uintptr_t)sc, 0, 0); | 779 | device_unit(self), (uintptr_t)sc, 0, 0); | |
780 | 780 | |||
781 | KASSERT((void *)sc == un); | 781 | KASSERT((void *)sc == un); | |
782 | 782 | |||
783 | aprint_naive("\n"); | 783 | aprint_naive("\n"); | |
784 | aprint_normal("\n"); | 784 | aprint_normal("\n"); | |
785 | devinfop = usbd_devinfo_alloc(uaa->uaa_device, 0); | 785 | devinfop = usbd_devinfo_alloc(uaa->uaa_device, 0); | |
786 | aprint_normal_dev(self, "%s\n", devinfop); | 786 | aprint_normal_dev(self, "%s\n", devinfop); | |
787 | usbd_devinfo_free(devinfop); | 787 | usbd_devinfo_free(devinfop); | |
788 | 788 | |||
789 | un->un_dev = self; | 789 | un->un_dev = self; | |
790 | un->un_udev = dev; | 790 | un->un_udev = dev; | |
791 | un->un_sc = sc; | 791 | un->un_sc = sc; | |
792 | un->un_ops = &aue_ops; | 792 | un->un_ops = &aue_ops; | |
793 | un->un_intr = &sc->aue_intr; | 793 | un->un_intr = &sc->aue_intr; | |
794 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 794 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
795 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 795 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
796 | un->un_rx_list_cnt = AUE_RX_LIST_CNT; | 796 | un->un_rx_list_cnt = AUE_RX_LIST_CNT; | |
797 | un->un_tx_list_cnt = AUE_RX_LIST_CNT; | 797 | un->un_tx_list_cnt = AUE_RX_LIST_CNT; | |
798 | un->un_rx_bufsz = AUE_BUFSZ; | 798 | un->un_rx_bufsz = AUE_BUFSZ; | |
799 | un->un_tx_bufsz = AUE_BUFSZ; | 799 | un->un_tx_bufsz = AUE_BUFSZ; | |
800 | 800 | |||
801 | sc->aue_intr.uni_buf = &sc->aue_ibuf; | 801 | sc->aue_intr.uni_buf = &sc->aue_ibuf; | |
802 | sc->aue_intr.uni_bufsz = sizeof(sc->aue_ibuf); | 802 | sc->aue_intr.uni_bufsz = sizeof(sc->aue_ibuf); | |
803 | sc->aue_intr.uni_interval = AUE_INTR_INTERVAL; | 803 | sc->aue_intr.uni_interval = AUE_INTR_INTERVAL; | |
804 | 804 | |||
805 | err = usbd_set_config_no(dev, AUE_CONFIG_NO, 1); | 805 | err = usbd_set_config_no(dev, AUE_CONFIG_NO, 1); | |
806 | if (err) { | 806 | if (err) { | |
807 | aprint_error_dev(self, "failed to set configuration" | 807 | aprint_error_dev(self, "failed to set configuration" | |
808 | ", err=%s\n", usbd_errstr(err)); | 808 | ", err=%s\n", usbd_errstr(err)); | |
809 | return; | 809 | return; | |
810 | } | 810 | } | |
811 | 811 | |||
812 | err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &un->un_iface); | 812 | err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &un->un_iface); | |
813 | if (err) { | 813 | if (err) { | |
814 | aprint_error_dev(self, "getting interface handle failed\n"); | 814 | aprint_error_dev(self, "getting interface handle failed\n"); | |
815 | return; | 815 | return; | |
816 | } | 816 | } | |
817 | 817 | |||
818 | un->un_flags = aue_lookup(uaa->uaa_vendor, uaa->uaa_product)->aue_flags; | 818 | un->un_flags = aue_lookup(uaa->uaa_vendor, uaa->uaa_product)->aue_flags; | |
819 | 819 | |||
820 | id = usbd_get_interface_descriptor(un->un_iface); | 820 | id = usbd_get_interface_descriptor(un->un_iface); | |
821 | 821 | |||
822 | /* Find endpoints. */ | 822 | /* Find endpoints. */ | |
823 | for (i = 0; i < id->bNumEndpoints; i++) { | 823 | for (i = 0; i < id->bNumEndpoints; i++) { | |
824 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 824 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
825 | if (ed == NULL) { | 825 | if (ed == NULL) { | |
826 | aprint_error_dev(self, | 826 | aprint_error_dev(self, | |
827 | "couldn't get endpoint descriptor %d\n", i); | 827 | "couldn't get endpoint descriptor %d\n", i); | |
828 | return; | 828 | return; | |
829 | } | 829 | } | |
830 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 830 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
831 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 831 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
832 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 832 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
833 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 833 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
834 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 834 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
835 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 835 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
836 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 836 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
837 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 837 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
838 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 838 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
839 | } | 839 | } | |
840 | } | 840 | } | |
841 | 841 | |||
842 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 842 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
843 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 843 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
844 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 844 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
845 | aprint_error_dev(self, "missing endpoint\n"); | 845 | aprint_error_dev(self, "missing endpoint\n"); | |
846 | return; | 846 | return; | |
847 | } | 847 | } | |
848 | 848 | |||
849 | /* First level attach. */ | 849 | /* First level attach. */ | |
850 | usbnet_attach(un, "auedet"); | 850 | usbnet_attach(un, "auedet"); | |
851 | 851 | |||
852 | /* Reset the adapter and get station address from the EEPROM. */ | 852 | /* Reset the adapter and get station address from the EEPROM. */ | |
853 | aue_reset(sc); | 853 | aue_reset(sc); | |
854 | aue_read_mac(un); | 854 | aue_read_mac(un); | |
855 | 855 | |||
856 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 856 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
857 | 0, &unm); | 857 | 0, &unm); | |
858 | } | 858 | } | |
859 | 859 | |||
860 | static void | 860 | static void | |
861 | aue_uno_intr(struct usbnet *un, usbd_status status) | 861 | aue_uno_intr(struct usbnet *un, usbd_status status) | |
862 | { | 862 | { | |
863 | struct ifnet *ifp = usbnet_ifp(un); | 863 | struct ifnet *ifp = usbnet_ifp(un); | |
864 | struct aue_softc *sc = usbnet_softc(un); | 864 | struct aue_softc *sc = usbnet_softc(un); | |
865 | struct aue_intrpkt *p = &sc->aue_ibuf; | 865 | struct aue_intrpkt *p = &sc->aue_ibuf; | |
866 | 866 | |||
867 | AUEHIST_FUNC(); | 867 | AUEHIST_FUNC(); | |
868 | AUEHIST_CALLARGSN(20, "aue%jd: enter txstat0 %#jx\n", | 868 | AUEHIST_CALLARGSN(20, "aue%jd: enter txstat0 %#jx\n", | |
869 | device_unit(un->un_dev), p->aue_txstat0, 0, 0); | 869 | device_unit(un->un_dev), p->aue_txstat0, 0, 0); | |
870 | 870 | |||
871 | if (p->aue_txstat0) | 871 | if (p->aue_txstat0) | |
872 | if_statinc(ifp, if_oerrors); | 872 | if_statinc(ifp, if_oerrors); | |
873 | 873 | |||
874 | if (p->aue_txstat0 & (AUE_TXSTAT0_LATECOLL | AUE_TXSTAT0_EXCESSCOLL)) | 874 | if (p->aue_txstat0 & (AUE_TXSTAT0_LATECOLL | AUE_TXSTAT0_EXCESSCOLL)) | |
875 | if_statinc(ifp, if_collisions); | 875 | if_statinc(ifp, if_collisions); | |
876 | } | 876 | } | |
877 | 877 | |||
878 | static void | 878 | static void | |
879 | aue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 879 | aue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
880 | { | 880 | { | |
881 | struct ifnet *ifp = usbnet_ifp(un); | 881 | struct ifnet *ifp = usbnet_ifp(un); | |
882 | uint8_t *buf = c->unc_buf; | 882 | uint8_t *buf = c->unc_buf; | |
883 | struct aue_rxpkt r; | 883 | struct aue_rxpkt r; | |
884 | uint32_t pktlen; | 884 | uint32_t pktlen; | |
885 | 885 | |||
886 | AUEHIST_FUNC(); | 886 | AUEHIST_FUNC(); | |
887 | AUEHIST_CALLARGSN(10, "aue%jd: enter len %ju", | 887 | AUEHIST_CALLARGSN(10, "aue%jd: enter len %ju", | |
888 | device_unit(un->un_dev), total_len, 0, 0); | 888 | device_unit(un->un_dev), total_len, 0, 0); | |
889 | 889 | |||
890 | if (total_len <= 4 + ETHER_CRC_LEN) { | 890 | if (total_len <= 4 + ETHER_CRC_LEN) { | |
891 | if_statinc(ifp, if_ierrors); | 891 | if_statinc(ifp, if_ierrors); | |
892 | return; | 892 | return; | |
893 | } | 893 | } | |
894 | 894 | |||
895 | memcpy(&r, buf + total_len - 4, sizeof(r)); | 895 | memcpy(&r, buf + total_len - 4, sizeof(r)); | |
896 | 896 | |||
897 | /* Turn off all the non-error bits in the rx status word. */ | 897 | /* Turn off all the non-error bits in the rx status word. */ | |
898 | r.aue_rxstat &= AUE_RXSTAT_MASK; | 898 | r.aue_rxstat &= AUE_RXSTAT_MASK; | |
899 | if (r.aue_rxstat) { | 899 | if (r.aue_rxstat) { | |
900 | if_statinc(ifp, if_ierrors); | 900 | if_statinc(ifp, if_ierrors); | |
901 | return; | 901 | return; | |
902 | } | 902 | } | |
903 | 903 | |||
904 | /* No errors; receive the packet. */ | 904 | /* No errors; receive the packet. */ | |
905 | pktlen = total_len - ETHER_CRC_LEN - 4; | 905 | pktlen = total_len - ETHER_CRC_LEN - 4; | |
906 | 906 | |||
907 | usbnet_enqueue(un, buf, pktlen, 0, 0, 0); | 907 | usbnet_enqueue(un, buf, pktlen, 0, 0, 0); | |
908 | } | 908 | } | |
909 | 909 | |||
910 | static unsigned | 910 | static unsigned | |
911 | aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 911 | aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
912 | { | 912 | { | |
913 | uint8_t *buf = c->unc_buf; | 913 | uint8_t *buf = c->unc_buf; | |
914 | int total_len; | 914 | int total_len; | |
915 | 915 | |||
916 | AUEHIST_FUNC(); | 916 | AUEHIST_FUNC(); | |
917 | AUEHIST_CALLARGSN(10, "aue%jd: enter pktlen=%jd", | 917 | AUEHIST_CALLARGSN(10, "aue%jd: enter pktlen=%jd", | |
918 | device_unit(un->un_dev), m->m_pkthdr.len, 0, 0); | 918 | device_unit(un->un_dev), m->m_pkthdr.len, 0, 0); | |
919 | 919 | |||
920 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | 920 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | |
921 | return 0; | 921 | return 0; | |
922 | 922 | |||
923 | /* | 923 | /* | |
924 | * Copy the mbuf data into a contiguous buffer, leaving two | 924 | * Copy the mbuf data into a contiguous buffer, leaving two | |
925 | * bytes at the beginning to hold the frame length. | 925 | * bytes at the beginning to hold the frame length. | |
926 | */ | 926 | */ | |
927 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | 927 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | |
928 | 928 | |||
929 | /* | 929 | /* | |
930 | * The ADMtek documentation says that the packet length is | 930 | * The ADMtek documentation says that the packet length is | |
931 | * supposed to be specified in the first two bytes of the | 931 | * supposed to be specified in the first two bytes of the | |
932 | * transfer, however it actually seems to ignore this info | 932 | * transfer, however it actually seems to ignore this info | |
933 | * and base the frame size on the bulk transfer length. | 933 | * and base the frame size on the bulk transfer length. | |
934 | */ | 934 | */ | |
935 | buf[0] = (uint8_t)m->m_pkthdr.len; | 935 | buf[0] = (uint8_t)m->m_pkthdr.len; | |
936 | buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | 936 | buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | |
937 | total_len = m->m_pkthdr.len + 2; | 937 | total_len = m->m_pkthdr.len + 2; | |
938 | 938 | |||
939 | DPRINTFN(5, "aue%jd: send %jd bytes", | 939 | DPRINTFN(5, "aue%jd: send %jd bytes", | |
940 | device_unit(un->un_dev), total_len, 0, 0); | 940 | device_unit(un->un_dev), total_len, 0, 0); | |
941 | 941 | |||
942 | return total_len; | 942 | return total_len; | |
943 | } | 943 | } | |
944 | 944 | |||
945 | static int | 945 | static int | |
946 | aue_uno_init(struct ifnet *ifp) | 946 | aue_uno_init(struct ifnet *ifp) | |
947 | { | 947 | { | |
948 | struct usbnet * const un = ifp->if_softc; | 948 | struct usbnet * const un = ifp->if_softc; | |
949 | struct aue_softc *sc = usbnet_softc(un); | 949 | struct aue_softc *sc = usbnet_softc(un); | |
950 | int i; | 950 | int i; | |
951 | const u_char *eaddr; | 951 | const u_char *eaddr; | |
952 | 952 | |||
953 | AUEHIST_FUNC(); | 953 | AUEHIST_FUNC(); | |
954 | AUEHIST_CALLARGSN(5, "aue%jd: enter link=%jd", | 954 | AUEHIST_CALLARGSN(5, "aue%jd: enter link=%jd", | |
955 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | 955 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | |
956 | 956 | |||
957 | /* Cancel pending I/O */ | |||
958 | if (ifp->if_flags & IFF_RUNNING) | |||
959 | return 0; | |||
960 | ||||
961 | /* Reset the interface. */ | 957 | /* Reset the interface. */ | |
962 | aue_reset(sc); | 958 | aue_reset(sc); | |
963 | 959 | |||
964 | eaddr = CLLADDR(ifp->if_sadl); | 960 | eaddr = CLLADDR(ifp->if_sadl); | |
965 | for (i = 0; i < ETHER_ADDR_LEN; i++) | 961 | for (i = 0; i < ETHER_ADDR_LEN; i++) | |
966 | aue_csr_write_1(sc, AUE_PAR0 + i, eaddr[i]); | 962 | aue_csr_write_1(sc, AUE_PAR0 + i, eaddr[i]); | |
967 | 963 | |||
968 | /* If we want promiscuous mode, set the allframes bit. */ | 964 | /* If we want promiscuous mode, set the allframes bit. */ | |
969 | if (ifp->if_flags & IFF_PROMISC) | 965 | if (ifp->if_flags & IFF_PROMISC) | |
970 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | 966 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | |
971 | else | 967 | else | |
972 | AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | 968 | AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | |
973 | 969 | |||
974 | /* Enable RX and TX */ | 970 | /* Enable RX and TX */ | |
975 | aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB); | 971 | aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB); | |
976 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB); | 972 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB); | |
977 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR); | 973 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR); | |
978 | 974 | |||
979 | return usbnet_init_rx_tx(un); | 975 | return usbnet_init_rx_tx(un); | |
980 | } | 976 | } | |
981 | 977 | |||
982 | static void | 978 | static void | |
983 | aue_uno_stop(struct ifnet *ifp, int disable) | 979 | aue_uno_stop(struct ifnet *ifp, int disable) | |
984 | { | 980 | { | |
985 | struct usbnet * const un = ifp->if_softc; | 981 | struct usbnet * const un = ifp->if_softc; | |
986 | struct aue_softc * const sc = usbnet_softc(un); | 982 | struct aue_softc * const sc = usbnet_softc(un); | |
987 | 983 | |||
988 | AUEHIST_FUNC(); | 984 | AUEHIST_FUNC(); | |
989 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | 985 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | |
990 | 986 | |||
991 | aue_csr_write_1(sc, AUE_CTL0, 0); | 987 | aue_csr_write_1(sc, AUE_CTL0, 0); | |
992 | aue_csr_write_1(sc, AUE_CTL1, 0); | 988 | aue_csr_write_1(sc, AUE_CTL1, 0); | |
993 | aue_reset(sc); | 989 | aue_reset(sc); | |
994 | } | 990 | } | |
995 | 991 | |||
996 | #ifdef _MODULE | 992 | #ifdef _MODULE | |
997 | #include "ioconf.c" | 993 | #include "ioconf.c" | |
998 | #endif | 994 | #endif | |
999 | 995 | |||
1000 | USBNET_MODULE(aue) | 996 | USBNET_MODULE(aue) |
--- src/sys/dev/usb/if_mue.c 2022/03/03 05:55:01 1.78
+++ src/sys/dev/usb/if_mue.c 2022/03/03 05:55:19 1.79
@@ -1,1297 +1,1293 @@ | @@ -1,1297 +1,1293 @@ | |||
1 | /* $NetBSD: if_mue.c,v 1.78 2022/03/03 05:55:01 riastradh Exp $ */ | 1 | /* $NetBSD: if_mue.c,v 1.79 2022/03/03 05:55:19 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_mue.c,v 1.3 2018/08/04 16:42:46 jsg Exp $ */ | 2 | /* $OpenBSD: if_mue.c,v 1.3 2018/08/04 16:42:46 jsg Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2018 Kevin Lo <kevlo@openbsd.org> | 5 | * Copyright (c) 2018 Kevin Lo <kevlo@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | 18 | */ | |
19 | 19 | |||
20 | /* Driver for Microchip LAN7500/LAN7800 chipsets. */ | 20 | /* Driver for Microchip LAN7500/LAN7800 chipsets. */ | |
21 | 21 | |||
22 | #include <sys/cdefs.h> | 22 | #include <sys/cdefs.h> | |
23 | __KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1.78 2022/03/03 05:55:01 riastradh Exp $"); | 23 | __KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1.79 2022/03/03 05:55:19 riastradh Exp $"); | |
24 | 24 | |||
25 | #ifdef _KERNEL_OPT | 25 | #ifdef _KERNEL_OPT | |
26 | #include "opt_usb.h" | 26 | #include "opt_usb.h" | |
27 | #include "opt_inet.h" | 27 | #include "opt_inet.h" | |
28 | #endif | 28 | #endif | |
29 | 29 | |||
30 | #include <sys/param.h> | 30 | #include <sys/param.h> | |
31 | 31 | |||
32 | #include <dev/usb/usbnet.h> | 32 | #include <dev/usb/usbnet.h> | |
33 | 33 | |||
34 | #include <dev/usb/if_muereg.h> | 34 | #include <dev/usb/if_muereg.h> | |
35 | #include <dev/usb/if_muevar.h> | 35 | #include <dev/usb/if_muevar.h> | |
36 | 36 | |||
37 | #define MUE_PRINTF(un, fmt, args...) \ | 37 | #define MUE_PRINTF(un, fmt, args...) \ | |
38 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | 38 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | |
39 | 39 | |||
40 | #ifdef USB_DEBUG | 40 | #ifdef USB_DEBUG | |
41 | int muedebug = 0; | 41 | int muedebug = 0; | |
42 | #define DPRINTF(un, fmt, args...) \ | 42 | #define DPRINTF(un, fmt, args...) \ | |
43 | do { \ | 43 | do { \ | |
44 | if (muedebug) \ | 44 | if (muedebug) \ | |
45 | MUE_PRINTF(un, fmt, ##args); \ | 45 | MUE_PRINTF(un, fmt, ##args); \ | |
46 | } while (0 /* CONSTCOND */) | 46 | } while (0 /* CONSTCOND */) | |
47 | #else | 47 | #else | |
48 | #define DPRINTF(un, fmt, args...) __nothing | 48 | #define DPRINTF(un, fmt, args...) __nothing | |
49 | #endif | 49 | #endif | |
50 | 50 | |||
51 | /* | 51 | /* | |
52 | * Various supported device vendors/products. | 52 | * Various supported device vendors/products. | |
53 | */ | 53 | */ | |
54 | struct mue_type { | 54 | struct mue_type { | |
55 | struct usb_devno mue_dev; | 55 | struct usb_devno mue_dev; | |
56 | uint16_t mue_flags; | 56 | uint16_t mue_flags; | |
57 | #define LAN7500 0x0001 /* LAN7500 */ | 57 | #define LAN7500 0x0001 /* LAN7500 */ | |
58 | #define LAN7800 0x0002 /* LAN7800 */ | 58 | #define LAN7800 0x0002 /* LAN7800 */ | |
59 | #define LAN7801 0x0004 /* LAN7801 */ | 59 | #define LAN7801 0x0004 /* LAN7801 */ | |
60 | #define LAN7850 0x0008 /* LAN7850 */ | 60 | #define LAN7850 0x0008 /* LAN7850 */ | |
61 | }; | 61 | }; | |
62 | 62 | |||
63 | static const struct mue_type mue_devs[] = { | 63 | static const struct mue_type mue_devs[] = { | |
64 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7500 }, LAN7500 }, | 64 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7500 }, LAN7500 }, | |
65 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7505 }, LAN7500 }, | 65 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7505 }, LAN7500 }, | |
66 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7800 }, LAN7800 }, | 66 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7800 }, LAN7800 }, | |
67 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7801 }, LAN7801 }, | 67 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7801 }, LAN7801 }, | |
68 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7850 }, LAN7850 } | 68 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7850 }, LAN7850 } | |
69 | }; | 69 | }; | |
70 | 70 | |||
71 | #define MUE_LOOKUP(uaa) ((const struct mue_type *)usb_lookup(mue_devs, \ | 71 | #define MUE_LOOKUP(uaa) ((const struct mue_type *)usb_lookup(mue_devs, \ | |
72 | uaa->uaa_vendor, uaa->uaa_product)) | 72 | uaa->uaa_vendor, uaa->uaa_product)) | |
73 | 73 | |||
74 | #define MUE_ENADDR_LO(enaddr) \ | 74 | #define MUE_ENADDR_LO(enaddr) \ | |
75 | ((enaddr[3] << 24) | (enaddr[2] << 16) | (enaddr[1] << 8) | enaddr[0]) | 75 | ((enaddr[3] << 24) | (enaddr[2] << 16) | (enaddr[1] << 8) | enaddr[0]) | |
76 | #define MUE_ENADDR_HI(enaddr) \ | 76 | #define MUE_ENADDR_HI(enaddr) \ | |
77 | ((enaddr[5] << 8) | enaddr[4]) | 77 | ((enaddr[5] << 8) | enaddr[4]) | |
78 | 78 | |||
79 | static int mue_match(device_t, cfdata_t, void *); | 79 | static int mue_match(device_t, cfdata_t, void *); | |
80 | static void mue_attach(device_t, device_t, void *); | 80 | static void mue_attach(device_t, device_t, void *); | |
81 | 81 | |||
82 | static uint32_t mue_csr_read(struct usbnet *, uint32_t); | 82 | static uint32_t mue_csr_read(struct usbnet *, uint32_t); | |
83 | static int mue_csr_write(struct usbnet *, uint32_t, uint32_t); | 83 | static int mue_csr_write(struct usbnet *, uint32_t, uint32_t); | |
84 | static int mue_wait_for_bits(struct usbnet *, uint32_t, uint32_t, | 84 | static int mue_wait_for_bits(struct usbnet *, uint32_t, uint32_t, | |
85 | uint32_t, uint32_t); | 85 | uint32_t, uint32_t); | |
86 | static uint8_t mue_eeprom_getbyte(struct usbnet *, int, uint8_t *); | 86 | static uint8_t mue_eeprom_getbyte(struct usbnet *, int, uint8_t *); | |
87 | static bool mue_eeprom_present(struct usbnet *); | 87 | static bool mue_eeprom_present(struct usbnet *); | |
88 | static void mue_dataport_write(struct usbnet *, uint32_t, uint32_t, | 88 | static void mue_dataport_write(struct usbnet *, uint32_t, uint32_t, | |
89 | uint32_t, uint32_t *); | 89 | uint32_t, uint32_t *); | |
90 | static void mue_init_ltm(struct usbnet *); | 90 | static void mue_init_ltm(struct usbnet *); | |
91 | static int mue_chip_init(struct usbnet *); | 91 | static int mue_chip_init(struct usbnet *); | |
92 | static void mue_set_macaddr(struct usbnet *); | 92 | static void mue_set_macaddr(struct usbnet *); | |
93 | static int mue_get_macaddr(struct usbnet *, prop_dictionary_t); | 93 | static int mue_get_macaddr(struct usbnet *, prop_dictionary_t); | |
94 | static int mue_prepare_tso(struct usbnet *, struct mbuf *); | 94 | static int mue_prepare_tso(struct usbnet *, struct mbuf *); | |
95 | static void mue_uno_mcast(struct ifnet *); | 95 | static void mue_uno_mcast(struct ifnet *); | |
96 | static void mue_sethwcsum_locked(struct usbnet *); | 96 | static void mue_sethwcsum_locked(struct usbnet *); | |
97 | static void mue_setmtu_locked(struct usbnet *); | 97 | static void mue_setmtu_locked(struct usbnet *); | |
98 | static void mue_reset(struct usbnet *); | 98 | static void mue_reset(struct usbnet *); | |
99 | 99 | |||
100 | static void mue_uno_stop(struct ifnet *, int); | 100 | static void mue_uno_stop(struct ifnet *, int); | |
101 | static int mue_uno_ioctl(struct ifnet *, u_long, void *); | 101 | static int mue_uno_ioctl(struct ifnet *, u_long, void *); | |
102 | static int mue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 102 | static int mue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
103 | static int mue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 103 | static int mue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
104 | static void mue_uno_mii_statchg(struct ifnet *); | 104 | static void mue_uno_mii_statchg(struct ifnet *); | |
105 | static void mue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 105 | static void mue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
106 | uint32_t); | 106 | uint32_t); | |
107 | static unsigned mue_uno_tx_prepare(struct usbnet *, struct mbuf *, | 107 | static unsigned mue_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
108 | struct usbnet_chain *); | 108 | struct usbnet_chain *); | |
109 | static int mue_uno_init(struct ifnet *); | 109 | static int mue_uno_init(struct ifnet *); | |
110 | 110 | |||
111 | static const struct usbnet_ops mue_ops = { | 111 | static const struct usbnet_ops mue_ops = { | |
112 | .uno_stop = mue_uno_stop, | 112 | .uno_stop = mue_uno_stop, | |
113 | .uno_ioctl = mue_uno_ioctl, | 113 | .uno_ioctl = mue_uno_ioctl, | |
114 | .uno_mcast = mue_uno_mcast, | 114 | .uno_mcast = mue_uno_mcast, | |
115 | .uno_read_reg = mue_uno_mii_read_reg, | 115 | .uno_read_reg = mue_uno_mii_read_reg, | |
116 | .uno_write_reg = mue_uno_mii_write_reg, | 116 | .uno_write_reg = mue_uno_mii_write_reg, | |
117 | .uno_statchg = mue_uno_mii_statchg, | 117 | .uno_statchg = mue_uno_mii_statchg, | |
118 | .uno_tx_prepare = mue_uno_tx_prepare, | 118 | .uno_tx_prepare = mue_uno_tx_prepare, | |
119 | .uno_rx_loop = mue_uno_rx_loop, | 119 | .uno_rx_loop = mue_uno_rx_loop, | |
120 | .uno_init = mue_uno_init, | 120 | .uno_init = mue_uno_init, | |
121 | }; | 121 | }; | |
122 | 122 | |||
123 | #define MUE_SETBIT(un, reg, x) \ | 123 | #define MUE_SETBIT(un, reg, x) \ | |
124 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) | 124 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) | |
125 | 125 | |||
126 | #define MUE_CLRBIT(un, reg, x) \ | 126 | #define MUE_CLRBIT(un, reg, x) \ | |
127 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) | 127 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) | |
128 | 128 | |||
129 | #define MUE_WAIT_SET(un, reg, set, fail) \ | 129 | #define MUE_WAIT_SET(un, reg, set, fail) \ | |
130 | mue_wait_for_bits(un, reg, set, ~0, fail) | 130 | mue_wait_for_bits(un, reg, set, ~0, fail) | |
131 | 131 | |||
132 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ | 132 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ | |
133 | mue_wait_for_bits(un, reg, 0, clear, fail) | 133 | mue_wait_for_bits(un, reg, 0, clear, fail) | |
134 | 134 | |||
135 | #define ETHER_IS_VALID(addr) \ | 135 | #define ETHER_IS_VALID(addr) \ | |
136 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) | 136 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) | |
137 | 137 | |||
138 | #define ETHER_IS_ZERO(addr) \ | 138 | #define ETHER_IS_ZERO(addr) \ | |
139 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | 139 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | |
140 | 140 | |||
141 | CFATTACH_DECL_NEW(mue, sizeof(struct usbnet), mue_match, mue_attach, | 141 | CFATTACH_DECL_NEW(mue, sizeof(struct usbnet), mue_match, mue_attach, | |
142 | usbnet_detach, usbnet_activate); | 142 | usbnet_detach, usbnet_activate); | |
143 | 143 | |||
144 | static uint32_t | 144 | static uint32_t | |
145 | mue_csr_read(struct usbnet *un, uint32_t reg) | 145 | mue_csr_read(struct usbnet *un, uint32_t reg) | |
146 | { | 146 | { | |
147 | usb_device_request_t req; | 147 | usb_device_request_t req; | |
148 | usbd_status err; | 148 | usbd_status err; | |
149 | uDWord val; | 149 | uDWord val; | |
150 | 150 | |||
151 | if (usbnet_isdying(un)) | 151 | if (usbnet_isdying(un)) | |
152 | return 0; | 152 | return 0; | |
153 | 153 | |||
154 | USETDW(val, 0); | 154 | USETDW(val, 0); | |
155 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 155 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
156 | req.bRequest = MUE_UR_READREG; | 156 | req.bRequest = MUE_UR_READREG; | |
157 | USETW(req.wValue, 0); | 157 | USETW(req.wValue, 0); | |
158 | USETW(req.wIndex, reg); | 158 | USETW(req.wIndex, reg); | |
159 | USETW(req.wLength, 4); | 159 | USETW(req.wLength, 4); | |
160 | 160 | |||
161 | err = usbd_do_request(un->un_udev, &req, &val); | 161 | err = usbd_do_request(un->un_udev, &req, &val); | |
162 | if (err) { | 162 | if (err) { | |
163 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | 163 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | |
164 | return 0; | 164 | return 0; | |
165 | } | 165 | } | |
166 | 166 | |||
167 | return UGETDW(val); | 167 | return UGETDW(val); | |
168 | } | 168 | } | |
169 | 169 | |||
170 | static int | 170 | static int | |
171 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) | 171 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) | |
172 | { | 172 | { | |
173 | usb_device_request_t req; | 173 | usb_device_request_t req; | |
174 | usbd_status err; | 174 | usbd_status err; | |
175 | uDWord val; | 175 | uDWord val; | |
176 | 176 | |||
177 | if (usbnet_isdying(un)) | 177 | if (usbnet_isdying(un)) | |
178 | return 0; | 178 | return 0; | |
179 | 179 | |||
180 | USETDW(val, aval); | 180 | USETDW(val, aval); | |
181 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 181 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
182 | req.bRequest = MUE_UR_WRITEREG; | 182 | req.bRequest = MUE_UR_WRITEREG; | |
183 | USETW(req.wValue, 0); | 183 | USETW(req.wValue, 0); | |
184 | USETW(req.wIndex, reg); | 184 | USETW(req.wIndex, reg); | |
185 | USETW(req.wLength, 4); | 185 | USETW(req.wLength, 4); | |
186 | 186 | |||
187 | err = usbd_do_request(un->un_udev, &req, &val); | 187 | err = usbd_do_request(un->un_udev, &req, &val); | |
188 | if (err) { | 188 | if (err) { | |
189 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | 189 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | |
190 | return -1; | 190 | return -1; | |
191 | } | 191 | } | |
192 | 192 | |||
193 | return 0; | 193 | return 0; | |
194 | } | 194 | } | |
195 | 195 | |||
196 | static int | 196 | static int | |
197 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, | 197 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, | |
198 | uint32_t set, uint32_t clear, uint32_t fail) | 198 | uint32_t set, uint32_t clear, uint32_t fail) | |
199 | { | 199 | { | |
200 | uint32_t val; | 200 | uint32_t val; | |
201 | int ntries; | 201 | int ntries; | |
202 | 202 | |||
203 | for (ntries = 0; ntries < 1000; ntries++) { | 203 | for (ntries = 0; ntries < 1000; ntries++) { | |
204 | if (usbnet_isdying(un)) | 204 | if (usbnet_isdying(un)) | |
205 | return 1; | 205 | return 1; | |
206 | val = mue_csr_read(un, reg); | 206 | val = mue_csr_read(un, reg); | |
207 | if ((val & set) || !(val & clear)) | 207 | if ((val & set) || !(val & clear)) | |
208 | return 0; | 208 | return 0; | |
209 | if (val & fail) | 209 | if (val & fail) | |
210 | return 1; | 210 | return 1; | |
211 | usbd_delay_ms(un->un_udev, 1); | 211 | usbd_delay_ms(un->un_udev, 1); | |
212 | } | 212 | } | |
213 | 213 | |||
214 | return 1; | 214 | return 1; | |
215 | } | 215 | } | |
216 | 216 | |||
217 | static int | 217 | static int | |
218 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 218 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
219 | { | 219 | { | |
220 | uint32_t data; | 220 | uint32_t data; | |
221 | 221 | |||
222 | if (un->un_phyno != phy) { | 222 | if (un->un_phyno != phy) { | |
223 | *val = 0; | 223 | *val = 0; | |
224 | return EINVAL; | 224 | return EINVAL; | |
225 | } | 225 | } | |
226 | 226 | |||
227 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 227 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
228 | MUE_PRINTF(un, "not ready\n"); | 228 | MUE_PRINTF(un, "not ready\n"); | |
229 | *val = 0; | 229 | *val = 0; | |
230 | return EBUSY; | 230 | return EBUSY; | |
231 | } | 231 | } | |
232 | 232 | |||
233 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | | 233 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | | |
234 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | 234 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | |
235 | MUE_MII_ACCESS_PHYADDR(phy)); | 235 | MUE_MII_ACCESS_PHYADDR(phy)); | |
236 | 236 | |||
237 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 237 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
238 | MUE_PRINTF(un, "timed out\n"); | 238 | MUE_PRINTF(un, "timed out\n"); | |
239 | *val = 0; | 239 | *val = 0; | |
240 | return ETIMEDOUT; | 240 | return ETIMEDOUT; | |
241 | } | 241 | } | |
242 | 242 | |||
243 | data = mue_csr_read(un, MUE_MII_DATA); | 243 | data = mue_csr_read(un, MUE_MII_DATA); | |
244 | *val = data & 0xffff; | 244 | *val = data & 0xffff; | |
245 | 245 | |||
246 | return 0; | 246 | return 0; | |
247 | } | 247 | } | |
248 | 248 | |||
249 | static int | 249 | static int | |
250 | mue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 250 | mue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
251 | { | 251 | { | |
252 | 252 | |||
253 | if (un->un_phyno != phy) | 253 | if (un->un_phyno != phy) | |
254 | return EINVAL; | 254 | return EINVAL; | |
255 | 255 | |||
256 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 256 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
257 | MUE_PRINTF(un, "not ready\n"); | 257 | MUE_PRINTF(un, "not ready\n"); | |
258 | return EBUSY; | 258 | return EBUSY; | |
259 | } | 259 | } | |
260 | 260 | |||
261 | mue_csr_write(un, MUE_MII_DATA, val); | 261 | mue_csr_write(un, MUE_MII_DATA, val); | |
262 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | | 262 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | | |
263 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | 263 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | |
264 | MUE_MII_ACCESS_PHYADDR(phy)); | 264 | MUE_MII_ACCESS_PHYADDR(phy)); | |
265 | 265 | |||
266 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 266 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
267 | MUE_PRINTF(un, "timed out\n"); | 267 | MUE_PRINTF(un, "timed out\n"); | |
268 | return ETIMEDOUT; | 268 | return ETIMEDOUT; | |
269 | } | 269 | } | |
270 | 270 | |||
271 | return 0; | 271 | return 0; | |
272 | } | 272 | } | |
273 | 273 | |||
274 | static void | 274 | static void | |
275 | mue_uno_mii_statchg(struct ifnet *ifp) | 275 | mue_uno_mii_statchg(struct ifnet *ifp) | |
276 | { | 276 | { | |
277 | struct usbnet * const un = ifp->if_softc; | 277 | struct usbnet * const un = ifp->if_softc; | |
278 | struct mii_data * const mii = usbnet_mii(un); | 278 | struct mii_data * const mii = usbnet_mii(un); | |
279 | uint32_t flow, threshold; | 279 | uint32_t flow, threshold; | |
280 | 280 | |||
281 | if (usbnet_isdying(un)) | 281 | if (usbnet_isdying(un)) | |
282 | return; | 282 | return; | |
283 | 283 | |||
284 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 284 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
285 | (IFM_ACTIVE | IFM_AVALID)) { | 285 | (IFM_ACTIVE | IFM_AVALID)) { | |
286 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 286 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
287 | case IFM_10_T: | 287 | case IFM_10_T: | |
288 | case IFM_100_TX: | 288 | case IFM_100_TX: | |
289 | case IFM_1000_T: | 289 | case IFM_1000_T: | |
290 | usbnet_set_link(un, true); | 290 | usbnet_set_link(un, true); | |
291 | break; | 291 | break; | |
292 | default: | 292 | default: | |
293 | break; | 293 | break; | |
294 | } | 294 | } | |
295 | } | 295 | } | |
296 | 296 | |||
297 | /* Lost link, do nothing. */ | 297 | /* Lost link, do nothing. */ | |
298 | if (!usbnet_havelink(un)) { | 298 | if (!usbnet_havelink(un)) { | |
299 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); | 299 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); | |
300 | return; | 300 | return; | |
301 | } | 301 | } | |
302 | 302 | |||
303 | if (!(un->un_flags & LAN7500)) { | 303 | if (!(un->un_flags & LAN7500)) { | |
304 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { | 304 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { | |
305 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { | 305 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { | |
306 | /* Disable U2 and enable U1. */ | 306 | /* Disable U2 and enable U1. */ | |
307 | MUE_CLRBIT(un, MUE_USB_CFG1, | 307 | MUE_CLRBIT(un, MUE_USB_CFG1, | |
308 | MUE_USB_CFG1_DEV_U2_INIT_EN); | 308 | MUE_USB_CFG1_DEV_U2_INIT_EN); | |
309 | MUE_SETBIT(un, MUE_USB_CFG1, | 309 | MUE_SETBIT(un, MUE_USB_CFG1, | |
310 | MUE_USB_CFG1_DEV_U1_INIT_EN); | 310 | MUE_USB_CFG1_DEV_U1_INIT_EN); | |
311 | } else { | 311 | } else { | |
312 | /* Enable U1 and U2. */ | 312 | /* Enable U1 and U2. */ | |
313 | MUE_SETBIT(un, MUE_USB_CFG1, | 313 | MUE_SETBIT(un, MUE_USB_CFG1, | |
314 | MUE_USB_CFG1_DEV_U1_INIT_EN | | 314 | MUE_USB_CFG1_DEV_U1_INIT_EN | | |
315 | MUE_USB_CFG1_DEV_U2_INIT_EN); | 315 | MUE_USB_CFG1_DEV_U2_INIT_EN); | |
316 | } | 316 | } | |
317 | } | 317 | } | |
318 | } | 318 | } | |
319 | 319 | |||
320 | flow = 0; | 320 | flow = 0; | |
321 | /* XXX Linux does not check IFM_FDX flag for 7800. */ | 321 | /* XXX Linux does not check IFM_FDX flag for 7800. */ | |
322 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | 322 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | |
323 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) | 323 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) | |
324 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; | 324 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; | |
325 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) | 325 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) | |
326 | flow |= MUE_FLOW_RX_FCEN; | 326 | flow |= MUE_FLOW_RX_FCEN; | |
327 | } | 327 | } | |
328 | 328 | |||
329 | /* XXX Magic numbers taken from Linux driver. */ | 329 | /* XXX Magic numbers taken from Linux driver. */ | |
330 | if (un->un_flags & LAN7500) | 330 | if (un->un_flags & LAN7500) | |
331 | threshold = 0x820; | 331 | threshold = 0x820; | |
332 | else | 332 | else | |
333 | switch (un->un_udev->ud_speed) { | 333 | switch (un->un_udev->ud_speed) { | |
334 | case USB_SPEED_SUPER: | 334 | case USB_SPEED_SUPER: | |
335 | threshold = 0x817; | 335 | threshold = 0x817; | |
336 | break; | 336 | break; | |
337 | case USB_SPEED_HIGH: | 337 | case USB_SPEED_HIGH: | |
338 | threshold = 0x211; | 338 | threshold = 0x211; | |
339 | break; | 339 | break; | |
340 | default: | 340 | default: | |
341 | threshold = 0; | 341 | threshold = 0; | |
342 | break; | 342 | break; | |
343 | } | 343 | } | |
344 | 344 | |||
345 | /* Threshold value should be set before enabling flow. */ | 345 | /* Threshold value should be set before enabling flow. */ | |
346 | mue_csr_write(un, (un->un_flags & LAN7500) ? | 346 | mue_csr_write(un, (un->un_flags & LAN7500) ? | |
347 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); | 347 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); | |
348 | mue_csr_write(un, MUE_FLOW, flow); | 348 | mue_csr_write(un, MUE_FLOW, flow); | |
349 | 349 | |||
350 | DPRINTF(un, "done\n"); | 350 | DPRINTF(un, "done\n"); | |
351 | } | 351 | } | |
352 | 352 | |||
353 | static uint8_t | 353 | static uint8_t | |
354 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) | 354 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) | |
355 | { | 355 | { | |
356 | uint32_t val; | 356 | uint32_t val; | |
357 | 357 | |||
358 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, 0)) { | 358 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, 0)) { | |
359 | MUE_PRINTF(un, "not ready\n"); | 359 | MUE_PRINTF(un, "not ready\n"); | |
360 | return ETIMEDOUT; | 360 | return ETIMEDOUT; | |
361 | } | 361 | } | |
362 | 362 | |||
363 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); | 363 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); | |
364 | mue_csr_write(un, MUE_E2P_CMD, MUE_E2P_CMD_READ | MUE_E2P_CMD_BUSY | | 364 | mue_csr_write(un, MUE_E2P_CMD, MUE_E2P_CMD_READ | MUE_E2P_CMD_BUSY | | |
365 | off); | 365 | off); | |
366 | 366 | |||
367 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, | 367 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, | |
368 | MUE_E2P_CMD_TIMEOUT)) { | 368 | MUE_E2P_CMD_TIMEOUT)) { | |
369 | MUE_PRINTF(un, "timed out\n"); | 369 | MUE_PRINTF(un, "timed out\n"); | |
370 | return ETIMEDOUT; | 370 | return ETIMEDOUT; | |
371 | } | 371 | } | |
372 | 372 | |||
373 | val = mue_csr_read(un, MUE_E2P_DATA); | 373 | val = mue_csr_read(un, MUE_E2P_DATA); | |
374 | *dest = val & 0xff; | 374 | *dest = val & 0xff; | |
375 | 375 | |||
376 | return 0; | 376 | return 0; | |
377 | } | 377 | } | |
378 | 378 | |||
379 | static int | 379 | static int | |
380 | mue_read_eeprom(struct usbnet *un, uint8_t *dest, int off, int cnt) | 380 | mue_read_eeprom(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
381 | { | 381 | { | |
382 | uint32_t val = 0; /* XXX gcc */ | 382 | uint32_t val = 0; /* XXX gcc */ | |
383 | uint8_t byte; | 383 | uint8_t byte; | |
384 | int i, err = 0; | 384 | int i, err = 0; | |
385 | 385 | |||
386 | /* | 386 | /* | |
387 | * EEPROM pins are muxed with the LED function on LAN7800 device. | 387 | * EEPROM pins are muxed with the LED function on LAN7800 device. | |
388 | */ | 388 | */ | |
389 | if (un->un_flags & LAN7800) { | 389 | if (un->un_flags & LAN7800) { | |
390 | val = mue_csr_read(un, MUE_HW_CFG); | 390 | val = mue_csr_read(un, MUE_HW_CFG); | |
391 | mue_csr_write(un, MUE_HW_CFG, | 391 | mue_csr_write(un, MUE_HW_CFG, | |
392 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); | 392 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); | |
393 | } | 393 | } | |
394 | 394 | |||
395 | for (i = 0; i < cnt; i++) { | 395 | for (i = 0; i < cnt; i++) { | |
396 | err = mue_eeprom_getbyte(un, off + i, &byte); | 396 | err = mue_eeprom_getbyte(un, off + i, &byte); | |
397 | if (err) | 397 | if (err) | |
398 | break; | 398 | break; | |
399 | *(dest + i) = byte; | 399 | *(dest + i) = byte; | |
400 | } | 400 | } | |
401 | 401 | |||
402 | if (un->un_flags & LAN7800) | 402 | if (un->un_flags & LAN7800) | |
403 | mue_csr_write(un, MUE_HW_CFG, val); | 403 | mue_csr_write(un, MUE_HW_CFG, val); | |
404 | 404 | |||
405 | return err ? 1 : 0; | 405 | return err ? 1 : 0; | |
406 | } | 406 | } | |
407 | 407 | |||
408 | static bool | 408 | static bool | |
409 | mue_eeprom_present(struct usbnet *un) | 409 | mue_eeprom_present(struct usbnet *un) | |
410 | { | 410 | { | |
411 | uint32_t val; | 411 | uint32_t val; | |
412 | uint8_t sig; | 412 | uint8_t sig; | |
413 | int ret; | 413 | int ret; | |
414 | 414 | |||
415 | if (un->un_flags & LAN7500) { | 415 | if (un->un_flags & LAN7500) { | |
416 | val = mue_csr_read(un, MUE_E2P_CMD); | 416 | val = mue_csr_read(un, MUE_E2P_CMD); | |
417 | return val & MUE_E2P_CMD_LOADED; | 417 | return val & MUE_E2P_CMD_LOADED; | |
418 | } else { | 418 | } else { | |
419 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); | 419 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); | |
420 | return (ret == 0) && (sig == MUE_E2P_IND); | 420 | return (ret == 0) && (sig == MUE_E2P_IND); | |
421 | } | 421 | } | |
422 | } | 422 | } | |
423 | 423 | |||
424 | static int | 424 | static int | |
425 | mue_read_otp_raw(struct usbnet *un, uint8_t *dest, int off, int cnt) | 425 | mue_read_otp_raw(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
426 | { | 426 | { | |
427 | uint32_t val; | 427 | uint32_t val; | |
428 | int i, err; | 428 | int i, err; | |
429 | 429 | |||
430 | val = mue_csr_read(un, MUE_OTP_PWR_DN); | 430 | val = mue_csr_read(un, MUE_OTP_PWR_DN); | |
431 | 431 | |||
432 | /* Checking if bit is set. */ | 432 | /* Checking if bit is set. */ | |
433 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { | 433 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { | |
434 | /* Clear it, then wait for it to be cleared. */ | 434 | /* Clear it, then wait for it to be cleared. */ | |
435 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); | 435 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); | |
436 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, | 436 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, | |
437 | 0); | 437 | 0); | |
438 | if (err) { | 438 | if (err) { | |
439 | MUE_PRINTF(un, "not ready\n"); | 439 | MUE_PRINTF(un, "not ready\n"); | |
440 | return 1; | 440 | return 1; | |
441 | } | 441 | } | |
442 | } | 442 | } | |
443 | 443 | |||
444 | /* Start reading the bytes, one at a time. */ | 444 | /* Start reading the bytes, one at a time. */ | |
445 | for (i = 0; i < cnt; i++) { | 445 | for (i = 0; i < cnt; i++) { | |
446 | mue_csr_write(un, MUE_OTP_ADDR1, | 446 | mue_csr_write(un, MUE_OTP_ADDR1, | |
447 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); | 447 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); | |
448 | mue_csr_write(un, MUE_OTP_ADDR2, | 448 | mue_csr_write(un, MUE_OTP_ADDR2, | |
449 | ((off + i) & MUE_OTP_ADDR2_MASK)); | 449 | ((off + i) & MUE_OTP_ADDR2_MASK)); | |
450 | mue_csr_write(un, MUE_OTP_FUNC_CMD, MUE_OTP_FUNC_CMD_READ); | 450 | mue_csr_write(un, MUE_OTP_FUNC_CMD, MUE_OTP_FUNC_CMD_READ); | |
451 | mue_csr_write(un, MUE_OTP_CMD_GO, MUE_OTP_CMD_GO_GO); | 451 | mue_csr_write(un, MUE_OTP_CMD_GO, MUE_OTP_CMD_GO_GO); | |
452 | 452 | |||
453 | err = MUE_WAIT_CLR(un, MUE_OTP_STATUS, MUE_OTP_STATUS_BUSY, 0); | 453 | err = MUE_WAIT_CLR(un, MUE_OTP_STATUS, MUE_OTP_STATUS_BUSY, 0); | |
454 | if (err) { | 454 | if (err) { | |
455 | MUE_PRINTF(un, "timed out\n"); | 455 | MUE_PRINTF(un, "timed out\n"); | |
456 | return 1; | 456 | return 1; | |
457 | } | 457 | } | |
458 | val = mue_csr_read(un, MUE_OTP_RD_DATA); | 458 | val = mue_csr_read(un, MUE_OTP_RD_DATA); | |
459 | *(dest + i) = (uint8_t)(val & 0xff); | 459 | *(dest + i) = (uint8_t)(val & 0xff); | |
460 | } | 460 | } | |
461 | 461 | |||
462 | return 0; | 462 | return 0; | |
463 | } | 463 | } | |
464 | 464 | |||
465 | static int | 465 | static int | |
466 | mue_read_otp(struct usbnet *un, uint8_t *dest, int off, int cnt) | 466 | mue_read_otp(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
467 | { | 467 | { | |
468 | uint8_t sig; | 468 | uint8_t sig; | |
469 | int err; | 469 | int err; | |
470 | 470 | |||
471 | if (un->un_flags & LAN7500) | 471 | if (un->un_flags & LAN7500) | |
472 | return 1; | 472 | return 1; | |
473 | 473 | |||
474 | err = mue_read_otp_raw(un, &sig, MUE_OTP_IND_OFFSET, 1); | 474 | err = mue_read_otp_raw(un, &sig, MUE_OTP_IND_OFFSET, 1); | |
475 | if (err) | 475 | if (err) | |
476 | return 1; | 476 | return 1; | |
477 | switch (sig) { | 477 | switch (sig) { | |
478 | case MUE_OTP_IND_1: | 478 | case MUE_OTP_IND_1: | |
479 | break; | 479 | break; | |
480 | case MUE_OTP_IND_2: | 480 | case MUE_OTP_IND_2: | |
481 | off += 0x100; | 481 | off += 0x100; | |
482 | break; | 482 | break; | |
483 | default: | 483 | default: | |
484 | DPRINTF(un, "OTP not found\n"); | 484 | DPRINTF(un, "OTP not found\n"); | |
485 | return 1; | 485 | return 1; | |
486 | } | 486 | } | |
487 | err = mue_read_otp_raw(un, dest, off, cnt); | 487 | err = mue_read_otp_raw(un, dest, off, cnt); | |
488 | return err; | 488 | return err; | |
489 | } | 489 | } | |
490 | 490 | |||
491 | static void | 491 | static void | |
492 | mue_dataport_write(struct usbnet *un, uint32_t sel, uint32_t addr, | 492 | mue_dataport_write(struct usbnet *un, uint32_t sel, uint32_t addr, | |
493 | uint32_t cnt, uint32_t *data) | 493 | uint32_t cnt, uint32_t *data) | |
494 | { | 494 | { | |
495 | uint32_t i; | 495 | uint32_t i; | |
496 | 496 | |||
497 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | 497 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | |
498 | MUE_PRINTF(un, "not ready\n"); | 498 | MUE_PRINTF(un, "not ready\n"); | |
499 | return; | 499 | return; | |
500 | } | 500 | } | |
501 | 501 | |||
502 | mue_csr_write(un, MUE_DP_SEL, | 502 | mue_csr_write(un, MUE_DP_SEL, | |
503 | (mue_csr_read(un, MUE_DP_SEL) & ~MUE_DP_SEL_RSEL_MASK) | sel); | 503 | (mue_csr_read(un, MUE_DP_SEL) & ~MUE_DP_SEL_RSEL_MASK) | sel); | |
504 | 504 | |||
505 | for (i = 0; i < cnt; i++) { | 505 | for (i = 0; i < cnt; i++) { | |
506 | mue_csr_write(un, MUE_DP_ADDR, addr + i); | 506 | mue_csr_write(un, MUE_DP_ADDR, addr + i); | |
507 | mue_csr_write(un, MUE_DP_DATA, data[i]); | 507 | mue_csr_write(un, MUE_DP_DATA, data[i]); | |
508 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); | 508 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); | |
509 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | 509 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | |
510 | MUE_PRINTF(un, "timed out\n"); | 510 | MUE_PRINTF(un, "timed out\n"); | |
511 | return; | 511 | return; | |
512 | } | 512 | } | |
513 | } | 513 | } | |
514 | } | 514 | } | |
515 | 515 | |||
516 | static void | 516 | static void | |
517 | mue_init_ltm(struct usbnet *un) | 517 | mue_init_ltm(struct usbnet *un) | |
518 | { | 518 | { | |
519 | uint32_t idx[MUE_NUM_LTM_INDEX] = { 0, 0, 0, 0, 0, 0 }; | 519 | uint32_t idx[MUE_NUM_LTM_INDEX] = { 0, 0, 0, 0, 0, 0 }; | |
520 | uint8_t temp[2]; | 520 | uint8_t temp[2]; | |
521 | size_t i; | 521 | size_t i; | |
522 | 522 | |||
523 | if (mue_csr_read(un, MUE_USB_CFG1) & MUE_USB_CFG1_LTM_ENABLE) { | 523 | if (mue_csr_read(un, MUE_USB_CFG1) & MUE_USB_CFG1_LTM_ENABLE) { | |
524 | if (mue_eeprom_present(un) && | 524 | if (mue_eeprom_present(un) && | |
525 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { | 525 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { | |
526 | if (temp[0] != sizeof(idx)) { | 526 | if (temp[0] != sizeof(idx)) { | |
527 | DPRINTF(un, "EEPROM: unexpected size\n"); | 527 | DPRINTF(un, "EEPROM: unexpected size\n"); | |
528 | goto done; | 528 | goto done; | |
529 | } | 529 | } | |
530 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, | 530 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, | |
531 | sizeof(idx))) { | 531 | sizeof(idx))) { | |
532 | DPRINTF(un, "EEPROM: failed to read\n"); | 532 | DPRINTF(un, "EEPROM: failed to read\n"); | |
533 | goto done; | 533 | goto done; | |
534 | } | 534 | } | |
535 | DPRINTF(un, "success\n"); | 535 | DPRINTF(un, "success\n"); | |
536 | } else if (mue_read_otp(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0) { | 536 | } else if (mue_read_otp(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0) { | |
537 | if (temp[0] != sizeof(idx)) { | 537 | if (temp[0] != sizeof(idx)) { | |
538 | DPRINTF(un, "OTP: unexpected size\n"); | 538 | DPRINTF(un, "OTP: unexpected size\n"); | |
539 | goto done; | 539 | goto done; | |
540 | } | 540 | } | |
541 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, | 541 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, | |
542 | sizeof(idx))) { | 542 | sizeof(idx))) { | |
543 | DPRINTF(un, "OTP: failed to read\n"); | 543 | DPRINTF(un, "OTP: failed to read\n"); | |
544 | goto done; | 544 | goto done; | |
545 | } | 545 | } | |
546 | DPRINTF(un, "success\n"); | 546 | DPRINTF(un, "success\n"); | |
547 | } else | 547 | } else | |
548 | DPRINTF(un, "nothing to do\n"); | 548 | DPRINTF(un, "nothing to do\n"); | |
549 | } else | 549 | } else | |
550 | DPRINTF(un, "nothing to do\n"); | 550 | DPRINTF(un, "nothing to do\n"); | |
551 | done: | 551 | done: | |
552 | for (i = 0; i < __arraycount(idx); i++) | 552 | for (i = 0; i < __arraycount(idx); i++) | |
553 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); | 553 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); | |
554 | } | 554 | } | |
555 | 555 | |||
556 | static int | 556 | static int | |
557 | mue_chip_init(struct usbnet *un) | 557 | mue_chip_init(struct usbnet *un) | |
558 | { | 558 | { | |
559 | uint32_t val; | 559 | uint32_t val; | |
560 | 560 | |||
561 | if ((un->un_flags & LAN7500) && | 561 | if ((un->un_flags & LAN7500) && | |
562 | MUE_WAIT_SET(un, MUE_PMT_CTL, MUE_PMT_CTL_READY, 0)) { | 562 | MUE_WAIT_SET(un, MUE_PMT_CTL, MUE_PMT_CTL_READY, 0)) { | |
563 | MUE_PRINTF(un, "not ready\n"); | 563 | MUE_PRINTF(un, "not ready\n"); | |
564 | return ETIMEDOUT; | 564 | return ETIMEDOUT; | |
565 | } | 565 | } | |
566 | 566 | |||
567 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); | 567 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); | |
568 | if (MUE_WAIT_CLR(un, MUE_HW_CFG, MUE_HW_CFG_LRST, 0)) { | 568 | if (MUE_WAIT_CLR(un, MUE_HW_CFG, MUE_HW_CFG_LRST, 0)) { | |
569 | MUE_PRINTF(un, "timed out\n"); | 569 | MUE_PRINTF(un, "timed out\n"); | |
570 | return ETIMEDOUT; | 570 | return ETIMEDOUT; | |
571 | } | 571 | } | |
572 | 572 | |||
573 | /* Respond to the IN token with a NAK. */ | 573 | /* Respond to the IN token with a NAK. */ | |
574 | if (un->un_flags & LAN7500) | 574 | if (un->un_flags & LAN7500) | |
575 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); | 575 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); | |
576 | else | 576 | else | |
577 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); | 577 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); | |
578 | 578 | |||
579 | if (un->un_flags & LAN7500) { | 579 | if (un->un_flags & LAN7500) { | |
580 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | 580 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | |
581 | val = MUE_7500_HS_RX_BUFSIZE / | 581 | val = MUE_7500_HS_RX_BUFSIZE / | |
582 | MUE_HS_USB_PKT_SIZE; | 582 | MUE_HS_USB_PKT_SIZE; | |
583 | else | 583 | else | |
584 | val = MUE_7500_FS_RX_BUFSIZE / | 584 | val = MUE_7500_FS_RX_BUFSIZE / | |
585 | MUE_FS_USB_PKT_SIZE; | 585 | MUE_FS_USB_PKT_SIZE; | |
586 | mue_csr_write(un, MUE_7500_BURST_CAP, val); | 586 | mue_csr_write(un, MUE_7500_BURST_CAP, val); | |
587 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, | 587 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, | |
588 | MUE_7500_DEFAULT_BULKIN_DELAY); | 588 | MUE_7500_DEFAULT_BULKIN_DELAY); | |
589 | 589 | |||
590 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BCE | MUE_HW_CFG_MEF); | 590 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BCE | MUE_HW_CFG_MEF); | |
591 | 591 | |||
592 | /* Set FIFO sizes. */ | 592 | /* Set FIFO sizes. */ | |
593 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; | 593 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; | |
594 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); | 594 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); | |
595 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; | 595 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; | |
596 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); | 596 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); | |
597 | } else { | 597 | } else { | |
598 | /* Init LTM. */ | 598 | /* Init LTM. */ | |
599 | mue_init_ltm(un); | 599 | mue_init_ltm(un); | |
600 | 600 | |||
601 | val = MUE_7800_RX_BUFSIZE; | 601 | val = MUE_7800_RX_BUFSIZE; | |
602 | switch (un->un_udev->ud_speed) { | 602 | switch (un->un_udev->ud_speed) { | |
603 | case USB_SPEED_SUPER: | 603 | case USB_SPEED_SUPER: | |
604 | val /= MUE_SS_USB_PKT_SIZE; | 604 | val /= MUE_SS_USB_PKT_SIZE; | |
605 | break; | 605 | break; | |
606 | case USB_SPEED_HIGH: | 606 | case USB_SPEED_HIGH: | |
607 | val /= MUE_HS_USB_PKT_SIZE; | 607 | val /= MUE_HS_USB_PKT_SIZE; | |
608 | break; | 608 | break; | |
609 | default: | 609 | default: | |
610 | val /= MUE_FS_USB_PKT_SIZE; | 610 | val /= MUE_FS_USB_PKT_SIZE; | |
611 | break; | 611 | break; | |
612 | } | 612 | } | |
613 | mue_csr_write(un, MUE_7800_BURST_CAP, val); | 613 | mue_csr_write(un, MUE_7800_BURST_CAP, val); | |
614 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, | 614 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, | |
615 | MUE_7800_DEFAULT_BULKIN_DELAY); | 615 | MUE_7800_DEFAULT_BULKIN_DELAY); | |
616 | 616 | |||
617 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); | 617 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); | |
618 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); | 618 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); | |
619 | 619 | |||
620 | /* | 620 | /* | |
621 | * Set FCL's RX and TX FIFO sizes: according to data sheet this | 621 | * Set FCL's RX and TX FIFO sizes: according to data sheet this | |
622 | * is already the default value. But we initialize it to the | 622 | * is already the default value. But we initialize it to the | |
623 | * same value anyways, as that's what the Linux driver does. | 623 | * same value anyways, as that's what the Linux driver does. | |
624 | */ | 624 | */ | |
625 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; | 625 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; | |
626 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); | 626 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); | |
627 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; | 627 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; | |
628 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); | 628 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); | |
629 | } | 629 | } | |
630 | 630 | |||
631 | /* Enabling interrupts. */ | 631 | /* Enabling interrupts. */ | |
632 | mue_csr_write(un, MUE_INT_STATUS, ~0); | 632 | mue_csr_write(un, MUE_INT_STATUS, ~0); | |
633 | 633 | |||
634 | mue_csr_write(un, (un->un_flags & LAN7500) ? | 634 | mue_csr_write(un, (un->un_flags & LAN7500) ? | |
635 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); | 635 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); | |
636 | mue_csr_write(un, MUE_FLOW, 0); | 636 | mue_csr_write(un, MUE_FLOW, 0); | |
637 | 637 | |||
638 | /* Reset PHY. */ | 638 | /* Reset PHY. */ | |
639 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); | 639 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); | |
640 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { | 640 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { | |
641 | MUE_PRINTF(un, "PHY not ready\n"); | 641 | MUE_PRINTF(un, "PHY not ready\n"); | |
642 | return ETIMEDOUT; | 642 | return ETIMEDOUT; | |
643 | } | 643 | } | |
644 | 644 | |||
645 | /* LAN7801 only has RGMII mode. */ | 645 | /* LAN7801 only has RGMII mode. */ | |
646 | if (un->un_flags & LAN7801) | 646 | if (un->un_flags & LAN7801) | |
647 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); | 647 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); | |
648 | 648 | |||
649 | if ((un->un_flags & (LAN7500 | LAN7800)) || | 649 | if ((un->un_flags & (LAN7500 | LAN7800)) || | |
650 | !mue_eeprom_present(un)) { | 650 | !mue_eeprom_present(un)) { | |
651 | /* Allow MAC to detect speed and duplex from PHY. */ | 651 | /* Allow MAC to detect speed and duplex from PHY. */ | |
652 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | | 652 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | | |
653 | MUE_MAC_CR_AUTO_DUPLEX); | 653 | MUE_MAC_CR_AUTO_DUPLEX); | |
654 | } | 654 | } | |
655 | 655 | |||
656 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); | 656 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); | |
657 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | 657 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | |
658 | MUE_7500_FCT_TX_CTL : MUE_7800_FCT_TX_CTL, MUE_FCT_TX_CTL_EN); | 658 | MUE_7500_FCT_TX_CTL : MUE_7800_FCT_TX_CTL, MUE_FCT_TX_CTL_EN); | |
659 | 659 | |||
660 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | 660 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | |
661 | MUE_7500_FCT_RX_CTL : MUE_7800_FCT_RX_CTL, MUE_FCT_RX_CTL_EN); | 661 | MUE_7500_FCT_RX_CTL : MUE_7800_FCT_RX_CTL, MUE_FCT_RX_CTL_EN); | |
662 | 662 | |||
663 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ | 663 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ | |
664 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { | 664 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { | |
665 | MUE_CLRBIT(un, MUE_LED_CFG, MUE_LED_CFG_LED10_FUN_SEL); | 665 | MUE_CLRBIT(un, MUE_LED_CFG, MUE_LED_CFG_LED10_FUN_SEL); | |
666 | MUE_SETBIT(un, MUE_LED_CFG, | 666 | MUE_SETBIT(un, MUE_LED_CFG, | |
667 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); | 667 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); | |
668 | } | 668 | } | |
669 | 669 | |||
670 | /* XXX We assume two LEDs at least when EEPROM is missing. */ | 670 | /* XXX We assume two LEDs at least when EEPROM is missing. */ | |
671 | if (un->un_flags & LAN7800 && | 671 | if (un->un_flags & LAN7800 && | |
672 | !mue_eeprom_present(un)) | 672 | !mue_eeprom_present(un)) | |
673 | MUE_SETBIT(un, MUE_HW_CFG, | 673 | MUE_SETBIT(un, MUE_HW_CFG, | |
674 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); | 674 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); | |
675 | 675 | |||
676 | return 0; | 676 | return 0; | |
677 | } | 677 | } | |
678 | 678 | |||
679 | static void | 679 | static void | |
680 | mue_set_macaddr(struct usbnet *un) | 680 | mue_set_macaddr(struct usbnet *un) | |
681 | { | 681 | { | |
682 | struct ifnet * const ifp = usbnet_ifp(un); | 682 | struct ifnet * const ifp = usbnet_ifp(un); | |
683 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | 683 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | |
684 | uint32_t lo, hi; | 684 | uint32_t lo, hi; | |
685 | 685 | |||
686 | lo = MUE_ENADDR_LO(enaddr); | 686 | lo = MUE_ENADDR_LO(enaddr); | |
687 | hi = MUE_ENADDR_HI(enaddr); | 687 | hi = MUE_ENADDR_HI(enaddr); | |
688 | 688 | |||
689 | mue_csr_write(un, MUE_RX_ADDRL, lo); | 689 | mue_csr_write(un, MUE_RX_ADDRL, lo); | |
690 | mue_csr_write(un, MUE_RX_ADDRH, hi); | 690 | mue_csr_write(un, MUE_RX_ADDRH, hi); | |
691 | } | 691 | } | |
692 | 692 | |||
693 | static int | 693 | static int | |
694 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) | 694 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) | |
695 | { | 695 | { | |
696 | prop_data_t eaprop; | 696 | prop_data_t eaprop; | |
697 | uint32_t low, high; | 697 | uint32_t low, high; | |
698 | 698 | |||
699 | if (!(un->un_flags & LAN7500)) { | 699 | if (!(un->un_flags & LAN7500)) { | |
700 | low = mue_csr_read(un, MUE_RX_ADDRL); | 700 | low = mue_csr_read(un, MUE_RX_ADDRL); | |
701 | high = mue_csr_read(un, MUE_RX_ADDRH); | 701 | high = mue_csr_read(un, MUE_RX_ADDRH); | |
702 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); | 702 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); | |
703 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); | 703 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); | |
704 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); | 704 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); | |
705 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); | 705 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); | |
706 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); | 706 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); | |
707 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); | 707 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); | |
708 | if (ETHER_IS_VALID(un->un_eaddr)) | 708 | if (ETHER_IS_VALID(un->un_eaddr)) | |
709 | return 0; | 709 | return 0; | |
710 | else | 710 | else | |
711 | DPRINTF(un, "registers: %s\n", | 711 | DPRINTF(un, "registers: %s\n", | |
712 | ether_sprintf(un->un_eaddr)); | 712 | ether_sprintf(un->un_eaddr)); | |
713 | } | 713 | } | |
714 | 714 | |||
715 | if (mue_eeprom_present(un) && !mue_read_eeprom(un, un->un_eaddr, | 715 | if (mue_eeprom_present(un) && !mue_read_eeprom(un, un->un_eaddr, | |
716 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { | 716 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { | |
717 | if (ETHER_IS_VALID(un->un_eaddr)) | 717 | if (ETHER_IS_VALID(un->un_eaddr)) | |
718 | return 0; | 718 | return 0; | |
719 | else | 719 | else | |
720 | DPRINTF(un, "EEPROM: %s\n", | 720 | DPRINTF(un, "EEPROM: %s\n", | |
721 | ether_sprintf(un->un_eaddr)); | 721 | ether_sprintf(un->un_eaddr)); | |
722 | } | 722 | } | |
723 | 723 | |||
724 | if (mue_read_otp(un, un->un_eaddr, MUE_OTP_MAC_OFFSET, | 724 | if (mue_read_otp(un, un->un_eaddr, MUE_OTP_MAC_OFFSET, | |
725 | ETHER_ADDR_LEN) == 0) { | 725 | ETHER_ADDR_LEN) == 0) { | |
726 | if (ETHER_IS_VALID(un->un_eaddr)) | 726 | if (ETHER_IS_VALID(un->un_eaddr)) | |
727 | return 0; | 727 | return 0; | |
728 | else | 728 | else | |
729 | DPRINTF(un, "OTP: %s\n", | 729 | DPRINTF(un, "OTP: %s\n", | |
730 | ether_sprintf(un->un_eaddr)); | 730 | ether_sprintf(un->un_eaddr)); | |
731 | } | 731 | } | |
732 | 732 | |||
733 | /* | 733 | /* | |
734 | * Other MD methods. This should be tried only if other methods fail. | 734 | * Other MD methods. This should be tried only if other methods fail. | |
735 | * Otherwise, MAC address for internal device can be assinged to | 735 | * Otherwise, MAC address for internal device can be assinged to | |
736 | * external devices on Raspberry Pi, for example. | 736 | * external devices on Raspberry Pi, for example. | |
737 | */ | 737 | */ | |
738 | eaprop = prop_dictionary_get(dict, "mac-address"); | 738 | eaprop = prop_dictionary_get(dict, "mac-address"); | |
739 | if (eaprop != NULL) { | 739 | if (eaprop != NULL) { | |
740 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | 740 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | |
741 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | 741 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | |
742 | memcpy(un->un_eaddr, prop_data_value(eaprop), | 742 | memcpy(un->un_eaddr, prop_data_value(eaprop), | |
743 | ETHER_ADDR_LEN); | 743 | ETHER_ADDR_LEN); | |
744 | if (ETHER_IS_VALID(un->un_eaddr)) | 744 | if (ETHER_IS_VALID(un->un_eaddr)) | |
745 | return 0; | 745 | return 0; | |
746 | else | 746 | else | |
747 | DPRINTF(un, "prop_dictionary_get: %s\n", | 747 | DPRINTF(un, "prop_dictionary_get: %s\n", | |
748 | ether_sprintf(un->un_eaddr)); | 748 | ether_sprintf(un->un_eaddr)); | |
749 | } | 749 | } | |
750 | 750 | |||
751 | return 1; | 751 | return 1; | |
752 | } | 752 | } | |
753 | 753 | |||
754 | 754 | |||
755 | /* | 755 | /* | |
756 | * Probe for a Microchip chip. | 756 | * Probe for a Microchip chip. | |
757 | */ | 757 | */ | |
758 | static int | 758 | static int | |
759 | mue_match(device_t parent, cfdata_t match, void *aux) | 759 | mue_match(device_t parent, cfdata_t match, void *aux) | |
760 | { | 760 | { | |
761 | struct usb_attach_arg *uaa = aux; | 761 | struct usb_attach_arg *uaa = aux; | |
762 | 762 | |||
763 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 763 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
764 | } | 764 | } | |
765 | 765 | |||
766 | static void | 766 | static void | |
767 | mue_attach(device_t parent, device_t self, void *aux) | 767 | mue_attach(device_t parent, device_t self, void *aux) | |
768 | { | 768 | { | |
769 | USBNET_MII_DECL_DEFAULT(unm); | 769 | USBNET_MII_DECL_DEFAULT(unm); | |
770 | struct usbnet * const un = device_private(self); | 770 | struct usbnet * const un = device_private(self); | |
771 | prop_dictionary_t dict = device_properties(self); | 771 | prop_dictionary_t dict = device_properties(self); | |
772 | struct usb_attach_arg *uaa = aux; | 772 | struct usb_attach_arg *uaa = aux; | |
773 | struct usbd_device *dev = uaa->uaa_device; | 773 | struct usbd_device *dev = uaa->uaa_device; | |
774 | usb_interface_descriptor_t *id; | 774 | usb_interface_descriptor_t *id; | |
775 | usb_endpoint_descriptor_t *ed; | 775 | usb_endpoint_descriptor_t *ed; | |
776 | char *devinfop; | 776 | char *devinfop; | |
777 | usbd_status err; | 777 | usbd_status err; | |
778 | const char *descr; | 778 | const char *descr; | |
779 | uint32_t id_rev; | 779 | uint32_t id_rev; | |
780 | uint8_t i; | 780 | uint8_t i; | |
781 | unsigned rx_list_cnt, tx_list_cnt; | 781 | unsigned rx_list_cnt, tx_list_cnt; | |
782 | unsigned rx_bufsz; | 782 | unsigned rx_bufsz; | |
783 | 783 | |||
784 | aprint_naive("\n"); | 784 | aprint_naive("\n"); | |
785 | aprint_normal("\n"); | 785 | aprint_normal("\n"); | |
786 | devinfop = usbd_devinfo_alloc(dev, 0); | 786 | devinfop = usbd_devinfo_alloc(dev, 0); | |
787 | aprint_normal_dev(self, "%s\n", devinfop); | 787 | aprint_normal_dev(self, "%s\n", devinfop); | |
788 | usbd_devinfo_free(devinfop); | 788 | usbd_devinfo_free(devinfop); | |
789 | 789 | |||
790 | un->un_dev = self; | 790 | un->un_dev = self; | |
791 | un->un_udev = dev; | 791 | un->un_udev = dev; | |
792 | un->un_sc = un; | 792 | un->un_sc = un; | |
793 | un->un_ops = &mue_ops; | 793 | un->un_ops = &mue_ops; | |
794 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 794 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
795 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 795 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
796 | 796 | |||
797 | #define MUE_CONFIG_NO 1 | 797 | #define MUE_CONFIG_NO 1 | |
798 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); | 798 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); | |
799 | if (err) { | 799 | if (err) { | |
800 | aprint_error_dev(self, "failed to set configuration: %s\n", | 800 | aprint_error_dev(self, "failed to set configuration: %s\n", | |
801 | usbd_errstr(err)); | 801 | usbd_errstr(err)); | |
802 | return; | 802 | return; | |
803 | } | 803 | } | |
804 | 804 | |||
805 | #define MUE_IFACE_IDX 0 | 805 | #define MUE_IFACE_IDX 0 | |
806 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); | 806 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); | |
807 | if (err) { | 807 | if (err) { | |
808 | aprint_error_dev(self, "failed to get interface handle: %s\n", | 808 | aprint_error_dev(self, "failed to get interface handle: %s\n", | |
809 | usbd_errstr(err)); | 809 | usbd_errstr(err)); | |
810 | return; | 810 | return; | |
811 | } | 811 | } | |
812 | 812 | |||
813 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; | 813 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; | |
814 | 814 | |||
815 | /* Decide on what our bufsize will be. */ | 815 | /* Decide on what our bufsize will be. */ | |
816 | if (un->un_flags & LAN7500) { | 816 | if (un->un_flags & LAN7500) { | |
817 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | 817 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | |
818 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; | 818 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; | |
819 | rx_list_cnt = 1; | 819 | rx_list_cnt = 1; | |
820 | tx_list_cnt = 1; | 820 | tx_list_cnt = 1; | |
821 | } else { | 821 | } else { | |
822 | rx_bufsz = MUE_7800_RX_BUFSIZE; | 822 | rx_bufsz = MUE_7800_RX_BUFSIZE; | |
823 | rx_list_cnt = MUE_RX_LIST_CNT; | 823 | rx_list_cnt = MUE_RX_LIST_CNT; | |
824 | tx_list_cnt = MUE_TX_LIST_CNT; | 824 | tx_list_cnt = MUE_TX_LIST_CNT; | |
825 | } | 825 | } | |
826 | 826 | |||
827 | un->un_rx_list_cnt = rx_list_cnt; | 827 | un->un_rx_list_cnt = rx_list_cnt; | |
828 | un->un_tx_list_cnt = tx_list_cnt; | 828 | un->un_tx_list_cnt = tx_list_cnt; | |
829 | un->un_rx_bufsz = rx_bufsz; | 829 | un->un_rx_bufsz = rx_bufsz; | |
830 | un->un_tx_bufsz = MUE_TX_BUFSIZE; | 830 | un->un_tx_bufsz = MUE_TX_BUFSIZE; | |
831 | 831 | |||
832 | /* Find endpoints. */ | 832 | /* Find endpoints. */ | |
833 | id = usbd_get_interface_descriptor(un->un_iface); | 833 | id = usbd_get_interface_descriptor(un->un_iface); | |
834 | for (i = 0; i < id->bNumEndpoints; i++) { | 834 | for (i = 0; i < id->bNumEndpoints; i++) { | |
835 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 835 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
836 | if (ed == NULL) { | 836 | if (ed == NULL) { | |
837 | aprint_error_dev(self, "failed to get ep %hhd\n", i); | 837 | aprint_error_dev(self, "failed to get ep %hhd\n", i); | |
838 | return; | 838 | return; | |
839 | } | 839 | } | |
840 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 840 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
841 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 841 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
842 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 842 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
843 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 843 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
844 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 844 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
845 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 845 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
846 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 846 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
847 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 847 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
848 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 848 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
849 | } | 849 | } | |
850 | } | 850 | } | |
851 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 851 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
852 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 852 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
853 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 853 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
854 | aprint_error_dev(self, "failed to find endpoints\n"); | 854 | aprint_error_dev(self, "failed to find endpoints\n"); | |
855 | return; | 855 | return; | |
856 | } | 856 | } | |
857 | 857 | |||
858 | /* Set these up now for mue_cmd(). */ | 858 | /* Set these up now for mue_cmd(). */ | |
859 | usbnet_attach(un, "muedet"); | 859 | usbnet_attach(un, "muedet"); | |
860 | 860 | |||
861 | un->un_phyno = 1; | 861 | un->un_phyno = 1; | |
862 | 862 | |||
863 | if (mue_chip_init(un)) { | 863 | if (mue_chip_init(un)) { | |
864 | aprint_error_dev(self, "failed to initialize chip\n"); | 864 | aprint_error_dev(self, "failed to initialize chip\n"); | |
865 | return; | 865 | return; | |
866 | } | 866 | } | |
867 | 867 | |||
868 | /* A Microchip chip was detected. Inform the world. */ | 868 | /* A Microchip chip was detected. Inform the world. */ | |
869 | id_rev = mue_csr_read(un, MUE_ID_REV); | 869 | id_rev = mue_csr_read(un, MUE_ID_REV); | |
870 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; | 870 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; | |
871 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, | 871 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, | |
872 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), | 872 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), | |
873 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); | 873 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); | |
874 | 874 | |||
875 | if (mue_get_macaddr(un, dict)) { | 875 | if (mue_get_macaddr(un, dict)) { | |
876 | aprint_error_dev(self, "failed to read MAC address\n"); | 876 | aprint_error_dev(self, "failed to read MAC address\n"); | |
877 | return; | 877 | return; | |
878 | } | 878 | } | |
879 | 879 | |||
880 | struct ifnet *ifp = usbnet_ifp(un); | 880 | struct ifnet *ifp = usbnet_ifp(un); | |
881 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | | 881 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | | |
882 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | 882 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | |
883 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | 883 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | |
884 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | 884 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | |
885 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | 885 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | |
886 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | 886 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | |
887 | 887 | |||
888 | struct ethercom *ec = usbnet_ec(un); | 888 | struct ethercom *ec = usbnet_ec(un); | |
889 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 889 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
890 | #if 0 /* XXX not yet */ | 890 | #if 0 /* XXX not yet */ | |
891 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; | 891 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; | |
892 | #endif | 892 | #endif | |
893 | 893 | |||
894 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 894 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
895 | 0, &unm); | 895 | 0, &unm); | |
896 | } | 896 | } | |
897 | 897 | |||
898 | static unsigned | 898 | static unsigned | |
899 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 899 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
900 | { | 900 | { | |
901 | struct ifnet * const ifp = usbnet_ifp(un); | 901 | struct ifnet * const ifp = usbnet_ifp(un); | |
902 | struct mue_txbuf_hdr hdr; | 902 | struct mue_txbuf_hdr hdr; | |
903 | uint32_t tx_cmd_a, tx_cmd_b; | 903 | uint32_t tx_cmd_a, tx_cmd_b; | |
904 | int csum, len, rv; | 904 | int csum, len, rv; | |
905 | bool tso, ipe, tpe; | 905 | bool tso, ipe, tpe; | |
906 | 906 | |||
907 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | 907 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | |
908 | return 0; | 908 | return 0; | |
909 | 909 | |||
910 | csum = m->m_pkthdr.csum_flags; | 910 | csum = m->m_pkthdr.csum_flags; | |
911 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); | 911 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); | |
912 | ipe = csum & M_CSUM_IPv4; | 912 | ipe = csum & M_CSUM_IPv4; | |
913 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | | 913 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | | |
914 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | 914 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | |
915 | 915 | |||
916 | len = m->m_pkthdr.len; | 916 | len = m->m_pkthdr.len; | |
917 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || | 917 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || | |
918 | ( tso && len > MUE_TSO_FRAME_LEN))) { | 918 | ( tso && len > MUE_TSO_FRAME_LEN))) { | |
919 | MUE_PRINTF(un, "packet length %d\n too long", len); | 919 | MUE_PRINTF(un, "packet length %d\n too long", len); | |
920 | return 0; | 920 | return 0; | |
921 | } | 921 | } | |
922 | 922 | |||
923 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); | 923 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); | |
924 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; | 924 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; | |
925 | 925 | |||
926 | if (tso) { | 926 | if (tso) { | |
927 | tx_cmd_a |= MUE_TX_CMD_A_LSO; | 927 | tx_cmd_a |= MUE_TX_CMD_A_LSO; | |
928 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) | 928 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) | |
929 | tx_cmd_b = m->m_pkthdr.segsz; | 929 | tx_cmd_b = m->m_pkthdr.segsz; | |
930 | else | 930 | else | |
931 | tx_cmd_b = MUE_TX_MSS_MIN; | 931 | tx_cmd_b = MUE_TX_MSS_MIN; | |
932 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; | 932 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; | |
933 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); | 933 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); | |
934 | rv = mue_prepare_tso(un, m); | 934 | rv = mue_prepare_tso(un, m); | |
935 | if (__predict_false(rv)) | 935 | if (__predict_false(rv)) | |
936 | return 0; | 936 | return 0; | |
937 | } else { | 937 | } else { | |
938 | if (ipe) | 938 | if (ipe) | |
939 | tx_cmd_a |= MUE_TX_CMD_A_IPE; | 939 | tx_cmd_a |= MUE_TX_CMD_A_IPE; | |
940 | if (tpe) | 940 | if (tpe) | |
941 | tx_cmd_a |= MUE_TX_CMD_A_TPE; | 941 | tx_cmd_a |= MUE_TX_CMD_A_TPE; | |
942 | tx_cmd_b = 0; | 942 | tx_cmd_b = 0; | |
943 | } | 943 | } | |
944 | 944 | |||
945 | hdr.tx_cmd_a = htole32(tx_cmd_a); | 945 | hdr.tx_cmd_a = htole32(tx_cmd_a); | |
946 | hdr.tx_cmd_b = htole32(tx_cmd_b); | 946 | hdr.tx_cmd_b = htole32(tx_cmd_b); | |
947 | 947 | |||
948 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | 948 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | |
949 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); | 949 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); | |
950 | 950 | |||
951 | return len + sizeof(hdr); | 951 | return len + sizeof(hdr); | |
952 | } | 952 | } | |
953 | 953 | |||
954 | /* | 954 | /* | |
955 | * L3 length field should be cleared. | 955 | * L3 length field should be cleared. | |
956 | */ | 956 | */ | |
957 | static int | 957 | static int | |
958 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) | 958 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) | |
959 | { | 959 | { | |
960 | struct ether_header *eh; | 960 | struct ether_header *eh; | |
961 | struct ip *ip; | 961 | struct ip *ip; | |
962 | struct ip6_hdr *ip6; | 962 | struct ip6_hdr *ip6; | |
963 | uint16_t type, len = 0; | 963 | uint16_t type, len = 0; | |
964 | int off; | 964 | int off; | |
965 | 965 | |||
966 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | 966 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | |
967 | eh = mtod(m, struct ether_header *); | 967 | eh = mtod(m, struct ether_header *); | |
968 | type = eh->ether_type; | 968 | type = eh->ether_type; | |
969 | } else | 969 | } else | |
970 | m_copydata(m, offsetof(struct ether_header, ether_type), | 970 | m_copydata(m, offsetof(struct ether_header, ether_type), | |
971 | sizeof(type), &type); | 971 | sizeof(type), &type); | |
972 | switch (type = htons(type)) { | 972 | switch (type = htons(type)) { | |
973 | case ETHERTYPE_IP: | 973 | case ETHERTYPE_IP: | |
974 | case ETHERTYPE_IPV6: | 974 | case ETHERTYPE_IPV6: | |
975 | off = ETHER_HDR_LEN; | 975 | off = ETHER_HDR_LEN; | |
976 | break; | 976 | break; | |
977 | case ETHERTYPE_VLAN: | 977 | case ETHERTYPE_VLAN: | |
978 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | 978 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | |
979 | break; | 979 | break; | |
980 | default: | 980 | default: | |
981 | return EINVAL; | 981 | return EINVAL; | |
982 | } | 982 | } | |
983 | 983 | |||
984 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { | 984 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { | |
985 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { | 985 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { | |
986 | ip = (void *)(mtod(m, char *) + off); | 986 | ip = (void *)(mtod(m, char *) + off); | |
987 | ip->ip_len = 0; | 987 | ip->ip_len = 0; | |
988 | } else | 988 | } else | |
989 | m_copyback(m, off + offsetof(struct ip, ip_len), | 989 | m_copyback(m, off + offsetof(struct ip, ip_len), | |
990 | sizeof(len), &len); | 990 | sizeof(len), &len); | |
991 | } else { | 991 | } else { | |
992 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { | 992 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { | |
993 | ip6 = (void *)(mtod(m, char *) + off); | 993 | ip6 = (void *)(mtod(m, char *) + off); | |
994 | ip6->ip6_plen = 0; | 994 | ip6->ip6_plen = 0; | |
995 | } else | 995 | } else | |
996 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), | 996 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), | |
997 | sizeof(len), &len); | 997 | sizeof(len), &len); | |
998 | } | 998 | } | |
999 | return 0; | 999 | return 0; | |
1000 | } | 1000 | } | |
1001 | 1001 | |||
1002 | static void | 1002 | static void | |
1003 | mue_uno_mcast(struct ifnet *ifp) | 1003 | mue_uno_mcast(struct ifnet *ifp) | |
1004 | { | 1004 | { | |
1005 | struct usbnet *un = ifp->if_softc; | 1005 | struct usbnet *un = ifp->if_softc; | |
1006 | struct ethercom *ec = usbnet_ec(un); | 1006 | struct ethercom *ec = usbnet_ec(un); | |
1007 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | 1007 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | |
1008 | struct ether_multi *enm; | 1008 | struct ether_multi *enm; | |
1009 | struct ether_multistep step; | 1009 | struct ether_multistep step; | |
1010 | uint32_t pfiltbl[MUE_NUM_ADDR_FILTX][2]; | 1010 | uint32_t pfiltbl[MUE_NUM_ADDR_FILTX][2]; | |
1011 | uint32_t hashtbl[MUE_DP_SEL_VHF_HASH_LEN]; | 1011 | uint32_t hashtbl[MUE_DP_SEL_VHF_HASH_LEN]; | |
1012 | uint32_t reg, rxfilt, h, hireg, loreg; | 1012 | uint32_t reg, rxfilt, h, hireg, loreg; | |
1013 | size_t i; | 1013 | size_t i; | |
1014 | 1014 | |||
1015 | if (usbnet_isdying(un)) | 1015 | if (usbnet_isdying(un)) | |
1016 | return; | 1016 | return; | |
1017 | 1017 | |||
1018 | /* Clear perfect filter and hash tables. */ | 1018 | /* Clear perfect filter and hash tables. */ | |
1019 | memset(pfiltbl, 0, sizeof(pfiltbl)); | 1019 | memset(pfiltbl, 0, sizeof(pfiltbl)); | |
1020 | memset(hashtbl, 0, sizeof(hashtbl)); | 1020 | memset(hashtbl, 0, sizeof(hashtbl)); | |
1021 | 1021 | |||
1022 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | 1022 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | |
1023 | rxfilt = mue_csr_read(un, reg); | 1023 | rxfilt = mue_csr_read(un, reg); | |
1024 | rxfilt &= ~(MUE_RFE_CTL_PERFECT | MUE_RFE_CTL_MULTICAST_HASH | | 1024 | rxfilt &= ~(MUE_RFE_CTL_PERFECT | MUE_RFE_CTL_MULTICAST_HASH | | |
1025 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); | 1025 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); | |
1026 | 1026 | |||
1027 | /* Always accept broadcast frames. */ | 1027 | /* Always accept broadcast frames. */ | |
1028 | rxfilt |= MUE_RFE_CTL_BROADCAST; | 1028 | rxfilt |= MUE_RFE_CTL_BROADCAST; | |
1029 | 1029 | |||
1030 | ETHER_LOCK(ec); | 1030 | ETHER_LOCK(ec); | |
1031 | if (ifp->if_flags & IFF_PROMISC) { | 1031 | if (ifp->if_flags & IFF_PROMISC) { | |
1032 | rxfilt |= MUE_RFE_CTL_UNICAST; | 1032 | rxfilt |= MUE_RFE_CTL_UNICAST; | |
1033 | allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; | 1033 | allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; | |
1034 | ec->ec_flags |= ETHER_F_ALLMULTI; | 1034 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
1035 | if (ifp->if_flags & IFF_PROMISC) | 1035 | if (ifp->if_flags & IFF_PROMISC) | |
1036 | DPRINTF(un, "promisc\n"); | 1036 | DPRINTF(un, "promisc\n"); | |
1037 | else | 1037 | else | |
1038 | DPRINTF(un, "allmulti\n"); | 1038 | DPRINTF(un, "allmulti\n"); | |
1039 | } else { | 1039 | } else { | |
1040 | /* Now program new ones. */ | 1040 | /* Now program new ones. */ | |
1041 | pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; | 1041 | pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; | |
1042 | pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); | 1042 | pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); | |
1043 | i = 1; | 1043 | i = 1; | |
1044 | ETHER_FIRST_MULTI(step, ec, enm); | 1044 | ETHER_FIRST_MULTI(step, ec, enm); | |
1045 | while (enm != NULL) { | 1045 | while (enm != NULL) { | |
1046 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 1046 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
1047 | ETHER_ADDR_LEN)) { | 1047 | ETHER_ADDR_LEN)) { | |
1048 | memset(pfiltbl, 0, sizeof(pfiltbl)); | 1048 | memset(pfiltbl, 0, sizeof(pfiltbl)); | |
1049 | memset(hashtbl, 0, sizeof(hashtbl)); | 1049 | memset(hashtbl, 0, sizeof(hashtbl)); | |
1050 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; | 1050 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; | |
1051 | goto allmulti; | 1051 | goto allmulti; | |
1052 | } | 1052 | } | |
1053 | if (i < MUE_NUM_ADDR_FILTX) { | 1053 | if (i < MUE_NUM_ADDR_FILTX) { | |
1054 | /* Use perfect address table if possible. */ | 1054 | /* Use perfect address table if possible. */ | |
1055 | pfiltbl[i][0] = MUE_ENADDR_HI(enm->enm_addrlo) | | 1055 | pfiltbl[i][0] = MUE_ENADDR_HI(enm->enm_addrlo) | | |
1056 | MUE_ADDR_FILTX_VALID; | 1056 | MUE_ADDR_FILTX_VALID; | |
1057 | pfiltbl[i][1] = MUE_ENADDR_LO(enm->enm_addrlo); | 1057 | pfiltbl[i][1] = MUE_ENADDR_LO(enm->enm_addrlo); | |
1058 | } else { | 1058 | } else { | |
1059 | /* Otherwise, use hash table. */ | 1059 | /* Otherwise, use hash table. */ | |
1060 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; | 1060 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; | |
1061 | h = (ether_crc32_be(enm->enm_addrlo, | 1061 | h = (ether_crc32_be(enm->enm_addrlo, | |
1062 | ETHER_ADDR_LEN) >> 23) & 0x1ff; | 1062 | ETHER_ADDR_LEN) >> 23) & 0x1ff; | |
1063 | hashtbl[h / 32] |= 1 << (h % 32); | 1063 | hashtbl[h / 32] |= 1 << (h % 32); | |
1064 | } | 1064 | } | |
1065 | i++; | 1065 | i++; | |
1066 | ETHER_NEXT_MULTI(step, enm); | 1066 | ETHER_NEXT_MULTI(step, enm); | |
1067 | } | 1067 | } | |
1068 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 1068 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
1069 | rxfilt |= MUE_RFE_CTL_PERFECT; | 1069 | rxfilt |= MUE_RFE_CTL_PERFECT; | |
1070 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) | 1070 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) | |
1071 | DPRINTF(un, "perfect filter and hash tables\n"); | 1071 | DPRINTF(un, "perfect filter and hash tables\n"); | |
1072 | else | 1072 | else | |
1073 | DPRINTF(un, "perfect filter\n"); | 1073 | DPRINTF(un, "perfect filter\n"); | |
1074 | } | 1074 | } | |
1075 | ETHER_UNLOCK(ec); | 1075 | ETHER_UNLOCK(ec); | |
1076 | 1076 | |||
1077 | for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { | 1077 | for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { | |
1078 | hireg = (un->un_flags & LAN7500) ? | 1078 | hireg = (un->un_flags & LAN7500) ? | |
1079 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); | 1079 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); | |
1080 | loreg = hireg + 4; | 1080 | loreg = hireg + 4; | |
1081 | mue_csr_write(un, hireg, 0); | 1081 | mue_csr_write(un, hireg, 0); | |
1082 | mue_csr_write(un, loreg, pfiltbl[i][1]); | 1082 | mue_csr_write(un, loreg, pfiltbl[i][1]); | |
1083 | mue_csr_write(un, hireg, pfiltbl[i][0]); | 1083 | mue_csr_write(un, hireg, pfiltbl[i][0]); | |
1084 | } | 1084 | } | |
1085 | 1085 | |||
1086 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, | 1086 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, | |
1087 | MUE_DP_SEL_VHF_HASH_LEN, hashtbl); | 1087 | MUE_DP_SEL_VHF_HASH_LEN, hashtbl); | |
1088 | 1088 | |||
1089 | mue_csr_write(un, reg, rxfilt); | 1089 | mue_csr_write(un, reg, rxfilt); | |
1090 | } | 1090 | } | |
1091 | 1091 | |||
1092 | static void | 1092 | static void | |
1093 | mue_sethwcsum_locked(struct usbnet *un) | 1093 | mue_sethwcsum_locked(struct usbnet *un) | |
1094 | { | 1094 | { | |
1095 | struct ifnet * const ifp = usbnet_ifp(un); | 1095 | struct ifnet * const ifp = usbnet_ifp(un); | |
1096 | uint32_t reg, val; | 1096 | uint32_t reg, val; | |
1097 | 1097 | |||
1098 | KASSERT(IFNET_LOCKED(ifp)); | 1098 | KASSERT(IFNET_LOCKED(ifp)); | |
1099 | 1099 | |||
1100 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | 1100 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | |
1101 | val = mue_csr_read(un, reg); | 1101 | val = mue_csr_read(un, reg); | |
1102 | 1102 | |||
1103 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { | 1103 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { | |
1104 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); | 1104 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); | |
1105 | val |= MUE_RFE_CTL_IP_COE; | 1105 | val |= MUE_RFE_CTL_IP_COE; | |
1106 | } else { | 1106 | } else { | |
1107 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); | 1107 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); | |
1108 | val &= ~MUE_RFE_CTL_IP_COE; | 1108 | val &= ~MUE_RFE_CTL_IP_COE; | |
1109 | } | 1109 | } | |
1110 | 1110 | |||
1111 | if (ifp->if_capenable & | 1111 | if (ifp->if_capenable & | |
1112 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 1112 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
1113 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | 1113 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | |
1114 | DPRINTF(un, "RX L4 hwcsum enabled\n"); | 1114 | DPRINTF(un, "RX L4 hwcsum enabled\n"); | |
1115 | val |= MUE_RFE_CTL_TCPUDP_COE; | 1115 | val |= MUE_RFE_CTL_TCPUDP_COE; | |
1116 | } else { | 1116 | } else { | |
1117 | DPRINTF(un, "RX L4 hwcsum disabled\n"); | 1117 | DPRINTF(un, "RX L4 hwcsum disabled\n"); | |
1118 | val &= ~MUE_RFE_CTL_TCPUDP_COE; | 1118 | val &= ~MUE_RFE_CTL_TCPUDP_COE; | |
1119 | } | 1119 | } | |
1120 | 1120 | |||
1121 | val &= ~MUE_RFE_CTL_VLAN_FILTER; | 1121 | val &= ~MUE_RFE_CTL_VLAN_FILTER; | |
1122 | 1122 | |||
1123 | mue_csr_write(un, reg, val); | 1123 | mue_csr_write(un, reg, val); | |
1124 | } | 1124 | } | |
1125 | 1125 | |||
1126 | static void | 1126 | static void | |
1127 | mue_setmtu_locked(struct usbnet *un) | 1127 | mue_setmtu_locked(struct usbnet *un) | |
1128 | { | 1128 | { | |
1129 | struct ifnet * const ifp = usbnet_ifp(un); | 1129 | struct ifnet * const ifp = usbnet_ifp(un); | |
1130 | uint32_t val; | 1130 | uint32_t val; | |
1131 | 1131 | |||
1132 | KASSERT(IFNET_LOCKED(ifp)); | 1132 | KASSERT(IFNET_LOCKED(ifp)); | |
1133 | 1133 | |||
1134 | /* Set the maximum frame size. */ | 1134 | /* Set the maximum frame size. */ | |
1135 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | 1135 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | |
1136 | val = mue_csr_read(un, MUE_MAC_RX); | 1136 | val = mue_csr_read(un, MUE_MAC_RX); | |
1137 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; | 1137 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; | |
1138 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); | 1138 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); | |
1139 | mue_csr_write(un, MUE_MAC_RX, val); | 1139 | mue_csr_write(un, MUE_MAC_RX, val); | |
1140 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | 1140 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | |
1141 | } | 1141 | } | |
1142 | 1142 | |||
1143 | static void | 1143 | static void | |
1144 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 1144 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
1145 | { | 1145 | { | |
1146 | struct ifnet * const ifp = usbnet_ifp(un); | 1146 | struct ifnet * const ifp = usbnet_ifp(un); | |
1147 | struct mue_rxbuf_hdr *hdrp; | 1147 | struct mue_rxbuf_hdr *hdrp; | |
1148 | uint32_t rx_cmd_a; | 1148 | uint32_t rx_cmd_a; | |
1149 | uint16_t pktlen; | 1149 | uint16_t pktlen; | |
1150 | int csum; | 1150 | int csum; | |
1151 | uint8_t *buf = c->unc_buf; | 1151 | uint8_t *buf = c->unc_buf; | |
1152 | bool v6; | 1152 | bool v6; | |
1153 | 1153 | |||
1154 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", | 1154 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", | |
1155 | total_len, un->un_rx_bufsz); | 1155 | total_len, un->un_rx_bufsz); | |
1156 | 1156 | |||
1157 | do { | 1157 | do { | |
1158 | if (__predict_false(total_len < sizeof(*hdrp))) { | 1158 | if (__predict_false(total_len < sizeof(*hdrp))) { | |
1159 | MUE_PRINTF(un, "packet length %u too short\n", total_len); | 1159 | MUE_PRINTF(un, "packet length %u too short\n", total_len); | |
1160 | if_statinc(ifp, if_ierrors); | 1160 | if_statinc(ifp, if_ierrors); | |
1161 | return; | 1161 | return; | |
1162 | } | 1162 | } | |
1163 | 1163 | |||
1164 | hdrp = (struct mue_rxbuf_hdr *)buf; | 1164 | hdrp = (struct mue_rxbuf_hdr *)buf; | |
1165 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); | 1165 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); | |
1166 | 1166 | |||
1167 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { | 1167 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { | |
1168 | /* | 1168 | /* | |
1169 | * We cannot use MUE_RX_CMD_A_RED bit here; | 1169 | * We cannot use MUE_RX_CMD_A_RED bit here; | |
1170 | * it is turned on in the cases of L3/L4 | 1170 | * it is turned on in the cases of L3/L4 | |
1171 | * checksum errors which we handle below. | 1171 | * checksum errors which we handle below. | |
1172 | */ | 1172 | */ | |
1173 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); | 1173 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); | |
1174 | if_statinc(ifp, if_ierrors); | 1174 | if_statinc(ifp, if_ierrors); | |
1175 | return; | 1175 | return; | |
1176 | } | 1176 | } | |
1177 | 1177 | |||
1178 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); | 1178 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); | |
1179 | if (un->un_flags & LAN7500) | 1179 | if (un->un_flags & LAN7500) | |
1180 | pktlen -= 2; | 1180 | pktlen -= 2; | |
1181 | 1181 | |||
1182 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || | 1182 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || | |
1183 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ | 1183 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ | |
1184 | pktlen + sizeof(*hdrp) > total_len)) { | 1184 | pktlen + sizeof(*hdrp) > total_len)) { | |
1185 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); | 1185 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); | |
1186 | if_statinc(ifp, if_ierrors); | 1186 | if_statinc(ifp, if_ierrors); | |
1187 | return; | 1187 | return; | |
1188 | } | 1188 | } | |
1189 | 1189 | |||
1190 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { | 1190 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { | |
1191 | csum = 0; | 1191 | csum = 0; | |
1192 | } else { | 1192 | } else { | |
1193 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; | 1193 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; | |
1194 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { | 1194 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { | |
1195 | case MUE_RX_CMD_A_PID_TCP: | 1195 | case MUE_RX_CMD_A_PID_TCP: | |
1196 | csum = v6 ? | 1196 | csum = v6 ? | |
1197 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; | 1197 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; | |
1198 | break; | 1198 | break; | |
1199 | case MUE_RX_CMD_A_PID_UDP: | 1199 | case MUE_RX_CMD_A_PID_UDP: | |
1200 | csum = v6 ? | 1200 | csum = v6 ? | |
1201 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; | 1201 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; | |
1202 | break; | 1202 | break; | |
1203 | case MUE_RX_CMD_A_PID_IP: | 1203 | case MUE_RX_CMD_A_PID_IP: | |
1204 | csum = v6 ? 0 : M_CSUM_IPv4; | 1204 | csum = v6 ? 0 : M_CSUM_IPv4; | |
1205 | break; | 1205 | break; | |
1206 | default: | 1206 | default: | |
1207 | csum = 0; | 1207 | csum = 0; | |
1208 | break; | 1208 | break; | |
1209 | } | 1209 | } | |
1210 | csum &= ifp->if_csum_flags_rx; | 1210 | csum &= ifp->if_csum_flags_rx; | |
1211 | if (__predict_false((csum & M_CSUM_IPv4) && | 1211 | if (__predict_false((csum & M_CSUM_IPv4) && | |
1212 | (rx_cmd_a & MUE_RX_CMD_A_ICE))) | 1212 | (rx_cmd_a & MUE_RX_CMD_A_ICE))) | |
1213 | csum |= M_CSUM_IPv4_BAD; | 1213 | csum |= M_CSUM_IPv4_BAD; | |
1214 | if (__predict_false((csum & ~M_CSUM_IPv4) && | 1214 | if (__predict_false((csum & ~M_CSUM_IPv4) && | |
1215 | (rx_cmd_a & MUE_RX_CMD_A_TCE))) | 1215 | (rx_cmd_a & MUE_RX_CMD_A_TCE))) | |
1216 | csum |= M_CSUM_TCP_UDP_BAD; | 1216 | csum |= M_CSUM_TCP_UDP_BAD; | |
1217 | } | 1217 | } | |
1218 | 1218 | |||
1219 | usbnet_enqueue(un, buf + sizeof(*hdrp), pktlen, csum, | 1219 | usbnet_enqueue(un, buf + sizeof(*hdrp), pktlen, csum, | |
1220 | 0, M_HASFCS); | 1220 | 0, M_HASFCS); | |
1221 | 1221 | |||
1222 | /* Attention: sizeof(hdr) = 10 */ | 1222 | /* Attention: sizeof(hdr) = 10 */ | |
1223 | pktlen = roundup(pktlen + sizeof(*hdrp), 4); | 1223 | pktlen = roundup(pktlen + sizeof(*hdrp), 4); | |
1224 | if (pktlen > total_len) | 1224 | if (pktlen > total_len) | |
1225 | pktlen = total_len; | 1225 | pktlen = total_len; | |
1226 | total_len -= pktlen; | 1226 | total_len -= pktlen; | |
1227 | buf += pktlen; | 1227 | buf += pktlen; | |
1228 | } while (total_len > 0); | 1228 | } while (total_len > 0); | |
1229 | } | 1229 | } | |
1230 | 1230 | |||
1231 | static int | 1231 | static int | |
1232 | mue_uno_init(struct ifnet *ifp) | 1232 | mue_uno_init(struct ifnet *ifp) | |
1233 | { | 1233 | { | |
1234 | struct usbnet * const un = ifp->if_softc; | 1234 | struct usbnet * const un = ifp->if_softc; | |
1235 | 1235 | |||
1236 | /* Cancel pending I/O and free all TX/RX buffers. */ | |||
1237 | if (ifp->if_flags & IFF_RUNNING) | |||
1238 | usbnet_stop(un, ifp, 1); | |||
1239 | ||||
1240 | mue_reset(un); | 1236 | mue_reset(un); | |
1241 | 1237 | |||
1242 | /* Set MAC address. */ | 1238 | /* Set MAC address. */ | |
1243 | mue_set_macaddr(un); | 1239 | mue_set_macaddr(un); | |
1244 | 1240 | |||
1245 | /* TCP/UDP checksum offload engines. */ | 1241 | /* TCP/UDP checksum offload engines. */ | |
1246 | mue_sethwcsum_locked(un); | 1242 | mue_sethwcsum_locked(un); | |
1247 | 1243 | |||
1248 | /* Set MTU. */ | 1244 | /* Set MTU. */ | |
1249 | mue_setmtu_locked(un); | 1245 | mue_setmtu_locked(un); | |
1250 | 1246 | |||
1251 | return usbnet_init_rx_tx(un); | 1247 | return usbnet_init_rx_tx(un); | |
1252 | } | 1248 | } | |
1253 | 1249 | |||
1254 | static int | 1250 | static int | |
1255 | mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 1251 | mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
1256 | { | 1252 | { | |
1257 | struct usbnet * const un = ifp->if_softc; | 1253 | struct usbnet * const un = ifp->if_softc; | |
1258 | 1254 | |||
1259 | switch (cmd) { | 1255 | switch (cmd) { | |
1260 | case SIOCSIFCAP: | 1256 | case SIOCSIFCAP: | |
1261 | mue_sethwcsum_locked(un); | 1257 | mue_sethwcsum_locked(un); | |
1262 | break; | 1258 | break; | |
1263 | case SIOCSIFMTU: | 1259 | case SIOCSIFMTU: | |
1264 | mue_setmtu_locked(un); | 1260 | mue_setmtu_locked(un); | |
1265 | break; | 1261 | break; | |
1266 | default: | 1262 | default: | |
1267 | break; | 1263 | break; | |
1268 | } | 1264 | } | |
1269 | 1265 | |||
1270 | return 0; | 1266 | return 0; | |
1271 | } | 1267 | } | |
1272 | 1268 | |||
1273 | static void | 1269 | static void | |
1274 | mue_reset(struct usbnet *un) | 1270 | mue_reset(struct usbnet *un) | |
1275 | { | 1271 | { | |
1276 | if (usbnet_isdying(un)) | 1272 | if (usbnet_isdying(un)) | |
1277 | return; | 1273 | return; | |
1278 | 1274 | |||
1279 | /* Wait a little while for the chip to get its brains in order. */ | 1275 | /* Wait a little while for the chip to get its brains in order. */ | |
1280 | usbd_delay_ms(un->un_udev, 1); | 1276 | usbd_delay_ms(un->un_udev, 1); | |
1281 | 1277 | |||
1282 | // mue_chip_init(un); /* XXX */ | 1278 | // mue_chip_init(un); /* XXX */ | |
1283 | } | 1279 | } | |
1284 | 1280 | |||
1285 | static void | 1281 | static void | |
1286 | mue_uno_stop(struct ifnet *ifp, int disable) | 1282 | mue_uno_stop(struct ifnet *ifp, int disable) | |
1287 | { | 1283 | { | |
1288 | struct usbnet * const un = ifp->if_softc; | 1284 | struct usbnet * const un = ifp->if_softc; | |
1289 | 1285 | |||
1290 | mue_reset(un); | 1286 | mue_reset(un); | |
1291 | } | 1287 | } | |
1292 | 1288 | |||
1293 | #ifdef _MODULE | 1289 | #ifdef _MODULE | |
1294 | #include "ioconf.c" | 1290 | #include "ioconf.c" | |
1295 | #endif | 1291 | #endif | |
1296 | 1292 | |||
1297 | USBNET_MODULE(mue) | 1293 | USBNET_MODULE(mue) |
--- src/sys/dev/usb/if_udav.c 2022/03/03 05:55:01 1.93
+++ src/sys/dev/usb/if_udav.c 2022/03/03 05:55:19 1.94
@@ -1,827 +1,823 @@ | @@ -1,827 +1,823 @@ | |||
1 | /* $NetBSD: if_udav.c,v 1.93 2022/03/03 05:55:01 riastradh Exp $ */ | 1 | /* $NetBSD: if_udav.c,v 1.94 2022/03/03 05:55:19 riastradh Exp $ */ | |
2 | /* $nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $ */ | 2 | /* $nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2003 | 5 | * Copyright (c) 2003 | |
6 | * Shingo WATANABE <nabe@nabechan.org>. All rights reserved. | 6 | * Shingo WATANABE <nabe@nabechan.org>. All rights reserved. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | 15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. Neither the name of the author nor the names of any co-contributors | 16 | * 3. Neither the name of the author nor the names of any co-contributors | |
17 | * may be used to endorse or promote products derived from this software | 17 | * may be used to endorse or promote products derived from this software | |
18 | * without specific prior written permission. | 18 | * without specific prior written permission. | |
19 | * | 19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
30 | * SUCH DAMAGE. | 30 | * SUCH DAMAGE. | |
31 | * | 31 | * | |
32 | */ | 32 | */ | |
33 | 33 | |||
34 | /* | 34 | /* | |
35 | * DM9601(DAVICOM USB to Ethernet MAC Controller with Integrated 10/100 PHY) | 35 | * DM9601(DAVICOM USB to Ethernet MAC Controller with Integrated 10/100 PHY) | |
36 | * The spec can be found at the following url. | 36 | * The spec can be found at the following url. | |
37 | * http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-F01-062202s.pdf | 37 | * http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-F01-062202s.pdf | |
38 | */ | 38 | */ | |
39 | 39 | |||
40 | /* | 40 | /* | |
41 | * TODO: | 41 | * TODO: | |
42 | * Interrupt Endpoint support | 42 | * Interrupt Endpoint support | |
43 | * External PHYs | 43 | * External PHYs | |
44 | * powerhook() support? | 44 | * powerhook() support? | |
45 | */ | 45 | */ | |
46 | 46 | |||
47 | #include <sys/cdefs.h> | 47 | #include <sys/cdefs.h> | |
48 | __KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.93 2022/03/03 05:55:01 riastradh Exp $"); | 48 | __KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.94 2022/03/03 05:55:19 riastradh Exp $"); | |
49 | 49 | |||
50 | #ifdef _KERNEL_OPT | 50 | #ifdef _KERNEL_OPT | |
51 | #include "opt_usb.h" | 51 | #include "opt_usb.h" | |
52 | #endif | 52 | #endif | |
53 | 53 | |||
54 | #include <sys/param.h> | 54 | #include <sys/param.h> | |
55 | 55 | |||
56 | #include <dev/usb/usbnet.h> | 56 | #include <dev/usb/usbnet.h> | |
57 | #include <dev/usb/if_udavreg.h> | 57 | #include <dev/usb/if_udavreg.h> | |
58 | 58 | |||
59 | /* Function declarations */ | 59 | /* Function declarations */ | |
60 | static int udav_match(device_t, cfdata_t, void *); | 60 | static int udav_match(device_t, cfdata_t, void *); | |
61 | static void udav_attach(device_t, device_t, void *); | 61 | static void udav_attach(device_t, device_t, void *); | |
62 | 62 | |||
63 | CFATTACH_DECL_NEW(udav, sizeof(struct usbnet), udav_match, udav_attach, | 63 | CFATTACH_DECL_NEW(udav, sizeof(struct usbnet), udav_match, udav_attach, | |
64 | usbnet_detach, usbnet_activate); | 64 | usbnet_detach, usbnet_activate); | |
65 | 65 | |||
66 | static void udav_chip_init(struct usbnet *); | 66 | static void udav_chip_init(struct usbnet *); | |
67 | 67 | |||
68 | static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *, | 68 | static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
69 | struct usbnet_chain *); | 69 | struct usbnet_chain *); | |
70 | static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 70 | static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
71 | static void udav_uno_stop(struct ifnet *, int); | 71 | static void udav_uno_stop(struct ifnet *, int); | |
72 | static void udav_uno_mcast(struct ifnet *); | 72 | static void udav_uno_mcast(struct ifnet *); | |
73 | static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 73 | static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
74 | static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 74 | static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
75 | static void udav_uno_mii_statchg(struct ifnet *); | 75 | static void udav_uno_mii_statchg(struct ifnet *); | |
76 | static int udav_uno_init(struct ifnet *); | 76 | static int udav_uno_init(struct ifnet *); | |
77 | static void udav_reset(struct usbnet *); | 77 | static void udav_reset(struct usbnet *); | |
78 | 78 | |||
79 | static int udav_csr_read(struct usbnet *, int, void *, int); | 79 | static int udav_csr_read(struct usbnet *, int, void *, int); | |
80 | static int udav_csr_write(struct usbnet *, int, void *, int); | 80 | static int udav_csr_write(struct usbnet *, int, void *, int); | |
81 | static int udav_csr_read1(struct usbnet *, int); | 81 | static int udav_csr_read1(struct usbnet *, int); | |
82 | static int udav_csr_write1(struct usbnet *, int, unsigned char); | 82 | static int udav_csr_write1(struct usbnet *, int, unsigned char); | |
83 | 83 | |||
84 | #if 0 | 84 | #if 0 | |
85 | static int udav_mem_read(struct usbnet *, int, void *, int); | 85 | static int udav_mem_read(struct usbnet *, int, void *, int); | |
86 | static int udav_mem_write(struct usbnet *, int, void *, int); | 86 | static int udav_mem_write(struct usbnet *, int, void *, int); | |
87 | static int udav_mem_write1(struct usbnet *, int, unsigned char); | 87 | static int udav_mem_write1(struct usbnet *, int, unsigned char); | |
88 | #endif | 88 | #endif | |
89 | 89 | |||
90 | /* Macros */ | 90 | /* Macros */ | |
91 | #ifdef UDAV_DEBUG | 91 | #ifdef UDAV_DEBUG | |
92 | #define DPRINTF(x) if (udavdebug) printf x | 92 | #define DPRINTF(x) if (udavdebug) printf x | |
93 | #define DPRINTFN(n, x) if (udavdebug >= (n)) printf x | 93 | #define DPRINTFN(n, x) if (udavdebug >= (n)) printf x | |
94 | int udavdebug = 0; | 94 | int udavdebug = 0; | |
95 | #else | 95 | #else | |
96 | #define DPRINTF(x) | 96 | #define DPRINTF(x) | |
97 | #define DPRINTFN(n, x) | 97 | #define DPRINTFN(n, x) | |
98 | #endif | 98 | #endif | |
99 | 99 | |||
100 | #define UDAV_SETBIT(un, reg, x) \ | 100 | #define UDAV_SETBIT(un, reg, x) \ | |
101 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) | (x)) | 101 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) | (x)) | |
102 | 102 | |||
103 | #define UDAV_CLRBIT(un, reg, x) \ | 103 | #define UDAV_CLRBIT(un, reg, x) \ | |
104 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) & ~(x)) | 104 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) & ~(x)) | |
105 | 105 | |||
106 | static const struct udav_type { | 106 | static const struct udav_type { | |
107 | struct usb_devno udav_dev; | 107 | struct usb_devno udav_dev; | |
108 | uint16_t udav_flags; | 108 | uint16_t udav_flags; | |
109 | #define UDAV_EXT_PHY 0x0001 | 109 | #define UDAV_EXT_PHY 0x0001 | |
110 | #define UDAV_NO_PHY 0x0002 | 110 | #define UDAV_NO_PHY 0x0002 | |
111 | } udav_devs [] = { | 111 | } udav_devs [] = { | |
112 | /* Corega USB-TXC */ | 112 | /* Corega USB-TXC */ | |
113 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC }, 0}, | 113 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC }, 0}, | |
114 | /* ShanTou ST268 USB NIC */ | 114 | /* ShanTou ST268 USB NIC */ | |
115 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268_USB_NIC }, 0}, | 115 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268_USB_NIC }, 0}, | |
116 | /* ShanTou ADM8515 */ | 116 | /* ShanTou ADM8515 */ | |
117 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515 }, 0}, | 117 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515 }, 0}, | |
118 | /* SUNRISING SR9600 */ | 118 | /* SUNRISING SR9600 */ | |
119 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_SR9600 }, 0 }, | 119 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_SR9600 }, 0 }, | |
120 | /* SUNRISING QF9700 */ | 120 | /* SUNRISING QF9700 */ | |
121 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_QF9700 }, UDAV_NO_PHY }, | 121 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_QF9700 }, UDAV_NO_PHY }, | |
122 | /* QUAN DM9601 */ | 122 | /* QUAN DM9601 */ | |
123 | {{USB_VENDOR_QUAN, USB_PRODUCT_QUAN_DM9601 }, 0}, | 123 | {{USB_VENDOR_QUAN, USB_PRODUCT_QUAN_DM9601 }, 0}, | |
124 | #if 0 | 124 | #if 0 | |
125 | /* DAVICOM DM9601 Generic? */ | 125 | /* DAVICOM DM9601 Generic? */ | |
126 | /* XXX: The following ids was obtained from the data sheet. */ | 126 | /* XXX: The following ids was obtained from the data sheet. */ | |
127 | {{ 0x0a46, 0x9601 }, 0}, | 127 | {{ 0x0a46, 0x9601 }, 0}, | |
128 | #endif | 128 | #endif | |
129 | }; | 129 | }; | |
130 | #define udav_lookup(v, p) ((const struct udav_type *)usb_lookup(udav_devs, v, p)) | 130 | #define udav_lookup(v, p) ((const struct udav_type *)usb_lookup(udav_devs, v, p)) | |
131 | 131 | |||
132 | static const struct usbnet_ops udav_ops = { | 132 | static const struct usbnet_ops udav_ops = { | |
133 | .uno_stop = udav_uno_stop, | 133 | .uno_stop = udav_uno_stop, | |
134 | .uno_mcast = udav_uno_mcast, | 134 | .uno_mcast = udav_uno_mcast, | |
135 | .uno_read_reg = udav_uno_mii_read_reg, | 135 | .uno_read_reg = udav_uno_mii_read_reg, | |
136 | .uno_write_reg = udav_uno_mii_write_reg, | 136 | .uno_write_reg = udav_uno_mii_write_reg, | |
137 | .uno_statchg = udav_uno_mii_statchg, | 137 | .uno_statchg = udav_uno_mii_statchg, | |
138 | .uno_tx_prepare = udav_uno_tx_prepare, | 138 | .uno_tx_prepare = udav_uno_tx_prepare, | |
139 | .uno_rx_loop = udav_uno_rx_loop, | 139 | .uno_rx_loop = udav_uno_rx_loop, | |
140 | .uno_init = udav_uno_init, | 140 | .uno_init = udav_uno_init, | |
141 | }; | 141 | }; | |
142 | 142 | |||
143 | /* Probe */ | 143 | /* Probe */ | |
144 | static int | 144 | static int | |
145 | udav_match(device_t parent, cfdata_t match, void *aux) | 145 | udav_match(device_t parent, cfdata_t match, void *aux) | |
146 | { | 146 | { | |
147 | struct usb_attach_arg *uaa = aux; | 147 | struct usb_attach_arg *uaa = aux; | |
148 | 148 | |||
149 | return udav_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 149 | return udav_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
150 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 150 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
151 | } | 151 | } | |
152 | 152 | |||
153 | /* Attach */ | 153 | /* Attach */ | |
154 | static void | 154 | static void | |
155 | udav_attach(device_t parent, device_t self, void *aux) | 155 | udav_attach(device_t parent, device_t self, void *aux) | |
156 | { | 156 | { | |
157 | USBNET_MII_DECL_DEFAULT(unm); | 157 | USBNET_MII_DECL_DEFAULT(unm); | |
158 | struct usbnet_mii *unmp; | 158 | struct usbnet_mii *unmp; | |
159 | struct usbnet * const un = device_private(self); | 159 | struct usbnet * const un = device_private(self); | |
160 | struct usb_attach_arg *uaa = aux; | 160 | struct usb_attach_arg *uaa = aux; | |
161 | struct usbd_device *dev = uaa->uaa_device; | 161 | struct usbd_device *dev = uaa->uaa_device; | |
162 | struct usbd_interface *iface; | 162 | struct usbd_interface *iface; | |
163 | usbd_status err; | 163 | usbd_status err; | |
164 | usb_interface_descriptor_t *id; | 164 | usb_interface_descriptor_t *id; | |
165 | usb_endpoint_descriptor_t *ed; | 165 | usb_endpoint_descriptor_t *ed; | |
166 | char *devinfop; | 166 | char *devinfop; | |
167 | int i; | 167 | int i; | |
168 | 168 | |||
169 | aprint_naive("\n"); | 169 | aprint_naive("\n"); | |
170 | aprint_normal("\n"); | 170 | aprint_normal("\n"); | |
171 | devinfop = usbd_devinfo_alloc(dev, 0); | 171 | devinfop = usbd_devinfo_alloc(dev, 0); | |
172 | aprint_normal_dev(self, "%s\n", devinfop); | 172 | aprint_normal_dev(self, "%s\n", devinfop); | |
173 | usbd_devinfo_free(devinfop); | 173 | usbd_devinfo_free(devinfop); | |
174 | 174 | |||
175 | un->un_dev = self; | 175 | un->un_dev = self; | |
176 | un->un_udev = dev; | 176 | un->un_udev = dev; | |
177 | un->un_sc = un; | 177 | un->un_sc = un; | |
178 | un->un_ops = &udav_ops; | 178 | un->un_ops = &udav_ops; | |
179 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 179 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
180 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 180 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
181 | un->un_rx_list_cnt = UDAV_RX_LIST_CNT; | 181 | un->un_rx_list_cnt = UDAV_RX_LIST_CNT; | |
182 | un->un_tx_list_cnt = UDAV_TX_LIST_CNT; | 182 | un->un_tx_list_cnt = UDAV_TX_LIST_CNT; | |
183 | un->un_rx_bufsz = UDAV_BUFSZ; | 183 | un->un_rx_bufsz = UDAV_BUFSZ; | |
184 | un->un_tx_bufsz = UDAV_BUFSZ; | 184 | un->un_tx_bufsz = UDAV_BUFSZ; | |
185 | 185 | |||
186 | /* Move the device into the configured state. */ | 186 | /* Move the device into the configured state. */ | |
187 | err = usbd_set_config_no(dev, UDAV_CONFIG_NO, 1); /* idx 0 */ | 187 | err = usbd_set_config_no(dev, UDAV_CONFIG_NO, 1); /* idx 0 */ | |
188 | if (err) { | 188 | if (err) { | |
189 | aprint_error_dev(self, "failed to set configuration" | 189 | aprint_error_dev(self, "failed to set configuration" | |
190 | ", err=%s\n", usbd_errstr(err)); | 190 | ", err=%s\n", usbd_errstr(err)); | |
191 | return; | 191 | return; | |
192 | } | 192 | } | |
193 | 193 | |||
194 | /* get control interface */ | 194 | /* get control interface */ | |
195 | err = usbd_device2interface_handle(dev, UDAV_IFACE_INDEX, &iface); | 195 | err = usbd_device2interface_handle(dev, UDAV_IFACE_INDEX, &iface); | |
196 | if (err) { | 196 | if (err) { | |
197 | aprint_error_dev(self, "failed to get interface, err=%s\n", | 197 | aprint_error_dev(self, "failed to get interface, err=%s\n", | |
198 | usbd_errstr(err)); | 198 | usbd_errstr(err)); | |
199 | return; | 199 | return; | |
200 | } | 200 | } | |
201 | 201 | |||
202 | un->un_iface = iface; | 202 | un->un_iface = iface; | |
203 | un->un_flags = udav_lookup(uaa->uaa_vendor, | 203 | un->un_flags = udav_lookup(uaa->uaa_vendor, | |
204 | uaa->uaa_product)->udav_flags; | 204 | uaa->uaa_product)->udav_flags; | |
205 | 205 | |||
206 | /* get interface descriptor */ | 206 | /* get interface descriptor */ | |
207 | id = usbd_get_interface_descriptor(un->un_iface); | 207 | id = usbd_get_interface_descriptor(un->un_iface); | |
208 | 208 | |||
209 | /* find endpoints */ | 209 | /* find endpoints */ | |
210 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | 210 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | |
211 | un->un_ed[USBNET_ENDPT_INTR] = -1; | 211 | un->un_ed[USBNET_ENDPT_INTR] = -1; | |
212 | for (i = 0; i < id->bNumEndpoints; i++) { | 212 | for (i = 0; i < id->bNumEndpoints; i++) { | |
213 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 213 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
214 | if (ed == NULL) { | 214 | if (ed == NULL) { | |
215 | aprint_error_dev(self, "couldn't get endpoint %d\n", i); | 215 | aprint_error_dev(self, "couldn't get endpoint %d\n", i); | |
216 | return; | 216 | return; | |
217 | } | 217 | } | |
218 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 218 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
219 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 219 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
220 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 220 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
221 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 221 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
222 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | 222 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | |
223 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 223 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
224 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | 224 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | |
225 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 225 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
226 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 226 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
227 | } | 227 | } | |
228 | 228 | |||
229 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 229 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
230 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 230 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
231 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 231 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
232 | aprint_error_dev(self, "missing endpoint\n"); | 232 | aprint_error_dev(self, "missing endpoint\n"); | |
233 | return; | 233 | return; | |
234 | } | 234 | } | |
235 | 235 | |||
236 | /* Not supported yet. */ | 236 | /* Not supported yet. */ | |
237 | un->un_ed[USBNET_ENDPT_INTR] = 0; | 237 | un->un_ed[USBNET_ENDPT_INTR] = 0; | |
238 | 238 | |||
239 | usbnet_attach(un, "udavdet"); | 239 | usbnet_attach(un, "udavdet"); | |
240 | 240 | |||
241 | // /* reset the adapter */ | 241 | // /* reset the adapter */ | |
242 | // udav_reset(un); | 242 | // udav_reset(un); | |
243 | 243 | |||
244 | /* Get Ethernet Address */ | 244 | /* Get Ethernet Address */ | |
245 | err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN); | 245 | err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN); | |
246 | if (err) { | 246 | if (err) { | |
247 | aprint_error_dev(self, "read MAC address failed\n"); | 247 | aprint_error_dev(self, "read MAC address failed\n"); | |
248 | return; | 248 | return; | |
249 | } | 249 | } | |
250 | 250 | |||
251 | if (ISSET(un->un_flags, UDAV_NO_PHY)) | 251 | if (ISSET(un->un_flags, UDAV_NO_PHY)) | |
252 | unmp = NULL; | 252 | unmp = NULL; | |
253 | else | 253 | else | |
254 | unmp = &unm; | 254 | unmp = &unm; | |
255 | 255 | |||
256 | /* initialize interface information */ | 256 | /* initialize interface information */ | |
257 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 257 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
258 | 0, unmp); | 258 | 0, unmp); | |
259 | 259 | |||
260 | return; | 260 | return; | |
261 | } | 261 | } | |
262 | 262 | |||
263 | #if 0 | 263 | #if 0 | |
264 | /* read memory */ | 264 | /* read memory */ | |
265 | static int | 265 | static int | |
266 | udav_mem_read(struct usbnet *un, int offset, void *buf, int len) | 266 | udav_mem_read(struct usbnet *un, int offset, void *buf, int len) | |
267 | { | 267 | { | |
268 | usb_device_request_t req; | 268 | usb_device_request_t req; | |
269 | usbd_status err; | 269 | usbd_status err; | |
270 | 270 | |||
271 | DPRINTFN(0x200, | 271 | DPRINTFN(0x200, | |
272 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 272 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
273 | 273 | |||
274 | if (usbnet_isdying(un)) | 274 | if (usbnet_isdying(un)) | |
275 | return 0; | 275 | return 0; | |
276 | 276 | |||
277 | offset &= 0xffff; | 277 | offset &= 0xffff; | |
278 | len &= 0xff; | 278 | len &= 0xff; | |
279 | 279 | |||
280 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 280 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
281 | req.bRequest = UDAV_REQ_MEM_READ; | 281 | req.bRequest = UDAV_REQ_MEM_READ; | |
282 | USETW(req.wValue, 0x0000); | 282 | USETW(req.wValue, 0x0000); | |
283 | USETW(req.wIndex, offset); | 283 | USETW(req.wIndex, offset); | |
284 | USETW(req.wLength, len); | 284 | USETW(req.wLength, len); | |
285 | 285 | |||
286 | err = usbd_do_request(un->un_udev, &req, buf); | 286 | err = usbd_do_request(un->un_udev, &req, buf); | |
287 | if (err) { | 287 | if (err) { | |
288 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | 288 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | |
289 | device_xname(un->un_dev), __func__, offset, err)); | 289 | device_xname(un->un_dev), __func__, offset, err)); | |
290 | } | 290 | } | |
291 | 291 | |||
292 | return err; | 292 | return err; | |
293 | } | 293 | } | |
294 | 294 | |||
295 | /* write memory */ | 295 | /* write memory */ | |
296 | static int | 296 | static int | |
297 | udav_mem_write(struct usbnet *un, int offset, void *buf, int len) | 297 | udav_mem_write(struct usbnet *un, int offset, void *buf, int len) | |
298 | { | 298 | { | |
299 | usb_device_request_t req; | 299 | usb_device_request_t req; | |
300 | usbd_status err; | 300 | usbd_status err; | |
301 | 301 | |||
302 | DPRINTFN(0x200, | 302 | DPRINTFN(0x200, | |
303 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 303 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
304 | 304 | |||
305 | if (usbnet_isdying(un)) | 305 | if (usbnet_isdying(un)) | |
306 | return 0; | 306 | return 0; | |
307 | 307 | |||
308 | offset &= 0xffff; | 308 | offset &= 0xffff; | |
309 | len &= 0xff; | 309 | len &= 0xff; | |
310 | 310 | |||
311 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 311 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
312 | req.bRequest = UDAV_REQ_MEM_WRITE; | 312 | req.bRequest = UDAV_REQ_MEM_WRITE; | |
313 | USETW(req.wValue, 0x0000); | 313 | USETW(req.wValue, 0x0000); | |
314 | USETW(req.wIndex, offset); | 314 | USETW(req.wIndex, offset); | |
315 | USETW(req.wLength, len); | 315 | USETW(req.wLength, len); | |
316 | 316 | |||
317 | err = usbd_do_request(un->un_udev, &req, buf); | 317 | err = usbd_do_request(un->un_udev, &req, buf); | |
318 | if (err) { | 318 | if (err) { | |
319 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 319 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
320 | device_xname(un->un_dev), __func__, offset, err)); | 320 | device_xname(un->un_dev), __func__, offset, err)); | |
321 | } | 321 | } | |
322 | 322 | |||
323 | return err; | 323 | return err; | |
324 | } | 324 | } | |
325 | 325 | |||
326 | /* write memory */ | 326 | /* write memory */ | |
327 | static int | 327 | static int | |
328 | udav_mem_write1(struct usbnet *un, int offset, unsigned char ch) | 328 | udav_mem_write1(struct usbnet *un, int offset, unsigned char ch) | |
329 | { | 329 | { | |
330 | usb_device_request_t req; | 330 | usb_device_request_t req; | |
331 | usbd_status err; | 331 | usbd_status err; | |
332 | 332 | |||
333 | DPRINTFN(0x200, | 333 | DPRINTFN(0x200, | |
334 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 334 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
335 | 335 | |||
336 | if (usbnet_isdying(un)) | 336 | if (usbnet_isdying(un)) | |
337 | return 0; | 337 | return 0; | |
338 | 338 | |||
339 | offset &= 0xffff; | 339 | offset &= 0xffff; | |
340 | 340 | |||
341 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 341 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
342 | req.bRequest = UDAV_REQ_MEM_WRITE1; | 342 | req.bRequest = UDAV_REQ_MEM_WRITE1; | |
343 | USETW(req.wValue, ch); | 343 | USETW(req.wValue, ch); | |
344 | USETW(req.wIndex, offset); | 344 | USETW(req.wIndex, offset); | |
345 | USETW(req.wLength, 0x0000); | 345 | USETW(req.wLength, 0x0000); | |
346 | 346 | |||
347 | err = usbd_do_request(un->un_udev, &req, NULL); | 347 | err = usbd_do_request(un->un_udev, &req, NULL); | |
348 | if (err) { | 348 | if (err) { | |
349 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 349 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
350 | device_xname(un->un_dev), __func__, offset, err)); | 350 | device_xname(un->un_dev), __func__, offset, err)); | |
351 | } | 351 | } | |
352 | 352 | |||
353 | return err; | 353 | return err; | |
354 | } | 354 | } | |
355 | #endif | 355 | #endif | |
356 | 356 | |||
357 | /* read register(s) */ | 357 | /* read register(s) */ | |
358 | static int | 358 | static int | |
359 | udav_csr_read(struct usbnet *un, int offset, void *buf, int len) | 359 | udav_csr_read(struct usbnet *un, int offset, void *buf, int len) | |
360 | { | 360 | { | |
361 | usb_device_request_t req; | 361 | usb_device_request_t req; | |
362 | usbd_status err; | 362 | usbd_status err; | |
363 | 363 | |||
364 | if (usbnet_isdying(un)) | 364 | if (usbnet_isdying(un)) | |
365 | return USBD_IOERROR; | 365 | return USBD_IOERROR; | |
366 | 366 | |||
367 | DPRINTFN(0x200, | 367 | DPRINTFN(0x200, | |
368 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 368 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
369 | 369 | |||
370 | offset &= 0xff; | 370 | offset &= 0xff; | |
371 | len &= 0xff; | 371 | len &= 0xff; | |
372 | 372 | |||
373 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 373 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
374 | req.bRequest = UDAV_REQ_REG_READ; | 374 | req.bRequest = UDAV_REQ_REG_READ; | |
375 | USETW(req.wValue, 0x0000); | 375 | USETW(req.wValue, 0x0000); | |
376 | USETW(req.wIndex, offset); | 376 | USETW(req.wIndex, offset); | |
377 | USETW(req.wLength, len); | 377 | USETW(req.wLength, len); | |
378 | 378 | |||
379 | err = usbd_do_request(un->un_udev, &req, buf); | 379 | err = usbd_do_request(un->un_udev, &req, buf); | |
380 | if (err) { | 380 | if (err) { | |
381 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | 381 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | |
382 | device_xname(un->un_dev), __func__, offset, err)); | 382 | device_xname(un->un_dev), __func__, offset, err)); | |
383 | memset(buf, 0, len); | 383 | memset(buf, 0, len); | |
384 | } | 384 | } | |
385 | 385 | |||
386 | return err; | 386 | return err; | |
387 | } | 387 | } | |
388 | 388 | |||
389 | /* write register(s) */ | 389 | /* write register(s) */ | |
390 | static int | 390 | static int | |
391 | udav_csr_write(struct usbnet *un, int offset, void *buf, int len) | 391 | udav_csr_write(struct usbnet *un, int offset, void *buf, int len) | |
392 | { | 392 | { | |
393 | usb_device_request_t req; | 393 | usb_device_request_t req; | |
394 | usbd_status err; | 394 | usbd_status err; | |
395 | 395 | |||
396 | if (usbnet_isdying(un)) | 396 | if (usbnet_isdying(un)) | |
397 | return USBD_IOERROR; | 397 | return USBD_IOERROR; | |
398 | 398 | |||
399 | DPRINTFN(0x200, | 399 | DPRINTFN(0x200, | |
400 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 400 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
401 | 401 | |||
402 | offset &= 0xff; | 402 | offset &= 0xff; | |
403 | len &= 0xff; | 403 | len &= 0xff; | |
404 | 404 | |||
405 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 405 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
406 | req.bRequest = UDAV_REQ_REG_WRITE; | 406 | req.bRequest = UDAV_REQ_REG_WRITE; | |
407 | USETW(req.wValue, 0x0000); | 407 | USETW(req.wValue, 0x0000); | |
408 | USETW(req.wIndex, offset); | 408 | USETW(req.wIndex, offset); | |
409 | USETW(req.wLength, len); | 409 | USETW(req.wLength, len); | |
410 | 410 | |||
411 | err = usbd_do_request(un->un_udev, &req, buf); | 411 | err = usbd_do_request(un->un_udev, &req, buf); | |
412 | if (err) { | 412 | if (err) { | |
413 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 413 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
414 | device_xname(un->un_dev), __func__, offset, err)); | 414 | device_xname(un->un_dev), __func__, offset, err)); | |
415 | } | 415 | } | |
416 | 416 | |||
417 | return err; | 417 | return err; | |
418 | } | 418 | } | |
419 | 419 | |||
420 | static int | 420 | static int | |
421 | udav_csr_read1(struct usbnet *un, int offset) | 421 | udav_csr_read1(struct usbnet *un, int offset) | |
422 | { | 422 | { | |
423 | uint8_t val = 0; | 423 | uint8_t val = 0; | |
424 | 424 | |||
425 | DPRINTFN(0x200, | 425 | DPRINTFN(0x200, | |
426 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 426 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
427 | 427 | |||
428 | if (usbnet_isdying(un)) | 428 | if (usbnet_isdying(un)) | |
429 | return 0; | 429 | return 0; | |
430 | 430 | |||
431 | return udav_csr_read(un, offset, &val, 1) ? 0 : val; | 431 | return udav_csr_read(un, offset, &val, 1) ? 0 : val; | |
432 | } | 432 | } | |
433 | 433 | |||
434 | /* write a register */ | 434 | /* write a register */ | |
435 | static int | 435 | static int | |
436 | udav_csr_write1(struct usbnet *un, int offset, unsigned char ch) | 436 | udav_csr_write1(struct usbnet *un, int offset, unsigned char ch) | |
437 | { | 437 | { | |
438 | usb_device_request_t req; | 438 | usb_device_request_t req; | |
439 | usbd_status err; | 439 | usbd_status err; | |
440 | 440 | |||
441 | if (usbnet_isdying(un)) | 441 | if (usbnet_isdying(un)) | |
442 | return USBD_IOERROR; | 442 | return USBD_IOERROR; | |
443 | 443 | |||
444 | DPRINTFN(0x200, | 444 | DPRINTFN(0x200, | |
445 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 445 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
446 | 446 | |||
447 | offset &= 0xff; | 447 | offset &= 0xff; | |
448 | 448 | |||
449 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 449 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
450 | req.bRequest = UDAV_REQ_REG_WRITE1; | 450 | req.bRequest = UDAV_REQ_REG_WRITE1; | |
451 | USETW(req.wValue, ch); | 451 | USETW(req.wValue, ch); | |
452 | USETW(req.wIndex, offset); | 452 | USETW(req.wIndex, offset); | |
453 | USETW(req.wLength, 0x0000); | 453 | USETW(req.wLength, 0x0000); | |
454 | 454 | |||
455 | err = usbd_do_request(un->un_udev, &req, NULL); | 455 | err = usbd_do_request(un->un_udev, &req, NULL); | |
456 | if (err) { | 456 | if (err) { | |
457 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 457 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
458 | device_xname(un->un_dev), __func__, offset, err)); | 458 | device_xname(un->un_dev), __func__, offset, err)); | |
459 | } | 459 | } | |
460 | 460 | |||
461 | return err; | 461 | return err; | |
462 | } | 462 | } | |
463 | 463 | |||
464 | static int | 464 | static int | |
465 | udav_uno_init(struct ifnet *ifp) | 465 | udav_uno_init(struct ifnet *ifp) | |
466 | { | 466 | { | |
467 | struct usbnet * const un = ifp->if_softc; | 467 | struct usbnet * const un = ifp->if_softc; | |
468 | struct mii_data * const mii = usbnet_mii(un); | 468 | struct mii_data * const mii = usbnet_mii(un); | |
469 | uint8_t eaddr[ETHER_ADDR_LEN]; | 469 | uint8_t eaddr[ETHER_ADDR_LEN]; | |
470 | int rc = 0; | 470 | int rc = 0; | |
471 | 471 | |||
472 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 472 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
473 | 473 | |||
474 | /* Cancel pending I/O and free all TX/RX buffers */ | |||
475 | if (ifp->if_flags & IFF_RUNNING) | |||
476 | usbnet_stop(un, ifp, 1); | |||
477 | ||||
478 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | 474 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | |
479 | udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); | 475 | udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); | |
480 | 476 | |||
481 | /* Initialize network control register */ | 477 | /* Initialize network control register */ | |
482 | /* Disable loopback */ | 478 | /* Disable loopback */ | |
483 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); | 479 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); | |
484 | 480 | |||
485 | /* Initialize RX control register */ | 481 | /* Initialize RX control register */ | |
486 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); | 482 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); | |
487 | 483 | |||
488 | /* If we want promiscuous mode, accept all physical frames. */ | 484 | /* If we want promiscuous mode, accept all physical frames. */ | |
489 | if (ifp->if_flags & IFF_PROMISC) | 485 | if (ifp->if_flags & IFF_PROMISC) | |
490 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 486 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
491 | else | 487 | else | |
492 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 488 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
493 | 489 | |||
494 | /* Enable RX */ | 490 | /* Enable RX */ | |
495 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); | 491 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); | |
496 | 492 | |||
497 | /* clear POWER_DOWN state of internal PHY */ | 493 | /* clear POWER_DOWN state of internal PHY */ | |
498 | UDAV_SETBIT(un, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); | 494 | UDAV_SETBIT(un, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); | |
499 | UDAV_CLRBIT(un, UDAV_GPR, UDAV_GPR_GEPIO0); | 495 | UDAV_CLRBIT(un, UDAV_GPR, UDAV_GPR_GEPIO0); | |
500 | 496 | |||
501 | if (mii && (rc = mii_mediachg(mii)) == ENXIO) | 497 | if (mii && (rc = mii_mediachg(mii)) == ENXIO) | |
502 | rc = 0; | 498 | rc = 0; | |
503 | 499 | |||
504 | if (rc != 0) { | 500 | if (rc != 0) { | |
505 | return rc; | 501 | return rc; | |
506 | } | 502 | } | |
507 | 503 | |||
508 | if (usbnet_isdying(un)) | 504 | if (usbnet_isdying(un)) | |
509 | rc = EIO; | 505 | rc = EIO; | |
510 | else | 506 | else | |
511 | rc = usbnet_init_rx_tx(un); | 507 | rc = usbnet_init_rx_tx(un); | |
512 | 508 | |||
513 | return rc; | 509 | return rc; | |
514 | } | 510 | } | |
515 | 511 | |||
516 | static void | 512 | static void | |
517 | udav_reset(struct usbnet *un) | 513 | udav_reset(struct usbnet *un) | |
518 | { | 514 | { | |
519 | 515 | |||
520 | if (usbnet_isdying(un)) | 516 | if (usbnet_isdying(un)) | |
521 | return; | 517 | return; | |
522 | 518 | |||
523 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 519 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
524 | 520 | |||
525 | udav_chip_init(un); | 521 | udav_chip_init(un); | |
526 | } | 522 | } | |
527 | 523 | |||
528 | static void | 524 | static void | |
529 | udav_chip_init(struct usbnet *un) | 525 | udav_chip_init(struct usbnet *un) | |
530 | { | 526 | { | |
531 | 527 | |||
532 | /* Select PHY */ | 528 | /* Select PHY */ | |
533 | #if 1 | 529 | #if 1 | |
534 | /* | 530 | /* | |
535 | * XXX: force select internal phy. | 531 | * XXX: force select internal phy. | |
536 | * external phy routines are not tested. | 532 | * external phy routines are not tested. | |
537 | */ | 533 | */ | |
538 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 534 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
539 | #else | 535 | #else | |
540 | if (un->un_flags & UDAV_EXT_PHY) { | 536 | if (un->un_flags & UDAV_EXT_PHY) { | |
541 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 537 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
542 | } else { | 538 | } else { | |
543 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 539 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
544 | } | 540 | } | |
545 | #endif | 541 | #endif | |
546 | 542 | |||
547 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); | 543 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); | |
548 | 544 | |||
549 | for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { | 545 | for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { | |
550 | if (usbnet_isdying(un)) | 546 | if (usbnet_isdying(un)) | |
551 | return; | 547 | return; | |
552 | if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) | 548 | if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) | |
553 | break; | 549 | break; | |
554 | delay(10); /* XXX */ | 550 | delay(10); /* XXX */ | |
555 | } | 551 | } | |
556 | delay(10000); /* XXX */ | 552 | delay(10000); /* XXX */ | |
557 | } | 553 | } | |
558 | 554 | |||
559 | #define UDAV_BITS 6 | 555 | #define UDAV_BITS 6 | |
560 | 556 | |||
561 | #define UDAV_CALCHASH(addr) \ | 557 | #define UDAV_CALCHASH(addr) \ | |
562 | (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) | 558 | (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) | |
563 | 559 | |||
564 | static void | 560 | static void | |
565 | udav_uno_mcast(struct ifnet *ifp) | 561 | udav_uno_mcast(struct ifnet *ifp) | |
566 | { | 562 | { | |
567 | struct usbnet * const un = ifp->if_softc; | 563 | struct usbnet * const un = ifp->if_softc; | |
568 | struct ethercom *ec = usbnet_ec(un); | 564 | struct ethercom *ec = usbnet_ec(un); | |
569 | struct ether_multi *enm; | 565 | struct ether_multi *enm; | |
570 | struct ether_multistep step; | 566 | struct ether_multistep step; | |
571 | uint8_t hashes[8]; | 567 | uint8_t hashes[8]; | |
572 | int h = 0; | 568 | int h = 0; | |
573 | 569 | |||
574 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 570 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
575 | 571 | |||
576 | if (usbnet_isdying(un)) | 572 | if (usbnet_isdying(un)) | |
577 | return; | 573 | return; | |
578 | 574 | |||
579 | if (ISSET(un->un_flags, UDAV_NO_PHY)) { | 575 | if (ISSET(un->un_flags, UDAV_NO_PHY)) { | |
580 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 576 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
581 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | 577 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | |
582 | return; | 578 | return; | |
583 | } | 579 | } | |
584 | 580 | |||
585 | if (ifp->if_flags & IFF_PROMISC) { | 581 | if (ifp->if_flags & IFF_PROMISC) { | |
586 | ETHER_LOCK(ec); | 582 | ETHER_LOCK(ec); | |
587 | ec->ec_flags |= ETHER_F_ALLMULTI; | 583 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
588 | ETHER_UNLOCK(ec); | 584 | ETHER_UNLOCK(ec); | |
589 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 585 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
590 | return; | 586 | return; | |
591 | } else if (ifp->if_flags & IFF_ALLMULTI) { /* XXX ??? Can't happen? */ | 587 | } else if (ifp->if_flags & IFF_ALLMULTI) { /* XXX ??? Can't happen? */ | |
592 | ETHER_LOCK(ec); | 588 | ETHER_LOCK(ec); | |
593 | allmulti: | 589 | allmulti: | |
594 | ec->ec_flags |= ETHER_F_ALLMULTI; | 590 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
595 | ETHER_UNLOCK(ec); | 591 | ETHER_UNLOCK(ec); | |
596 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 592 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
597 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | 593 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | |
598 | return; | 594 | return; | |
599 | } | 595 | } | |
600 | 596 | |||
601 | /* first, zot all the existing hash bits */ | 597 | /* first, zot all the existing hash bits */ | |
602 | memset(hashes, 0x00, sizeof(hashes)); | 598 | memset(hashes, 0x00, sizeof(hashes)); | |
603 | hashes[7] |= 0x80; /* broadcast address */ | 599 | hashes[7] |= 0x80; /* broadcast address */ | |
604 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | 600 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | |
605 | 601 | |||
606 | /* now program new ones */ | 602 | /* now program new ones */ | |
607 | ETHER_LOCK(ec); | 603 | ETHER_LOCK(ec); | |
608 | ETHER_FIRST_MULTI(step, ec, enm); | 604 | ETHER_FIRST_MULTI(step, ec, enm); | |
609 | while (enm != NULL) { | 605 | while (enm != NULL) { | |
610 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 606 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
611 | ETHER_ADDR_LEN) != 0) { | 607 | ETHER_ADDR_LEN) != 0) { | |
612 | goto allmulti; | 608 | goto allmulti; | |
613 | } | 609 | } | |
614 | 610 | |||
615 | h = UDAV_CALCHASH(enm->enm_addrlo); | 611 | h = UDAV_CALCHASH(enm->enm_addrlo); | |
616 | hashes[h>>3] |= 1 << (h & 0x7); | 612 | hashes[h>>3] |= 1 << (h & 0x7); | |
617 | ETHER_NEXT_MULTI(step, enm); | 613 | ETHER_NEXT_MULTI(step, enm); | |
618 | } | 614 | } | |
619 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 615 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
620 | ETHER_UNLOCK(ec); | 616 | ETHER_UNLOCK(ec); | |
621 | 617 | |||
622 | /* disable all multicast */ | 618 | /* disable all multicast */ | |
623 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 619 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
624 | 620 | |||
625 | /* write hash value to the register */ | 621 | /* write hash value to the register */ | |
626 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | 622 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | |
627 | } | 623 | } | |
628 | 624 | |||
629 | static unsigned | 625 | static unsigned | |
630 | udav_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 626 | udav_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
631 | { | 627 | { | |
632 | int total_len; | 628 | int total_len; | |
633 | uint8_t *buf = c->unc_buf; | 629 | uint8_t *buf = c->unc_buf; | |
634 | 630 | |||
635 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 631 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
636 | 632 | |||
637 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | 633 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | |
638 | return 0; | 634 | return 0; | |
639 | 635 | |||
640 | /* Copy the mbuf data into a contiguous buffer */ | 636 | /* Copy the mbuf data into a contiguous buffer */ | |
641 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | 637 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | |
642 | total_len = m->m_pkthdr.len; | 638 | total_len = m->m_pkthdr.len; | |
643 | if (total_len < UDAV_MIN_FRAME_LEN) { | 639 | if (total_len < UDAV_MIN_FRAME_LEN) { | |
644 | memset(buf + 2 + total_len, 0, | 640 | memset(buf + 2 + total_len, 0, | |
645 | UDAV_MIN_FRAME_LEN - total_len); | 641 | UDAV_MIN_FRAME_LEN - total_len); | |
646 | total_len = UDAV_MIN_FRAME_LEN; | 642 | total_len = UDAV_MIN_FRAME_LEN; | |
647 | } | 643 | } | |
648 | 644 | |||
649 | /* Frame length is specified in the first 2bytes of the buffer */ | 645 | /* Frame length is specified in the first 2bytes of the buffer */ | |
650 | buf[0] = (uint8_t)total_len; | 646 | buf[0] = (uint8_t)total_len; | |
651 | buf[1] = (uint8_t)(total_len >> 8); | 647 | buf[1] = (uint8_t)(total_len >> 8); | |
652 | total_len += 2; | 648 | total_len += 2; | |
653 | 649 | |||
654 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | 650 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | |
655 | __func__, total_len)); | 651 | __func__, total_len)); | |
656 | 652 | |||
657 | return total_len; | 653 | return total_len; | |
658 | } | 654 | } | |
659 | 655 | |||
660 | static void | 656 | static void | |
661 | udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 657 | udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
662 | { | 658 | { | |
663 | struct ifnet *ifp = usbnet_ifp(un); | 659 | struct ifnet *ifp = usbnet_ifp(un); | |
664 | uint8_t *buf = c->unc_buf; | 660 | uint8_t *buf = c->unc_buf; | |
665 | uint16_t pkt_len; | 661 | uint16_t pkt_len; | |
666 | uint8_t pktstat; | 662 | uint8_t pktstat; | |
667 | 663 | |||
668 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 664 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
669 | 665 | |||
670 | /* first byte in received data */ | 666 | /* first byte in received data */ | |
671 | pktstat = *buf; | 667 | pktstat = *buf; | |
672 | total_len -= sizeof(pktstat); | 668 | total_len -= sizeof(pktstat); | |
673 | buf += sizeof(pktstat); | 669 | buf += sizeof(pktstat); | |
674 | 670 | |||
675 | DPRINTF(("%s: RX Status: 0x%02x\n", device_xname(un->un_dev), pktstat)); | 671 | DPRINTF(("%s: RX Status: 0x%02x\n", device_xname(un->un_dev), pktstat)); | |
676 | 672 | |||
677 | pkt_len = UGETW(buf); | 673 | pkt_len = UGETW(buf); | |
678 | total_len -= sizeof(pkt_len); | 674 | total_len -= sizeof(pkt_len); | |
679 | buf += sizeof(pkt_len); | 675 | buf += sizeof(pkt_len); | |
680 | 676 | |||
681 | DPRINTF(("%s: RX Length: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | 677 | DPRINTF(("%s: RX Length: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | |
682 | 678 | |||
683 | if (pktstat & UDAV_RSR_LCS) { | 679 | if (pktstat & UDAV_RSR_LCS) { | |
684 | if_statinc(ifp, if_collisions); | 680 | if_statinc(ifp, if_collisions); | |
685 | return; | 681 | return; | |
686 | } | 682 | } | |
687 | 683 | |||
688 | if (pkt_len < sizeof(struct ether_header) || | 684 | if (pkt_len < sizeof(struct ether_header) || | |
689 | pkt_len > total_len || | 685 | pkt_len > total_len || | |
690 | (pktstat & UDAV_RSR_ERR)) { | 686 | (pktstat & UDAV_RSR_ERR)) { | |
691 | if_statinc(ifp, if_ierrors); | 687 | if_statinc(ifp, if_ierrors); | |
692 | return; | 688 | return; | |
693 | } | 689 | } | |
694 | 690 | |||
695 | pkt_len -= ETHER_CRC_LEN; | 691 | pkt_len -= ETHER_CRC_LEN; | |
696 | 692 | |||
697 | DPRINTF(("%s: Rx deliver: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | 693 | DPRINTF(("%s: Rx deliver: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | |
698 | 694 | |||
699 | usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); | 695 | usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); | |
700 | } | 696 | } | |
701 | 697 | |||
702 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | 698 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | |
703 | static void | 699 | static void | |
704 | udav_uno_stop(struct ifnet *ifp, int disable) | 700 | udav_uno_stop(struct ifnet *ifp, int disable) | |
705 | { | 701 | { | |
706 | struct usbnet * const un = ifp->if_softc; | 702 | struct usbnet * const un = ifp->if_softc; | |
707 | 703 | |||
708 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 704 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
709 | 705 | |||
710 | udav_reset(un); | 706 | udav_reset(un); | |
711 | } | 707 | } | |
712 | 708 | |||
713 | static int | 709 | static int | |
714 | udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 710 | udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
715 | { | 711 | { | |
716 | uint8_t data[2]; | 712 | uint8_t data[2]; | |
717 | 713 | |||
718 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | 714 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | |
719 | device_xname(un->un_dev), __func__, phy, reg)); | 715 | device_xname(un->un_dev), __func__, phy, reg)); | |
720 | 716 | |||
721 | if (usbnet_isdying(un)) { | 717 | if (usbnet_isdying(un)) { | |
722 | #ifdef DIAGNOSTIC | 718 | #ifdef DIAGNOSTIC | |
723 | printf("%s: %s: dying\n", device_xname(un->un_dev), | 719 | printf("%s: %s: dying\n", device_xname(un->un_dev), | |
724 | __func__); | 720 | __func__); | |
725 | #endif | 721 | #endif | |
726 | *val = 0; | 722 | *val = 0; | |
727 | return EINVAL; | 723 | return EINVAL; | |
728 | } | 724 | } | |
729 | 725 | |||
730 | /* XXX: one PHY only for the internal PHY */ | 726 | /* XXX: one PHY only for the internal PHY */ | |
731 | if (phy != 0) { | 727 | if (phy != 0) { | |
732 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 728 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
733 | device_xname(un->un_dev), __func__, phy)); | 729 | device_xname(un->un_dev), __func__, phy)); | |
734 | *val = 0; | 730 | *val = 0; | |
735 | return EINVAL; | 731 | return EINVAL; | |
736 | } | 732 | } | |
737 | 733 | |||
738 | /* select internal PHY and set PHY register address */ | 734 | /* select internal PHY and set PHY register address */ | |
739 | udav_csr_write1(un, UDAV_EPAR, | 735 | udav_csr_write1(un, UDAV_EPAR, | |
740 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | 736 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | |
741 | 737 | |||
742 | /* select PHY operation and start read command */ | 738 | /* select PHY operation and start read command */ | |
743 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); | 739 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); | |
744 | 740 | |||
745 | /* XXX: should be wait? */ | 741 | /* XXX: should be wait? */ | |
746 | 742 | |||
747 | /* end read command */ | 743 | /* end read command */ | |
748 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRR); | 744 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRR); | |
749 | 745 | |||
750 | /* retrieve the result from data registers */ | 746 | /* retrieve the result from data registers */ | |
751 | udav_csr_read(un, UDAV_EPDRL, data, 2); | 747 | udav_csr_read(un, UDAV_EPDRL, data, 2); | |
752 | 748 | |||
753 | *val = data[0] | (data[1] << 8); | 749 | *val = data[0] | (data[1] << 8); | |
754 | 750 | |||
755 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | 751 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | |
756 | device_xname(un->un_dev), __func__, phy, reg, *val)); | 752 | device_xname(un->un_dev), __func__, phy, reg, *val)); | |
757 | 753 | |||
758 | return 0; | 754 | return 0; | |
759 | } | 755 | } | |
760 | 756 | |||
761 | static int | 757 | static int | |
762 | udav_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 758 | udav_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
763 | { | 759 | { | |
764 | uint8_t data[2]; | 760 | uint8_t data[2]; | |
765 | 761 | |||
766 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | 762 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | |
767 | device_xname(un->un_dev), __func__, phy, reg, val)); | 763 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
768 | 764 | |||
769 | if (usbnet_isdying(un)) { | 765 | if (usbnet_isdying(un)) { | |
770 | #ifdef DIAGNOSTIC | 766 | #ifdef DIAGNOSTIC | |
771 | printf("%s: %s: dying\n", device_xname(un->un_dev), | 767 | printf("%s: %s: dying\n", device_xname(un->un_dev), | |
772 | __func__); | 768 | __func__); | |
773 | #endif | 769 | #endif | |
774 | return EIO; | 770 | return EIO; | |
775 | } | 771 | } | |
776 | 772 | |||
777 | /* XXX: one PHY only for the internal PHY */ | 773 | /* XXX: one PHY only for the internal PHY */ | |
778 | if (phy != 0) { | 774 | if (phy != 0) { | |
779 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 775 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
780 | device_xname(un->un_dev), __func__, phy)); | 776 | device_xname(un->un_dev), __func__, phy)); | |
781 | return EIO; | 777 | return EIO; | |
782 | } | 778 | } | |
783 | 779 | |||
784 | /* select internal PHY and set PHY register address */ | 780 | /* select internal PHY and set PHY register address */ | |
785 | udav_csr_write1(un, UDAV_EPAR, | 781 | udav_csr_write1(un, UDAV_EPAR, | |
786 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | 782 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | |
787 | 783 | |||
788 | /* put the value to the data registers */ | 784 | /* put the value to the data registers */ | |
789 | data[0] = val & 0xff; | 785 | data[0] = val & 0xff; | |
790 | data[1] = (val >> 8) & 0xff; | 786 | data[1] = (val >> 8) & 0xff; | |
791 | udav_csr_write(un, UDAV_EPDRL, data, 2); | 787 | udav_csr_write(un, UDAV_EPDRL, data, 2); | |
792 | 788 | |||
793 | /* select PHY operation and start write command */ | 789 | /* select PHY operation and start write command */ | |
794 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); | 790 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); | |
795 | 791 | |||
796 | /* XXX: should be wait? */ | 792 | /* XXX: should be wait? */ | |
797 | 793 | |||
798 | /* end write command */ | 794 | /* end write command */ | |
799 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRW); | 795 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRW); | |
800 | 796 | |||
801 | return 0; | 797 | return 0; | |
802 | } | 798 | } | |
803 | 799 | |||
804 | static void | 800 | static void | |
805 | udav_uno_mii_statchg(struct ifnet *ifp) | 801 | udav_uno_mii_statchg(struct ifnet *ifp) | |
806 | { | 802 | { | |
807 | struct usbnet * const un = ifp->if_softc; | 803 | struct usbnet * const un = ifp->if_softc; | |
808 | struct mii_data * const mii = usbnet_mii(un); | 804 | struct mii_data * const mii = usbnet_mii(un); | |
809 | 805 | |||
810 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | 806 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | |
811 | 807 | |||
812 | if (usbnet_isdying(un)) | 808 | if (usbnet_isdying(un)) | |
813 | return; | 809 | return; | |
814 | 810 | |||
815 | if ((mii->mii_media_status & IFM_ACTIVE) && | 811 | if ((mii->mii_media_status & IFM_ACTIVE) && | |
816 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | 812 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | |
817 | DPRINTF(("%s: %s: got link\n", | 813 | DPRINTF(("%s: %s: got link\n", | |
818 | device_xname(un->un_dev), __func__)); | 814 | device_xname(un->un_dev), __func__)); | |
819 | usbnet_set_link(un, true); | 815 | usbnet_set_link(un, true); | |
820 | } | 816 | } | |
821 | } | 817 | } | |
822 | 818 | |||
823 | #ifdef _MODULE | 819 | #ifdef _MODULE | |
824 | #include "ioconf.c" | 820 | #include "ioconf.c" | |
825 | #endif | 821 | #endif | |
826 | 822 | |||
827 | USBNET_MODULE(udav) | 823 | USBNET_MODULE(udav) |
--- src/sys/dev/usb/if_ure.c 2022/03/03 05:55:01 1.53
+++ src/sys/dev/usb/if_ure.c 2022/03/03 05:55:19 1.54
@@ -1,1128 +1,1124 @@ | @@ -1,1128 +1,1124 @@ | |||
1 | /* $NetBSD: if_ure.c,v 1.53 2022/03/03 05:55:01 riastradh Exp $ */ | 1 | /* $NetBSD: if_ure.c,v 1.54 2022/03/03 05:55:19 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_ure.c,v 1.10 2018/11/02 21:32:30 jcs Exp $ */ | 2 | /* $OpenBSD: if_ure.c,v 1.10 2018/11/02 21:32:30 jcs Exp $ */ | |
3 | 3 | |||
4 | /*- | 4 | /*- | |
5 | * Copyright (c) 2015-2016 Kevin Lo <kevlo@FreeBSD.org> | 5 | * Copyright (c) 2015-2016 Kevin Lo <kevlo@FreeBSD.org> | |
6 | * All rights reserved. | 6 | * All rights reserved. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | 15 | * documentation and/or other materials provided with the distribution. | |
16 | * | 16 | * | |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
27 | * SUCH DAMAGE. | 27 | * SUCH DAMAGE. | |
28 | */ | 28 | */ | |
29 | 29 | |||
30 | /* RealTek RTL8152/RTL8153 10/100/Gigabit USB Ethernet device */ | 30 | /* RealTek RTL8152/RTL8153 10/100/Gigabit USB Ethernet device */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | __KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.53 2022/03/03 05:55:01 riastradh Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.54 2022/03/03 05:55:19 riastradh Exp $"); | |
34 | 34 | |||
35 | #ifdef _KERNEL_OPT | 35 | #ifdef _KERNEL_OPT | |
36 | #include "opt_usb.h" | 36 | #include "opt_usb.h" | |
37 | #include "opt_inet.h" | 37 | #include "opt_inet.h" | |
38 | #endif | 38 | #endif | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/cprng.h> | 41 | #include <sys/cprng.h> | |
42 | 42 | |||
43 | #include <net/route.h> | 43 | #include <net/route.h> | |
44 | 44 | |||
45 | #include <dev/usb/usbnet.h> | 45 | #include <dev/usb/usbnet.h> | |
46 | 46 | |||
47 | #include <netinet/in_offload.h> /* XXX for in_undefer_cksum() */ | 47 | #include <netinet/in_offload.h> /* XXX for in_undefer_cksum() */ | |
48 | #ifdef INET6 | 48 | #ifdef INET6 | |
49 | #include <netinet/in.h> | 49 | #include <netinet/in.h> | |
50 | #include <netinet6/in6_offload.h> /* XXX for in6_undefer_cksum() */ | 50 | #include <netinet6/in6_offload.h> /* XXX for in6_undefer_cksum() */ | |
51 | #endif | 51 | #endif | |
52 | 52 | |||
53 | #include <dev/ic/rtl81x9reg.h> /* XXX for RTK_GMEDIASTAT */ | 53 | #include <dev/ic/rtl81x9reg.h> /* XXX for RTK_GMEDIASTAT */ | |
54 | #include <dev/usb/if_urereg.h> | 54 | #include <dev/usb/if_urereg.h> | |
55 | #include <dev/usb/if_urevar.h> | 55 | #include <dev/usb/if_urevar.h> | |
56 | 56 | |||
57 | #define URE_PRINTF(un, fmt, args...) \ | 57 | #define URE_PRINTF(un, fmt, args...) \ | |
58 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | 58 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | |
59 | 59 | |||
60 | #define URE_DEBUG | 60 | #define URE_DEBUG | |
61 | #ifdef URE_DEBUG | 61 | #ifdef URE_DEBUG | |
62 | #define DPRINTF(x) do { if (uredebug) printf x; } while (0) | 62 | #define DPRINTF(x) do { if (uredebug) printf x; } while (0) | |
63 | #define DPRINTFN(n, x) do { if (uredebug >= (n)) printf x; } while (0) | 63 | #define DPRINTFN(n, x) do { if (uredebug >= (n)) printf x; } while (0) | |
64 | int uredebug = 0; | 64 | int uredebug = 0; | |
65 | #else | 65 | #else | |
66 | #define DPRINTF(x) | 66 | #define DPRINTF(x) | |
67 | #define DPRINTFN(n, x) | 67 | #define DPRINTFN(n, x) | |
68 | #endif | 68 | #endif | |
69 | 69 | |||
70 | #define ETHER_IS_ZERO(addr) \ | 70 | #define ETHER_IS_ZERO(addr) \ | |
71 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | 71 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | |
72 | 72 | |||
73 | static const struct usb_devno ure_devs[] = { | 73 | static const struct usb_devno ure_devs[] = { | |
74 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 }, | 74 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 }, | |
75 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8153 } | 75 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8153 } | |
76 | }; | 76 | }; | |
77 | 77 | |||
78 | #define URE_BUFSZ (16 * 1024) | 78 | #define URE_BUFSZ (16 * 1024) | |
79 | 79 | |||
80 | static void ure_reset(struct usbnet *); | 80 | static void ure_reset(struct usbnet *); | |
81 | static uint32_t ure_txcsum(struct mbuf *); | 81 | static uint32_t ure_txcsum(struct mbuf *); | |
82 | static int ure_rxcsum(struct ifnet *, struct ure_rxpkt *); | 82 | static int ure_rxcsum(struct ifnet *, struct ure_rxpkt *); | |
83 | static void ure_rtl8152_init(struct usbnet *); | 83 | static void ure_rtl8152_init(struct usbnet *); | |
84 | static void ure_rtl8153_init(struct usbnet *); | 84 | static void ure_rtl8153_init(struct usbnet *); | |
85 | static void ure_disable_teredo(struct usbnet *); | 85 | static void ure_disable_teredo(struct usbnet *); | |
86 | static void ure_init_fifo(struct usbnet *); | 86 | static void ure_init_fifo(struct usbnet *); | |
87 | 87 | |||
88 | static void ure_uno_stop(struct ifnet *, int); | 88 | static void ure_uno_stop(struct ifnet *, int); | |
89 | static void ure_uno_mcast(struct ifnet *); | 89 | static void ure_uno_mcast(struct ifnet *); | |
90 | static int ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 90 | static int ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
91 | static int ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 91 | static int ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
92 | static void ure_uno_miibus_statchg(struct ifnet *); | 92 | static void ure_uno_miibus_statchg(struct ifnet *); | |
93 | static unsigned ure_uno_tx_prepare(struct usbnet *, struct mbuf *, | 93 | static unsigned ure_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
94 | struct usbnet_chain *); | 94 | struct usbnet_chain *); | |
95 | static void ure_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 95 | static void ure_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
96 | uint32_t); | 96 | uint32_t); | |
97 | static int ure_uno_init(struct ifnet *); | 97 | static int ure_uno_init(struct ifnet *); | |
98 | 98 | |||
99 | static int ure_match(device_t, cfdata_t, void *); | 99 | static int ure_match(device_t, cfdata_t, void *); | |
100 | static void ure_attach(device_t, device_t, void *); | 100 | static void ure_attach(device_t, device_t, void *); | |
101 | 101 | |||
102 | CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach, | 102 | CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach, | |
103 | usbnet_detach, usbnet_activate); | 103 | usbnet_detach, usbnet_activate); | |
104 | 104 | |||
105 | static const struct usbnet_ops ure_ops = { | 105 | static const struct usbnet_ops ure_ops = { | |
106 | .uno_stop = ure_uno_stop, | 106 | .uno_stop = ure_uno_stop, | |
107 | .uno_mcast = ure_uno_mcast, | 107 | .uno_mcast = ure_uno_mcast, | |
108 | .uno_read_reg = ure_uno_mii_read_reg, | 108 | .uno_read_reg = ure_uno_mii_read_reg, | |
109 | .uno_write_reg = ure_uno_mii_write_reg, | 109 | .uno_write_reg = ure_uno_mii_write_reg, | |
110 | .uno_statchg = ure_uno_miibus_statchg, | 110 | .uno_statchg = ure_uno_miibus_statchg, | |
111 | .uno_tx_prepare = ure_uno_tx_prepare, | 111 | .uno_tx_prepare = ure_uno_tx_prepare, | |
112 | .uno_rx_loop = ure_uno_rx_loop, | 112 | .uno_rx_loop = ure_uno_rx_loop, | |
113 | .uno_init = ure_uno_init, | 113 | .uno_init = ure_uno_init, | |
114 | }; | 114 | }; | |
115 | 115 | |||
116 | static int | 116 | static int | |
117 | ure_ctl(struct usbnet *un, uint8_t rw, uint16_t val, uint16_t index, | 117 | ure_ctl(struct usbnet *un, uint8_t rw, uint16_t val, uint16_t index, | |
118 | void *buf, int len) | 118 | void *buf, int len) | |
119 | { | 119 | { | |
120 | usb_device_request_t req; | 120 | usb_device_request_t req; | |
121 | usbd_status err; | 121 | usbd_status err; | |
122 | 122 | |||
123 | if (usbnet_isdying(un)) | 123 | if (usbnet_isdying(un)) | |
124 | return 0; | 124 | return 0; | |
125 | 125 | |||
126 | if (rw == URE_CTL_WRITE) | 126 | if (rw == URE_CTL_WRITE) | |
127 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 127 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
128 | else | 128 | else | |
129 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 129 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
130 | req.bRequest = UR_SET_ADDRESS; | 130 | req.bRequest = UR_SET_ADDRESS; | |
131 | USETW(req.wValue, val); | 131 | USETW(req.wValue, val); | |
132 | USETW(req.wIndex, index); | 132 | USETW(req.wIndex, index); | |
133 | USETW(req.wLength, len); | 133 | USETW(req.wLength, len); | |
134 | 134 | |||
135 | DPRINTFN(5, ("ure_ctl: rw %d, val %04hu, index %04hu, len %d\n", | 135 | DPRINTFN(5, ("ure_ctl: rw %d, val %04hu, index %04hu, len %d\n", | |
136 | rw, val, index, len)); | 136 | rw, val, index, len)); | |
137 | err = usbd_do_request(un->un_udev, &req, buf); | 137 | err = usbd_do_request(un->un_udev, &req, buf); | |
138 | if (err) { | 138 | if (err) { | |
139 | DPRINTF(("ure_ctl: error %d\n", err)); | 139 | DPRINTF(("ure_ctl: error %d\n", err)); | |
140 | if (rw == URE_CTL_READ) | 140 | if (rw == URE_CTL_READ) | |
141 | memset(buf, 0, len); | 141 | memset(buf, 0, len); | |
142 | return -1; | 142 | return -1; | |
143 | } | 143 | } | |
144 | 144 | |||
145 | return 0; | 145 | return 0; | |
146 | } | 146 | } | |
147 | 147 | |||
148 | static int | 148 | static int | |
149 | ure_read_mem(struct usbnet *un, uint16_t addr, uint16_t index, | 149 | ure_read_mem(struct usbnet *un, uint16_t addr, uint16_t index, | |
150 | void *buf, int len) | 150 | void *buf, int len) | |
151 | { | 151 | { | |
152 | return ure_ctl(un, URE_CTL_READ, addr, index, buf, len); | 152 | return ure_ctl(un, URE_CTL_READ, addr, index, buf, len); | |
153 | } | 153 | } | |
154 | 154 | |||
155 | static int | 155 | static int | |
156 | ure_write_mem(struct usbnet *un, uint16_t addr, uint16_t index, | 156 | ure_write_mem(struct usbnet *un, uint16_t addr, uint16_t index, | |
157 | void *buf, int len) | 157 | void *buf, int len) | |
158 | { | 158 | { | |
159 | return ure_ctl(un, URE_CTL_WRITE, addr, index, buf, len); | 159 | return ure_ctl(un, URE_CTL_WRITE, addr, index, buf, len); | |
160 | } | 160 | } | |
161 | 161 | |||
162 | static uint8_t | 162 | static uint8_t | |
163 | ure_read_1(struct usbnet *un, uint16_t reg, uint16_t index) | 163 | ure_read_1(struct usbnet *un, uint16_t reg, uint16_t index) | |
164 | { | 164 | { | |
165 | uint32_t val; | 165 | uint32_t val; | |
166 | uint8_t temp[4]; | 166 | uint8_t temp[4]; | |
167 | uint8_t shift; | 167 | uint8_t shift; | |
168 | 168 | |||
169 | shift = (reg & 3) << 3; | 169 | shift = (reg & 3) << 3; | |
170 | reg &= ~3; | 170 | reg &= ~3; | |
171 | 171 | |||
172 | ure_read_mem(un, reg, index, &temp, 4); | 172 | ure_read_mem(un, reg, index, &temp, 4); | |
173 | val = UGETDW(temp); | 173 | val = UGETDW(temp); | |
174 | val >>= shift; | 174 | val >>= shift; | |
175 | 175 | |||
176 | return val & 0xff; | 176 | return val & 0xff; | |
177 | } | 177 | } | |
178 | 178 | |||
179 | static uint16_t | 179 | static uint16_t | |
180 | ure_read_2(struct usbnet *un, uint16_t reg, uint16_t index) | 180 | ure_read_2(struct usbnet *un, uint16_t reg, uint16_t index) | |
181 | { | 181 | { | |
182 | uint32_t val; | 182 | uint32_t val; | |
183 | uint8_t temp[4]; | 183 | uint8_t temp[4]; | |
184 | uint8_t shift; | 184 | uint8_t shift; | |
185 | 185 | |||
186 | shift = (reg & 2) << 3; | 186 | shift = (reg & 2) << 3; | |
187 | reg &= ~3; | 187 | reg &= ~3; | |
188 | 188 | |||
189 | ure_read_mem(un, reg, index, &temp, 4); | 189 | ure_read_mem(un, reg, index, &temp, 4); | |
190 | val = UGETDW(temp); | 190 | val = UGETDW(temp); | |
191 | val >>= shift; | 191 | val >>= shift; | |
192 | 192 | |||
193 | return val & 0xffff; | 193 | return val & 0xffff; | |
194 | } | 194 | } | |
195 | 195 | |||
196 | static uint32_t | 196 | static uint32_t | |
197 | ure_read_4(struct usbnet *un, uint16_t reg, uint16_t index) | 197 | ure_read_4(struct usbnet *un, uint16_t reg, uint16_t index) | |
198 | { | 198 | { | |
199 | uint8_t temp[4]; | 199 | uint8_t temp[4]; | |
200 | 200 | |||
201 | ure_read_mem(un, reg, index, &temp, 4); | 201 | ure_read_mem(un, reg, index, &temp, 4); | |
202 | return UGETDW(temp); | 202 | return UGETDW(temp); | |
203 | } | 203 | } | |
204 | 204 | |||
205 | static int | 205 | static int | |
206 | ure_write_1(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | 206 | ure_write_1(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | |
207 | { | 207 | { | |
208 | uint16_t byen; | 208 | uint16_t byen; | |
209 | uint8_t temp[4]; | 209 | uint8_t temp[4]; | |
210 | uint8_t shift; | 210 | uint8_t shift; | |
211 | 211 | |||
212 | byen = URE_BYTE_EN_BYTE; | 212 | byen = URE_BYTE_EN_BYTE; | |
213 | shift = reg & 3; | 213 | shift = reg & 3; | |
214 | val &= 0xff; | 214 | val &= 0xff; | |
215 | 215 | |||
216 | if (reg & 3) { | 216 | if (reg & 3) { | |
217 | byen <<= shift; | 217 | byen <<= shift; | |
218 | val <<= (shift << 3); | 218 | val <<= (shift << 3); | |
219 | reg &= ~3; | 219 | reg &= ~3; | |
220 | } | 220 | } | |
221 | 221 | |||
222 | USETDW(temp, val); | 222 | USETDW(temp, val); | |
223 | return ure_write_mem(un, reg, index | byen, &temp, 4); | 223 | return ure_write_mem(un, reg, index | byen, &temp, 4); | |
224 | } | 224 | } | |
225 | 225 | |||
226 | static int | 226 | static int | |
227 | ure_write_2(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | 227 | ure_write_2(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | |
228 | { | 228 | { | |
229 | uint16_t byen; | 229 | uint16_t byen; | |
230 | uint8_t temp[4]; | 230 | uint8_t temp[4]; | |
231 | uint8_t shift; | 231 | uint8_t shift; | |
232 | 232 | |||
233 | byen = URE_BYTE_EN_WORD; | 233 | byen = URE_BYTE_EN_WORD; | |
234 | shift = reg & 2; | 234 | shift = reg & 2; | |
235 | val &= 0xffff; | 235 | val &= 0xffff; | |
236 | 236 | |||
237 | if (reg & 2) { | 237 | if (reg & 2) { | |
238 | byen <<= shift; | 238 | byen <<= shift; | |
239 | val <<= (shift << 3); | 239 | val <<= (shift << 3); | |
240 | reg &= ~3; | 240 | reg &= ~3; | |
241 | } | 241 | } | |
242 | 242 | |||
243 | USETDW(temp, val); | 243 | USETDW(temp, val); | |
244 | return ure_write_mem(un, reg, index | byen, &temp, 4); | 244 | return ure_write_mem(un, reg, index | byen, &temp, 4); | |
245 | } | 245 | } | |
246 | 246 | |||
247 | static int | 247 | static int | |
248 | ure_write_4(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | 248 | ure_write_4(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | |
249 | { | 249 | { | |
250 | uint8_t temp[4]; | 250 | uint8_t temp[4]; | |
251 | 251 | |||
252 | USETDW(temp, val); | 252 | USETDW(temp, val); | |
253 | return ure_write_mem(un, reg, index | URE_BYTE_EN_DWORD, &temp, 4); | 253 | return ure_write_mem(un, reg, index | URE_BYTE_EN_DWORD, &temp, 4); | |
254 | } | 254 | } | |
255 | 255 | |||
256 | static uint16_t | 256 | static uint16_t | |
257 | ure_ocp_reg_read(struct usbnet *un, uint16_t addr) | 257 | ure_ocp_reg_read(struct usbnet *un, uint16_t addr) | |
258 | { | 258 | { | |
259 | uint16_t reg; | 259 | uint16_t reg; | |
260 | 260 | |||
261 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | 261 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | |
262 | reg = (addr & 0x0fff) | 0xb000; | 262 | reg = (addr & 0x0fff) | 0xb000; | |
263 | 263 | |||
264 | return ure_read_2(un, reg, URE_MCU_TYPE_PLA); | 264 | return ure_read_2(un, reg, URE_MCU_TYPE_PLA); | |
265 | } | 265 | } | |
266 | 266 | |||
267 | static void | 267 | static void | |
268 | ure_ocp_reg_write(struct usbnet *un, uint16_t addr, uint16_t data) | 268 | ure_ocp_reg_write(struct usbnet *un, uint16_t addr, uint16_t data) | |
269 | { | 269 | { | |
270 | uint16_t reg; | 270 | uint16_t reg; | |
271 | 271 | |||
272 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | 272 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | |
273 | reg = (addr & 0x0fff) | 0xb000; | 273 | reg = (addr & 0x0fff) | 0xb000; | |
274 | 274 | |||
275 | ure_write_2(un, reg, URE_MCU_TYPE_PLA, data); | 275 | ure_write_2(un, reg, URE_MCU_TYPE_PLA, data); | |
276 | } | 276 | } | |
277 | 277 | |||
278 | static int | 278 | static int | |
279 | ure_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 279 | ure_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
280 | { | 280 | { | |
281 | 281 | |||
282 | if (un->un_phyno != phy) { | 282 | if (un->un_phyno != phy) { | |
283 | *val = 0; | 283 | *val = 0; | |
284 | return EINVAL; | 284 | return EINVAL; | |
285 | } | 285 | } | |
286 | 286 | |||
287 | /* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */ | 287 | /* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */ | |
288 | if (reg == RTK_GMEDIASTAT) { | 288 | if (reg == RTK_GMEDIASTAT) { | |
289 | *val = ure_read_1(un, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA); | 289 | *val = ure_read_1(un, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA); | |
290 | return USBD_NORMAL_COMPLETION; | 290 | return USBD_NORMAL_COMPLETION; | |
291 | } | 291 | } | |
292 | 292 | |||
293 | *val = ure_ocp_reg_read(un, URE_OCP_BASE_MII + reg * 2); | 293 | *val = ure_ocp_reg_read(un, URE_OCP_BASE_MII + reg * 2); | |
294 | 294 | |||
295 | return 0; | 295 | return 0; | |
296 | } | 296 | } | |
297 | 297 | |||
298 | static int | 298 | static int | |
299 | ure_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 299 | ure_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
300 | { | 300 | { | |
301 | 301 | |||
302 | if (un->un_phyno != phy) | 302 | if (un->un_phyno != phy) | |
303 | return EINVAL; | 303 | return EINVAL; | |
304 | 304 | |||
305 | ure_ocp_reg_write(un, URE_OCP_BASE_MII + reg * 2, val); | 305 | ure_ocp_reg_write(un, URE_OCP_BASE_MII + reg * 2, val); | |
306 | 306 | |||
307 | return 0; | 307 | return 0; | |
308 | } | 308 | } | |
309 | 309 | |||
310 | static void | 310 | static void | |
311 | ure_uno_miibus_statchg(struct ifnet *ifp) | 311 | ure_uno_miibus_statchg(struct ifnet *ifp) | |
312 | { | 312 | { | |
313 | struct usbnet * const un = ifp->if_softc; | 313 | struct usbnet * const un = ifp->if_softc; | |
314 | struct mii_data * const mii = usbnet_mii(un); | 314 | struct mii_data * const mii = usbnet_mii(un); | |
315 | 315 | |||
316 | if (usbnet_isdying(un)) | 316 | if (usbnet_isdying(un)) | |
317 | return; | 317 | return; | |
318 | 318 | |||
319 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 319 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
320 | (IFM_ACTIVE | IFM_AVALID)) { | 320 | (IFM_ACTIVE | IFM_AVALID)) { | |
321 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 321 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
322 | case IFM_10_T: | 322 | case IFM_10_T: | |
323 | case IFM_100_TX: | 323 | case IFM_100_TX: | |
324 | usbnet_set_link(un, true); | 324 | usbnet_set_link(un, true); | |
325 | break; | 325 | break; | |
326 | case IFM_1000_T: | 326 | case IFM_1000_T: | |
327 | if ((un->un_flags & URE_FLAG_8152) != 0) | 327 | if ((un->un_flags & URE_FLAG_8152) != 0) | |
328 | break; | 328 | break; | |
329 | usbnet_set_link(un, true); | 329 | usbnet_set_link(un, true); | |
330 | break; | 330 | break; | |
331 | default: | 331 | default: | |
332 | break; | 332 | break; | |
333 | } | 333 | } | |
334 | } | 334 | } | |
335 | } | 335 | } | |
336 | 336 | |||
337 | static void | 337 | static void | |
338 | ure_uno_mcast(struct ifnet *ifp) | 338 | ure_uno_mcast(struct ifnet *ifp) | |
339 | { | 339 | { | |
340 | struct usbnet *un = ifp->if_softc; | 340 | struct usbnet *un = ifp->if_softc; | |
341 | struct ethercom *ec = usbnet_ec(un); | 341 | struct ethercom *ec = usbnet_ec(un); | |
342 | struct ether_multi *enm; | 342 | struct ether_multi *enm; | |
343 | struct ether_multistep step; | 343 | struct ether_multistep step; | |
344 | uint32_t mchash[2] = { 0, 0 }; | 344 | uint32_t mchash[2] = { 0, 0 }; | |
345 | uint32_t h = 0, rxmode; | 345 | uint32_t h = 0, rxmode; | |
346 | 346 | |||
347 | if (usbnet_isdying(un)) | 347 | if (usbnet_isdying(un)) | |
348 | return; | 348 | return; | |
349 | 349 | |||
350 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | 350 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | |
351 | rxmode &= ~(URE_RCR_AAP | URE_RCR_AM); | 351 | rxmode &= ~(URE_RCR_AAP | URE_RCR_AM); | |
352 | /* continue to accept my own DA and bcast frames */ | 352 | /* continue to accept my own DA and bcast frames */ | |
353 | 353 | |||
354 | ETHER_LOCK(ec); | 354 | ETHER_LOCK(ec); | |
355 | if (ifp->if_flags & IFF_PROMISC) { | 355 | if (ifp->if_flags & IFF_PROMISC) { | |
356 | ec->ec_flags |= ETHER_F_ALLMULTI; | 356 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
357 | ETHER_UNLOCK(ec); | 357 | ETHER_UNLOCK(ec); | |
358 | /* run promisc. mode */ | 358 | /* run promisc. mode */ | |
359 | rxmode |= URE_RCR_AM; /* ??? */ | 359 | rxmode |= URE_RCR_AM; /* ??? */ | |
360 | rxmode |= URE_RCR_AAP; | 360 | rxmode |= URE_RCR_AAP; | |
361 | goto update; | 361 | goto update; | |
362 | } | 362 | } | |
363 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 363 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
364 | ETHER_FIRST_MULTI(step, ec, enm); | 364 | ETHER_FIRST_MULTI(step, ec, enm); | |
365 | while (enm != NULL) { | 365 | while (enm != NULL) { | |
366 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 366 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
367 | ec->ec_flags |= ETHER_F_ALLMULTI; | 367 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
368 | ETHER_UNLOCK(ec); | 368 | ETHER_UNLOCK(ec); | |
369 | /* accept all mcast frames */ | 369 | /* accept all mcast frames */ | |
370 | rxmode |= URE_RCR_AM; | 370 | rxmode |= URE_RCR_AM; | |
371 | mchash[0] = mchash[1] = ~0U; /* necessary ?? */ | 371 | mchash[0] = mchash[1] = ~0U; /* necessary ?? */ | |
372 | goto update; | 372 | goto update; | |
373 | } | 373 | } | |
374 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 374 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
375 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | 375 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | |
376 | ETHER_NEXT_MULTI(step, enm); | 376 | ETHER_NEXT_MULTI(step, enm); | |
377 | } | 377 | } | |
378 | ETHER_UNLOCK(ec); | 378 | ETHER_UNLOCK(ec); | |
379 | if (h != 0) { | 379 | if (h != 0) { | |
380 | rxmode |= URE_RCR_AM; /* activate mcast hash filter */ | 380 | rxmode |= URE_RCR_AM; /* activate mcast hash filter */ | |
381 | h = bswap32(mchash[0]); | 381 | h = bswap32(mchash[0]); | |
382 | mchash[0] = bswap32(mchash[1]); | 382 | mchash[0] = bswap32(mchash[1]); | |
383 | mchash[1] = h; | 383 | mchash[1] = h; | |
384 | } | 384 | } | |
385 | update: | 385 | update: | |
386 | ure_write_4(un, URE_PLA_MAR0, URE_MCU_TYPE_PLA, mchash[0]); | 386 | ure_write_4(un, URE_PLA_MAR0, URE_MCU_TYPE_PLA, mchash[0]); | |
387 | ure_write_4(un, URE_PLA_MAR4, URE_MCU_TYPE_PLA, mchash[1]); | 387 | ure_write_4(un, URE_PLA_MAR4, URE_MCU_TYPE_PLA, mchash[1]); | |
388 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | 388 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | |
389 | } | 389 | } | |
390 | 390 | |||
391 | static void | 391 | static void | |
392 | ure_reset(struct usbnet *un) | 392 | ure_reset(struct usbnet *un) | |
393 | { | 393 | { | |
394 | int i; | 394 | int i; | |
395 | 395 | |||
396 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); | 396 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); | |
397 | 397 | |||
398 | for (i = 0; i < URE_TIMEOUT; i++) { | 398 | for (i = 0; i < URE_TIMEOUT; i++) { | |
399 | if (usbnet_isdying(un)) | 399 | if (usbnet_isdying(un)) | |
400 | return; | 400 | return; | |
401 | if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) & | 401 | if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) & | |
402 | URE_CR_RST)) | 402 | URE_CR_RST)) | |
403 | break; | 403 | break; | |
404 | usbd_delay_ms(un->un_udev, 10); | 404 | usbd_delay_ms(un->un_udev, 10); | |
405 | } | 405 | } | |
406 | if (i == URE_TIMEOUT) | 406 | if (i == URE_TIMEOUT) | |
407 | URE_PRINTF(un, "reset never completed\n"); | 407 | URE_PRINTF(un, "reset never completed\n"); | |
408 | } | 408 | } | |
409 | 409 | |||
410 | static int | 410 | static int | |
411 | ure_uno_init(struct ifnet *ifp) | 411 | ure_uno_init(struct ifnet *ifp) | |
412 | { | 412 | { | |
413 | struct usbnet * const un = ifp->if_softc; | 413 | struct usbnet * const un = ifp->if_softc; | |
414 | uint8_t eaddr[8]; | 414 | uint8_t eaddr[8]; | |
415 | 415 | |||
416 | /* Cancel pending I/O. */ | |||
417 | if (ifp->if_flags & IFF_RUNNING) | |||
418 | usbnet_stop(un, ifp, 1); | |||
419 | ||||
420 | /* Set MAC address. */ | 416 | /* Set MAC address. */ | |
421 | memset(eaddr, 0, sizeof(eaddr)); | 417 | memset(eaddr, 0, sizeof(eaddr)); | |
422 | memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); | 418 | memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); | |
423 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG); | 419 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG); | |
424 | ure_write_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES, | 420 | ure_write_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES, | |
425 | eaddr, 8); | 421 | eaddr, 8); | |
426 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML); | 422 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML); | |
427 | 423 | |||
428 | /* Reset the packet filter. */ | 424 | /* Reset the packet filter. */ | |
429 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | 425 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | |
430 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) & | 426 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) & | |
431 | ~URE_FMC_FCR_MCU_EN); | 427 | ~URE_FMC_FCR_MCU_EN); | |
432 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | 428 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | |
433 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) | | 429 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) | | |
434 | URE_FMC_FCR_MCU_EN); | 430 | URE_FMC_FCR_MCU_EN); | |
435 | 431 | |||
436 | /* Enable transmit and receive. */ | 432 | /* Enable transmit and receive. */ | |
437 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, | 433 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, | |
438 | ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE | | 434 | ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE | | |
439 | URE_CR_TE); | 435 | URE_CR_TE); | |
440 | 436 | |||
441 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | 437 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | |
442 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) & | 438 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) & | |
443 | ~URE_RXDY_GATED_EN); | 439 | ~URE_RXDY_GATED_EN); | |
444 | 440 | |||
445 | return usbnet_init_rx_tx(un); | 441 | return usbnet_init_rx_tx(un); | |
446 | } | 442 | } | |
447 | 443 | |||
448 | static void | 444 | static void | |
449 | ure_uno_stop(struct ifnet *ifp, int disable __unused) | 445 | ure_uno_stop(struct ifnet *ifp, int disable __unused) | |
450 | { | 446 | { | |
451 | struct usbnet * const un = ifp->if_softc; | 447 | struct usbnet * const un = ifp->if_softc; | |
452 | 448 | |||
453 | ure_reset(un); | 449 | ure_reset(un); | |
454 | } | 450 | } | |
455 | 451 | |||
456 | static void | 452 | static void | |
457 | ure_rtl8152_init(struct usbnet *un) | 453 | ure_rtl8152_init(struct usbnet *un) | |
458 | { | 454 | { | |
459 | uint32_t pwrctrl; | 455 | uint32_t pwrctrl; | |
460 | 456 | |||
461 | /* Disable ALDPS. */ | 457 | /* Disable ALDPS. */ | |
462 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | 458 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | |
463 | URE_DIS_SDSAVE); | 459 | URE_DIS_SDSAVE); | |
464 | usbd_delay_ms(un->un_udev, 20); | 460 | usbd_delay_ms(un->un_udev, 20); | |
465 | 461 | |||
466 | if (un->un_flags & URE_FLAG_VER_4C00) { | 462 | if (un->un_flags & URE_FLAG_VER_4C00) { | |
467 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | 463 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | |
468 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | 464 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | |
469 | ~URE_LED_MODE_MASK); | 465 | ~URE_LED_MODE_MASK); | |
470 | } | 466 | } | |
471 | 467 | |||
472 | ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, | 468 | ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, | |
473 | ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & | 469 | ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & | |
474 | ~URE_POWER_CUT); | 470 | ~URE_POWER_CUT); | |
475 | ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, | 471 | ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, | |
476 | ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & | 472 | ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & | |
477 | ~URE_RESUME_INDICATE); | 473 | ~URE_RESUME_INDICATE); | |
478 | 474 | |||
479 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | 475 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | |
480 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | 476 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | |
481 | URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); | 477 | URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); | |
482 | pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); | 478 | pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); | |
483 | pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; | 479 | pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; | |
484 | pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; | 480 | pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; | |
485 | ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); | 481 | ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); | |
486 | ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, | 482 | ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, | |
487 | URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | | 483 | URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | | |
488 | URE_SPDWN_LINKCHG_MSK); | 484 | URE_SPDWN_LINKCHG_MSK); | |
489 | 485 | |||
490 | /* Enable Rx aggregation. */ | 486 | /* Enable Rx aggregation. */ | |
491 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | 487 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | |
492 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | 488 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | |
493 | ~URE_RX_AGG_DISABLE); | 489 | ~URE_RX_AGG_DISABLE); | |
494 | 490 | |||
495 | /* Disable ALDPS. */ | 491 | /* Disable ALDPS. */ | |
496 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | 492 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | |
497 | URE_DIS_SDSAVE); | 493 | URE_DIS_SDSAVE); | |
498 | usbd_delay_ms(un->un_udev, 20); | 494 | usbd_delay_ms(un->un_udev, 20); | |
499 | 495 | |||
500 | ure_init_fifo(un); | 496 | ure_init_fifo(un); | |
501 | 497 | |||
502 | ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB, | 498 | ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB, | |
503 | URE_TX_AGG_MAX_THRESHOLD); | 499 | URE_TX_AGG_MAX_THRESHOLD); | |
504 | ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); | 500 | ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); | |
505 | ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB, | 501 | ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB, | |
506 | URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); | 502 | URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); | |
507 | } | 503 | } | |
508 | 504 | |||
509 | static void | 505 | static void | |
510 | ure_rtl8153_init(struct usbnet *un) | 506 | ure_rtl8153_init(struct usbnet *un) | |
511 | { | 507 | { | |
512 | uint16_t val; | 508 | uint16_t val; | |
513 | uint8_t u1u2[8]; | 509 | uint8_t u1u2[8]; | |
514 | int i; | 510 | int i; | |
515 | 511 | |||
516 | /* Disable ALDPS. */ | 512 | /* Disable ALDPS. */ | |
517 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 513 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
518 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | 514 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | |
519 | usbd_delay_ms(un->un_udev, 20); | 515 | usbd_delay_ms(un->un_udev, 20); | |
520 | 516 | |||
521 | memset(u1u2, 0x00, sizeof(u1u2)); | 517 | memset(u1u2, 0x00, sizeof(u1u2)); | |
522 | ure_write_mem(un, URE_USB_TOLERANCE, | 518 | ure_write_mem(un, URE_USB_TOLERANCE, | |
523 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 519 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
524 | 520 | |||
525 | for (i = 0; i < URE_TIMEOUT; i++) { | 521 | for (i = 0; i < URE_TIMEOUT; i++) { | |
526 | if (usbnet_isdying(un)) | 522 | if (usbnet_isdying(un)) | |
527 | return; | 523 | return; | |
528 | if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & | 524 | if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & | |
529 | URE_AUTOLOAD_DONE) | 525 | URE_AUTOLOAD_DONE) | |
530 | break; | 526 | break; | |
531 | usbd_delay_ms(un->un_udev, 10); | 527 | usbd_delay_ms(un->un_udev, 10); | |
532 | } | 528 | } | |
533 | if (i == URE_TIMEOUT) | 529 | if (i == URE_TIMEOUT) | |
534 | URE_PRINTF(un, "timeout waiting for chip autoload\n"); | 530 | URE_PRINTF(un, "timeout waiting for chip autoload\n"); | |
535 | 531 | |||
536 | for (i = 0; i < URE_TIMEOUT; i++) { | 532 | for (i = 0; i < URE_TIMEOUT; i++) { | |
537 | if (usbnet_isdying(un)) | 533 | if (usbnet_isdying(un)) | |
538 | return; | 534 | return; | |
539 | val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & | 535 | val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & | |
540 | URE_PHY_STAT_MASK; | 536 | URE_PHY_STAT_MASK; | |
541 | if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) | 537 | if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) | |
542 | break; | 538 | break; | |
543 | usbd_delay_ms(un->un_udev, 10); | 539 | usbd_delay_ms(un->un_udev, 10); | |
544 | } | 540 | } | |
545 | if (i == URE_TIMEOUT) | 541 | if (i == URE_TIMEOUT) | |
546 | URE_PRINTF(un, "timeout waiting for phy to stabilize\n"); | 542 | URE_PRINTF(un, "timeout waiting for phy to stabilize\n"); | |
547 | 543 | |||
548 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, | 544 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, | |
549 | ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & | 545 | ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & | |
550 | ~URE_U2P3_ENABLE); | 546 | ~URE_U2P3_ENABLE); | |
551 | 547 | |||
552 | if (un->un_flags & URE_FLAG_VER_5C10) { | 548 | if (un->un_flags & URE_FLAG_VER_5C10) { | |
553 | val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); | 549 | val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); | |
554 | val &= ~URE_PWD_DN_SCALE_MASK; | 550 | val &= ~URE_PWD_DN_SCALE_MASK; | |
555 | val |= URE_PWD_DN_SCALE(96); | 551 | val |= URE_PWD_DN_SCALE(96); | |
556 | ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); | 552 | ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); | |
557 | 553 | |||
558 | ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB, | 554 | ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB, | |
559 | ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) | | 555 | ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) | | |
560 | URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); | 556 | URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); | |
561 | } else if (un->un_flags & URE_FLAG_VER_5C20) { | 557 | } else if (un->un_flags & URE_FLAG_VER_5C20) { | |
562 | ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, | 558 | ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, | |
563 | ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) & | 559 | ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) & | |
564 | ~URE_ECM_ALDPS); | 560 | ~URE_ECM_ALDPS); | |
565 | } | 561 | } | |
566 | if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) { | 562 | if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) { | |
567 | val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); | 563 | val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); | |
568 | if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == | 564 | if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == | |
569 | 0) | 565 | 0) | |
570 | val &= ~URE_DYNAMIC_BURST; | 566 | val &= ~URE_DYNAMIC_BURST; | |
571 | else | 567 | else | |
572 | val |= URE_DYNAMIC_BURST; | 568 | val |= URE_DYNAMIC_BURST; | |
573 | ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); | 569 | ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); | |
574 | } | 570 | } | |
575 | 571 | |||
576 | ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, | 572 | ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, | |
577 | ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | | 573 | ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | | |
578 | URE_EP4_FULL_FC); | 574 | URE_EP4_FULL_FC); | |
579 | 575 | |||
580 | ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, | 576 | ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, | |
581 | ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & | 577 | ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & | |
582 | ~URE_TIMER11_EN); | 578 | ~URE_TIMER11_EN); | |
583 | 579 | |||
584 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | 580 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | |
585 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | 581 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | |
586 | ~URE_LED_MODE_MASK); | 582 | ~URE_LED_MODE_MASK); | |
587 | 583 | |||
588 | if ((un->un_flags & URE_FLAG_VER_5C10) && | 584 | if ((un->un_flags & URE_FLAG_VER_5C10) && | |
589 | un->un_udev->ud_speed != USB_SPEED_SUPER) | 585 | un->un_udev->ud_speed != USB_SPEED_SUPER) | |
590 | val = URE_LPM_TIMER_500MS; | 586 | val = URE_LPM_TIMER_500MS; | |
591 | else | 587 | else | |
592 | val = URE_LPM_TIMER_500US; | 588 | val = URE_LPM_TIMER_500US; | |
593 | ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, | 589 | ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, | |
594 | val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); | 590 | val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); | |
595 | 591 | |||
596 | val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); | 592 | val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); | |
597 | val &= ~URE_SEN_VAL_MASK; | 593 | val &= ~URE_SEN_VAL_MASK; | |
598 | val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; | 594 | val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; | |
599 | ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); | 595 | ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); | |
600 | 596 | |||
601 | ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); | 597 | ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); | |
602 | 598 | |||
603 | ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, | 599 | ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, | |
604 | ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) & | 600 | ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) & | |
605 | ~(URE_PWR_EN | URE_PHASE2_EN)); | 601 | ~(URE_PWR_EN | URE_PHASE2_EN)); | |
606 | ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB, | 602 | ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB, | |
607 | ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) & | 603 | ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) & | |
608 | ~URE_PCUT_STATUS); | 604 | ~URE_PCUT_STATUS); | |
609 | 605 | |||
610 | memset(u1u2, 0xff, sizeof(u1u2)); | 606 | memset(u1u2, 0xff, sizeof(u1u2)); | |
611 | ure_write_mem(un, URE_USB_TOLERANCE, | 607 | ure_write_mem(un, URE_USB_TOLERANCE, | |
612 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 608 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
613 | 609 | |||
614 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, | 610 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, | |
615 | URE_ALDPS_SPDWN_RATIO); | 611 | URE_ALDPS_SPDWN_RATIO); | |
616 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, | 612 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, | |
617 | URE_EEE_SPDWN_RATIO); | 613 | URE_EEE_SPDWN_RATIO); | |
618 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, | 614 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, | |
619 | URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | | 615 | URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | | |
620 | URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); | 616 | URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); | |
621 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, | 617 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, | |
622 | URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | | 618 | URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | | |
623 | URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | | 619 | URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | | |
624 | URE_EEE_SPDWN_EN); | 620 | URE_EEE_SPDWN_EN); | |
625 | 621 | |||
626 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | 622 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | |
627 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | 623 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | |
628 | val |= URE_U2P3_ENABLE; | 624 | val |= URE_U2P3_ENABLE; | |
629 | else | 625 | else | |
630 | val &= ~URE_U2P3_ENABLE; | 626 | val &= ~URE_U2P3_ENABLE; | |
631 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | 627 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | |
632 | 628 | |||
633 | memset(u1u2, 0x00, sizeof(u1u2)); | 629 | memset(u1u2, 0x00, sizeof(u1u2)); | |
634 | ure_write_mem(un, URE_USB_TOLERANCE, | 630 | ure_write_mem(un, URE_USB_TOLERANCE, | |
635 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 631 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
636 | 632 | |||
637 | /* Disable ALDPS. */ | 633 | /* Disable ALDPS. */ | |
638 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 634 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
639 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | 635 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | |
640 | usbd_delay_ms(un->un_udev, 20); | 636 | usbd_delay_ms(un->un_udev, 20); | |
641 | 637 | |||
642 | ure_init_fifo(un); | 638 | ure_init_fifo(un); | |
643 | 639 | |||
644 | /* Enable Rx aggregation. */ | 640 | /* Enable Rx aggregation. */ | |
645 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | 641 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | |
646 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | 642 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | |
647 | ~URE_RX_AGG_DISABLE); | 643 | ~URE_RX_AGG_DISABLE); | |
648 | 644 | |||
649 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | 645 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | |
650 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | 646 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | |
651 | val |= URE_U2P3_ENABLE; | 647 | val |= URE_U2P3_ENABLE; | |
652 | else | 648 | else | |
653 | val &= ~URE_U2P3_ENABLE; | 649 | val &= ~URE_U2P3_ENABLE; | |
654 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | 650 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | |
655 | 651 | |||
656 | memset(u1u2, 0xff, sizeof(u1u2)); | 652 | memset(u1u2, 0xff, sizeof(u1u2)); | |
657 | ure_write_mem(un, URE_USB_TOLERANCE, | 653 | ure_write_mem(un, URE_USB_TOLERANCE, | |
658 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 654 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
659 | } | 655 | } | |
660 | 656 | |||
661 | static void | 657 | static void | |
662 | ure_disable_teredo(struct usbnet *un) | 658 | ure_disable_teredo(struct usbnet *un) | |
663 | { | 659 | { | |
664 | ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, | 660 | ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, | |
665 | ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & | 661 | ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & | |
666 | ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); | 662 | ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); | |
667 | ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, | 663 | ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, | |
668 | URE_WDT6_SET_MODE); | 664 | URE_WDT6_SET_MODE); | |
669 | ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); | 665 | ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); | |
670 | ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); | 666 | ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); | |
671 | } | 667 | } | |
672 | 668 | |||
673 | static void | 669 | static void | |
674 | ure_init_fifo(struct usbnet *un) | 670 | ure_init_fifo(struct usbnet *un) | |
675 | { | 671 | { | |
676 | uint32_t rxmode, rx_fifo1, rx_fifo2; | 672 | uint32_t rxmode, rx_fifo1, rx_fifo2; | |
677 | int i; | 673 | int i; | |
678 | 674 | |||
679 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | 675 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | |
680 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | | 676 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | | |
681 | URE_RXDY_GATED_EN); | 677 | URE_RXDY_GATED_EN); | |
682 | 678 | |||
683 | ure_disable_teredo(un); | 679 | ure_disable_teredo(un); | |
684 | 680 | |||
685 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | 681 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | |
686 | rxmode &= ~URE_RCR_ACPT_ALL; | 682 | rxmode &= ~URE_RCR_ACPT_ALL; | |
687 | rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */ | 683 | rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */ | |
688 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | 684 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | |
689 | 685 | |||
690 | if (!(un->un_flags & URE_FLAG_8152)) { | 686 | if (!(un->un_flags & URE_FLAG_8152)) { | |
691 | if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 | | 687 | if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 | | |
692 | URE_FLAG_VER_5C20)) | 688 | URE_FLAG_VER_5C20)) | |
693 | ure_ocp_reg_write(un, URE_OCP_ADC_CFG, | 689 | ure_ocp_reg_write(un, URE_OCP_ADC_CFG, | |
694 | URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); | 690 | URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); | |
695 | if (un->un_flags & URE_FLAG_VER_5C00) | 691 | if (un->un_flags & URE_FLAG_VER_5C00) | |
696 | ure_ocp_reg_write(un, URE_OCP_EEE_CFG, | 692 | ure_ocp_reg_write(un, URE_OCP_EEE_CFG, | |
697 | ure_ocp_reg_read(un, URE_OCP_EEE_CFG) & | 693 | ure_ocp_reg_read(un, URE_OCP_EEE_CFG) & | |
698 | ~URE_CTAP_SHORT_EN); | 694 | ~URE_CTAP_SHORT_EN); | |
699 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 695 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
700 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | 696 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | |
701 | URE_EEE_CLKDIV_EN); | 697 | URE_EEE_CLKDIV_EN); | |
702 | ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED, | 698 | ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED, | |
703 | ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) | | 699 | ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) | | |
704 | URE_EN_10M_BGOFF); | 700 | URE_EN_10M_BGOFF); | |
705 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 701 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
706 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | 702 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | |
707 | URE_EN_10M_PLLOFF); | 703 | URE_EN_10M_PLLOFF); | |
708 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE); | 704 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE); | |
709 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13); | 705 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13); | |
710 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | 706 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | |
711 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | 707 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | |
712 | URE_PFM_PWM_SWITCH); | 708 | URE_PFM_PWM_SWITCH); | |
713 | 709 | |||
714 | /* Enable LPF corner auto tune. */ | 710 | /* Enable LPF corner auto tune. */ | |
715 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG); | 711 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG); | |
716 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f); | 712 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f); | |
717 | 713 | |||
718 | /* Adjust 10M amplitude. */ | 714 | /* Adjust 10M amplitude. */ | |
719 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1); | 715 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1); | |
720 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af); | 716 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af); | |
721 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2); | 717 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2); | |
722 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208); | 718 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208); | |
723 | } | 719 | } | |
724 | 720 | |||
725 | ure_reset(un); | 721 | ure_reset(un); | |
726 | 722 | |||
727 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); | 723 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); | |
728 | 724 | |||
729 | ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, | 725 | ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, | |
730 | ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 726 | ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
731 | ~URE_NOW_IS_OOB); | 727 | ~URE_NOW_IS_OOB); | |
732 | 728 | |||
733 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | 729 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | |
734 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & | 730 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & | |
735 | ~URE_MCU_BORW_EN); | 731 | ~URE_MCU_BORW_EN); | |
736 | for (i = 0; i < URE_TIMEOUT; i++) { | 732 | for (i = 0; i < URE_TIMEOUT; i++) { | |
737 | if (usbnet_isdying(un)) | 733 | if (usbnet_isdying(un)) | |
738 | return; | 734 | return; | |
739 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 735 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
740 | URE_LINK_LIST_READY) | 736 | URE_LINK_LIST_READY) | |
741 | break; | 737 | break; | |
742 | usbd_delay_ms(un->un_udev, 10); | 738 | usbd_delay_ms(un->un_udev, 10); | |
743 | } | 739 | } | |
744 | if (i == URE_TIMEOUT) | 740 | if (i == URE_TIMEOUT) | |
745 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | 741 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | |
746 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | 742 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | |
747 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | | 743 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | | |
748 | URE_RE_INIT_LL); | 744 | URE_RE_INIT_LL); | |
749 | for (i = 0; i < URE_TIMEOUT; i++) { | 745 | for (i = 0; i < URE_TIMEOUT; i++) { | |
750 | if (usbnet_isdying(un)) | 746 | if (usbnet_isdying(un)) | |
751 | return; | 747 | return; | |
752 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 748 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
753 | URE_LINK_LIST_READY) | 749 | URE_LINK_LIST_READY) | |
754 | break; | 750 | break; | |
755 | usbd_delay_ms(un->un_udev, 10); | 751 | usbd_delay_ms(un->un_udev, 10); | |
756 | } | 752 | } | |
757 | if (i == URE_TIMEOUT) | 753 | if (i == URE_TIMEOUT) | |
758 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | 754 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | |
759 | 755 | |||
760 | ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA, | 756 | ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA, | |
761 | ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & | 757 | ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & | |
762 | ~URE_CPCR_RX_VLAN); | 758 | ~URE_CPCR_RX_VLAN); | |
763 | ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA, | 759 | ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA, | |
764 | ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | | 760 | ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | | |
765 | URE_TCR0_AUTO_FIFO); | 761 | URE_TCR0_AUTO_FIFO); | |
766 | 762 | |||
767 | /* Configure Rx FIFO threshold and coalescing. */ | 763 | /* Configure Rx FIFO threshold and coalescing. */ | |
768 | ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, | 764 | ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, | |
769 | URE_RXFIFO_THR1_NORMAL); | 765 | URE_RXFIFO_THR1_NORMAL); | |
770 | if (un->un_udev->ud_speed == USB_SPEED_FULL) { | 766 | if (un->un_udev->ud_speed == USB_SPEED_FULL) { | |
771 | rx_fifo1 = URE_RXFIFO_THR2_FULL; | 767 | rx_fifo1 = URE_RXFIFO_THR2_FULL; | |
772 | rx_fifo2 = URE_RXFIFO_THR3_FULL; | 768 | rx_fifo2 = URE_RXFIFO_THR3_FULL; | |
773 | } else { | 769 | } else { | |
774 | rx_fifo1 = URE_RXFIFO_THR2_HIGH; | 770 | rx_fifo1 = URE_RXFIFO_THR2_HIGH; | |
775 | rx_fifo2 = URE_RXFIFO_THR3_HIGH; | 771 | rx_fifo2 = URE_RXFIFO_THR3_HIGH; | |
776 | } | 772 | } | |
777 | ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); | 773 | ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); | |
778 | ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); | 774 | ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); | |
779 | 775 | |||
780 | /* Configure Tx FIFO threshold. */ | 776 | /* Configure Tx FIFO threshold. */ | |
781 | ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, | 777 | ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, | |
782 | URE_TXFIFO_THR_NORMAL); | 778 | URE_TXFIFO_THR_NORMAL); | |
783 | } | 779 | } | |
784 | 780 | |||
785 | static int | 781 | static int | |
786 | ure_match(device_t parent, cfdata_t match, void *aux) | 782 | ure_match(device_t parent, cfdata_t match, void *aux) | |
787 | { | 783 | { | |
788 | struct usb_attach_arg *uaa = aux; | 784 | struct usb_attach_arg *uaa = aux; | |
789 | 785 | |||
790 | return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 786 | return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
791 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 787 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
792 | } | 788 | } | |
793 | 789 | |||
794 | static void | 790 | static void | |
795 | ure_attach(device_t parent, device_t self, void *aux) | 791 | ure_attach(device_t parent, device_t self, void *aux) | |
796 | { | 792 | { | |
797 | USBNET_MII_DECL_DEFAULT(unm); | 793 | USBNET_MII_DECL_DEFAULT(unm); | |
798 | struct usbnet * const un = device_private(self); | 794 | struct usbnet * const un = device_private(self); | |
799 | struct usb_attach_arg *uaa = aux; | 795 | struct usb_attach_arg *uaa = aux; | |
800 | struct usbd_device *dev = uaa->uaa_device; | 796 | struct usbd_device *dev = uaa->uaa_device; | |
801 | usb_interface_descriptor_t *id; | 797 | usb_interface_descriptor_t *id; | |
802 | usb_endpoint_descriptor_t *ed; | 798 | usb_endpoint_descriptor_t *ed; | |
803 | int error, i; | 799 | int error, i; | |
804 | uint16_t ver; | 800 | uint16_t ver; | |
805 | uint8_t eaddr[8]; /* 2byte padded */ | 801 | uint8_t eaddr[8]; /* 2byte padded */ | |
806 | char *devinfop; | 802 | char *devinfop; | |
807 | uint32_t maclo, machi; | 803 | uint32_t maclo, machi; | |
808 | 804 | |||
809 | aprint_naive("\n"); | 805 | aprint_naive("\n"); | |
810 | aprint_normal("\n"); | 806 | aprint_normal("\n"); | |
811 | devinfop = usbd_devinfo_alloc(dev, 0); | 807 | devinfop = usbd_devinfo_alloc(dev, 0); | |
812 | aprint_normal_dev(self, "%s\n", devinfop); | 808 | aprint_normal_dev(self, "%s\n", devinfop); | |
813 | usbd_devinfo_free(devinfop); | 809 | usbd_devinfo_free(devinfop); | |
814 | 810 | |||
815 | un->un_dev = self; | 811 | un->un_dev = self; | |
816 | un->un_udev = dev; | 812 | un->un_udev = dev; | |
817 | un->un_sc = un; | 813 | un->un_sc = un; | |
818 | un->un_ops = &ure_ops; | 814 | un->un_ops = &ure_ops; | |
819 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 815 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
820 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 816 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
821 | un->un_rx_list_cnt = URE_RX_LIST_CNT; | 817 | un->un_rx_list_cnt = URE_RX_LIST_CNT; | |
822 | un->un_tx_list_cnt = URE_TX_LIST_CNT; | 818 | un->un_tx_list_cnt = URE_TX_LIST_CNT; | |
823 | un->un_rx_bufsz = URE_BUFSZ; | 819 | un->un_rx_bufsz = URE_BUFSZ; | |
824 | un->un_tx_bufsz = URE_BUFSZ; | 820 | un->un_tx_bufsz = URE_BUFSZ; | |
825 | 821 | |||
826 | #define URE_CONFIG_NO 1 /* XXX */ | 822 | #define URE_CONFIG_NO 1 /* XXX */ | |
827 | error = usbd_set_config_no(dev, URE_CONFIG_NO, 1); | 823 | error = usbd_set_config_no(dev, URE_CONFIG_NO, 1); | |
828 | if (error) { | 824 | if (error) { | |
829 | aprint_error_dev(self, "failed to set configuration: %s\n", | 825 | aprint_error_dev(self, "failed to set configuration: %s\n", | |
830 | usbd_errstr(error)); | 826 | usbd_errstr(error)); | |
831 | return; /* XXX */ | 827 | return; /* XXX */ | |
832 | } | 828 | } | |
833 | 829 | |||
834 | if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152) | 830 | if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152) | |
835 | un->un_flags |= URE_FLAG_8152; | 831 | un->un_flags |= URE_FLAG_8152; | |
836 | 832 | |||
837 | #define URE_IFACE_IDX 0 /* XXX */ | 833 | #define URE_IFACE_IDX 0 /* XXX */ | |
838 | error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface); | 834 | error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface); | |
839 | if (error) { | 835 | if (error) { | |
840 | aprint_error_dev(self, "failed to get interface handle: %s\n", | 836 | aprint_error_dev(self, "failed to get interface handle: %s\n", | |
841 | usbd_errstr(error)); | 837 | usbd_errstr(error)); | |
842 | return; /* XXX */ | 838 | return; /* XXX */ | |
843 | } | 839 | } | |
844 | 840 | |||
845 | id = usbd_get_interface_descriptor(un->un_iface); | 841 | id = usbd_get_interface_descriptor(un->un_iface); | |
846 | for (i = 0; i < id->bNumEndpoints; i++) { | 842 | for (i = 0; i < id->bNumEndpoints; i++) { | |
847 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 843 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
848 | if (ed == NULL) { | 844 | if (ed == NULL) { | |
849 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 845 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
850 | return; /* XXX */ | 846 | return; /* XXX */ | |
851 | } | 847 | } | |
852 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 848 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
853 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 849 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
854 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 850 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
855 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 851 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
856 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 852 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
857 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 853 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
858 | } | 854 | } | |
859 | } | 855 | } | |
860 | 856 | |||
861 | /* Set these up now for ure_ctl(). */ | 857 | /* Set these up now for ure_ctl(). */ | |
862 | usbnet_attach(un, "uredet"); | 858 | usbnet_attach(un, "uredet"); | |
863 | 859 | |||
864 | un->un_phyno = 0; | 860 | un->un_phyno = 0; | |
865 | 861 | |||
866 | ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; | 862 | ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; | |
867 | switch (ver) { | 863 | switch (ver) { | |
868 | case 0x4c00: | 864 | case 0x4c00: | |
869 | un->un_flags |= URE_FLAG_VER_4C00; | 865 | un->un_flags |= URE_FLAG_VER_4C00; | |
870 | break; | 866 | break; | |
871 | case 0x4c10: | 867 | case 0x4c10: | |
872 | un->un_flags |= URE_FLAG_VER_4C10; | 868 | un->un_flags |= URE_FLAG_VER_4C10; | |
873 | break; | 869 | break; | |
874 | case 0x5c00: | 870 | case 0x5c00: | |
875 | un->un_flags |= URE_FLAG_VER_5C00; | 871 | un->un_flags |= URE_FLAG_VER_5C00; | |
876 | break; | 872 | break; | |
877 | case 0x5c10: | 873 | case 0x5c10: | |
878 | un->un_flags |= URE_FLAG_VER_5C10; | 874 | un->un_flags |= URE_FLAG_VER_5C10; | |
879 | break; | 875 | break; | |
880 | case 0x5c20: | 876 | case 0x5c20: | |
881 | un->un_flags |= URE_FLAG_VER_5C20; | 877 | un->un_flags |= URE_FLAG_VER_5C20; | |
882 | break; | 878 | break; | |
883 | case 0x5c30: | 879 | case 0x5c30: | |
884 | un->un_flags |= URE_FLAG_VER_5C30; | 880 | un->un_flags |= URE_FLAG_VER_5C30; | |
885 | break; | 881 | break; | |
886 | default: | 882 | default: | |
887 | /* fake addr? or just fail? */ | 883 | /* fake addr? or just fail? */ | |
888 | break; | 884 | break; | |
889 | } | 885 | } | |
890 | aprint_normal_dev(self, "RTL%d %sver %04x\n", | 886 | aprint_normal_dev(self, "RTL%d %sver %04x\n", | |
891 | (un->un_flags & URE_FLAG_8152) ? 8152 : 8153, | 887 | (un->un_flags & URE_FLAG_8152) ? 8152 : 8153, | |
892 | (un->un_flags != 0) ? "" : "unknown ", | 888 | (un->un_flags != 0) ? "" : "unknown ", | |
893 | ver); | 889 | ver); | |
894 | 890 | |||
895 | if (un->un_flags & URE_FLAG_8152) | 891 | if (un->un_flags & URE_FLAG_8152) | |
896 | ure_rtl8152_init(un); | 892 | ure_rtl8152_init(un); | |
897 | else | 893 | else | |
898 | ure_rtl8153_init(un); | 894 | ure_rtl8153_init(un); | |
899 | 895 | |||
900 | if ((un->un_flags & URE_FLAG_VER_4C00) || | 896 | if ((un->un_flags & URE_FLAG_VER_4C00) || | |
901 | (un->un_flags & URE_FLAG_VER_4C10)) | 897 | (un->un_flags & URE_FLAG_VER_4C10)) | |
902 | ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr, | 898 | ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr, | |
903 | sizeof(eaddr)); | 899 | sizeof(eaddr)); | |
904 | else | 900 | else | |
905 | ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr, | 901 | ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr, | |
906 | sizeof(eaddr)); | 902 | sizeof(eaddr)); | |
907 | if (ETHER_IS_ZERO(eaddr)) { | 903 | if (ETHER_IS_ZERO(eaddr)) { | |
908 | maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); | 904 | maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); | |
909 | machi = cprng_strong32() & 0xffff; | 905 | machi = cprng_strong32() & 0xffff; | |
910 | eaddr[0] = maclo & 0xff; | 906 | eaddr[0] = maclo & 0xff; | |
911 | eaddr[1] = (maclo >> 8) & 0xff; | 907 | eaddr[1] = (maclo >> 8) & 0xff; | |
912 | eaddr[2] = (maclo >> 16) & 0xff; | 908 | eaddr[2] = (maclo >> 16) & 0xff; | |
913 | eaddr[3] = (maclo >> 24) & 0xff; | 909 | eaddr[3] = (maclo >> 24) & 0xff; | |
914 | eaddr[4] = machi & 0xff; | 910 | eaddr[4] = machi & 0xff; | |
915 | eaddr[5] = (machi >> 8) & 0xff; | 911 | eaddr[5] = (machi >> 8) & 0xff; | |
916 | } | 912 | } | |
917 | memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr)); | 913 | memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr)); | |
918 | 914 | |||
919 | struct ifnet *ifp = usbnet_ifp(un); | 915 | struct ifnet *ifp = usbnet_ifp(un); | |
920 | 916 | |||
921 | /* | 917 | /* | |
922 | * We don't support TSOv4 and v6 for now, that are required to | 918 | * We don't support TSOv4 and v6 for now, that are required to | |
923 | * be handled in software for some cases. | 919 | * be handled in software for some cases. | |
924 | */ | 920 | */ | |
925 | ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx | | 921 | ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx | | |
926 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx; | 922 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx; | |
927 | #ifdef INET6 | 923 | #ifdef INET6 | |
928 | ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx; | 924 | ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx; | |
929 | #endif | 925 | #endif | |
930 | if (un->un_flags & ~URE_FLAG_VER_4C00) { | 926 | if (un->un_flags & ~URE_FLAG_VER_4C00) { | |
931 | ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | | 927 | ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | | |
932 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 928 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
933 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | 929 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | |
934 | } | 930 | } | |
935 | struct ethercom *ec = usbnet_ec(un); | 931 | struct ethercom *ec = usbnet_ec(un); | |
936 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 932 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
937 | #ifdef notyet | 933 | #ifdef notyet | |
938 | ec->ec_capabilities |= ETHERCAP_JUMBO_MTU; | 934 | ec->ec_capabilities |= ETHERCAP_JUMBO_MTU; | |
939 | #endif | 935 | #endif | |
940 | 936 | |||
941 | unm.un_mii_phyloc = un->un_phyno; | 937 | unm.un_mii_phyloc = un->un_phyno; | |
942 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 938 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
943 | 0, &unm); | 939 | 0, &unm); | |
944 | } | 940 | } | |
945 | 941 | |||
946 | static void | 942 | static void | |
947 | ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 943 | ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
948 | { | 944 | { | |
949 | struct ifnet *ifp = usbnet_ifp(un); | 945 | struct ifnet *ifp = usbnet_ifp(un); | |
950 | uint8_t *buf = c->unc_buf; | 946 | uint8_t *buf = c->unc_buf; | |
951 | uint16_t pkt_len = 0; | 947 | uint16_t pkt_len = 0; | |
952 | uint16_t pkt_count = 0; | 948 | uint16_t pkt_count = 0; | |
953 | struct ure_rxpkt rxhdr; | 949 | struct ure_rxpkt rxhdr; | |
954 | 950 | |||
955 | do { | 951 | do { | |
956 | if (total_len < sizeof(rxhdr)) { | 952 | if (total_len < sizeof(rxhdr)) { | |
957 | DPRINTF(("too few bytes left for a packet header\n")); | 953 | DPRINTF(("too few bytes left for a packet header\n")); | |
958 | if_statinc(ifp, if_ierrors); | 954 | if_statinc(ifp, if_ierrors); | |
959 | return; | 955 | return; | |
960 | } | 956 | } | |
961 | 957 | |||
962 | buf += roundup(pkt_len, 8); | 958 | buf += roundup(pkt_len, 8); | |
963 | 959 | |||
964 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | 960 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | |
965 | total_len -= sizeof(rxhdr); | 961 | total_len -= sizeof(rxhdr); | |
966 | 962 | |||
967 | pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK; | 963 | pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK; | |
968 | DPRINTFN(4, ("next packet is %d bytes\n", pkt_len)); | 964 | DPRINTFN(4, ("next packet is %d bytes\n", pkt_len)); | |
969 | if (pkt_len > total_len) { | 965 | if (pkt_len > total_len) { | |
970 | DPRINTF(("not enough bytes left for next packet\n")); | 966 | DPRINTF(("not enough bytes left for next packet\n")); | |
971 | if_statinc(ifp, if_ierrors); | 967 | if_statinc(ifp, if_ierrors); | |
972 | return; | 968 | return; | |
973 | } | 969 | } | |
974 | 970 | |||
975 | total_len -= roundup(pkt_len, 8); | 971 | total_len -= roundup(pkt_len, 8); | |
976 | buf += sizeof(rxhdr); | 972 | buf += sizeof(rxhdr); | |
977 | 973 | |||
978 | usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN, | 974 | usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN, | |
979 | ure_rxcsum(ifp, &rxhdr), 0, 0); | 975 | ure_rxcsum(ifp, &rxhdr), 0, 0); | |
980 | 976 | |||
981 | pkt_count++; | 977 | pkt_count++; | |
982 | 978 | |||
983 | } while (total_len > 0); | 979 | } while (total_len > 0); | |
984 | 980 | |||
985 | if (pkt_count) | 981 | if (pkt_count) | |
986 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | 982 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | |
987 | } | 983 | } | |
988 | 984 | |||
989 | static int | 985 | static int | |
990 | ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp) | 986 | ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp) | |
991 | { | 987 | { | |
992 | int enabled = ifp->if_csum_flags_rx, flags = 0; | 988 | int enabled = ifp->if_csum_flags_rx, flags = 0; | |
993 | uint32_t csum, misc; | 989 | uint32_t csum, misc; | |
994 | 990 | |||
995 | if (enabled == 0) | 991 | if (enabled == 0) | |
996 | return 0; | 992 | return 0; | |
997 | 993 | |||
998 | csum = le32toh(rp->ure_csum); | 994 | csum = le32toh(rp->ure_csum); | |
999 | misc = le32toh(rp->ure_misc); | 995 | misc = le32toh(rp->ure_misc); | |
1000 | 996 | |||
1001 | if (csum & URE_RXPKT_IPV4_CS) { | 997 | if (csum & URE_RXPKT_IPV4_CS) { | |
1002 | flags |= M_CSUM_IPv4; | 998 | flags |= M_CSUM_IPv4; | |
1003 | if (csum & URE_RXPKT_TCP_CS) | 999 | if (csum & URE_RXPKT_TCP_CS) | |
1004 | flags |= M_CSUM_TCPv4; | 1000 | flags |= M_CSUM_TCPv4; | |
1005 | if (csum & URE_RXPKT_UDP_CS) | 1001 | if (csum & URE_RXPKT_UDP_CS) | |
1006 | flags |= M_CSUM_UDPv4; | 1002 | flags |= M_CSUM_UDPv4; | |
1007 | } else if (csum & URE_RXPKT_IPV6_CS) { | 1003 | } else if (csum & URE_RXPKT_IPV6_CS) { | |
1008 | flags = 0; | 1004 | flags = 0; | |
1009 | if (csum & URE_RXPKT_TCP_CS) | 1005 | if (csum & URE_RXPKT_TCP_CS) | |
1010 | flags |= M_CSUM_TCPv6; | 1006 | flags |= M_CSUM_TCPv6; | |
1011 | if (csum & URE_RXPKT_UDP_CS) | 1007 | if (csum & URE_RXPKT_UDP_CS) | |
1012 | flags |= M_CSUM_UDPv6; | 1008 | flags |= M_CSUM_UDPv6; | |
1013 | } | 1009 | } | |
1014 | 1010 | |||
1015 | flags &= enabled; | 1011 | flags &= enabled; | |
1016 | if (__predict_false((flags & M_CSUM_IPv4) && | 1012 | if (__predict_false((flags & M_CSUM_IPv4) && | |
1017 | (misc & URE_RXPKT_IP_F))) | 1013 | (misc & URE_RXPKT_IP_F))) | |
1018 | flags |= M_CSUM_IPv4_BAD; | 1014 | flags |= M_CSUM_IPv4_BAD; | |
1019 | if (__predict_false( | 1015 | if (__predict_false( | |
1020 | ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F)) | 1016 | ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F)) | |
1021 | || ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F)) | 1017 | || ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F)) | |
1022 | )) | 1018 | )) | |
1023 | flags |= M_CSUM_TCP_UDP_BAD; | 1019 | flags |= M_CSUM_TCP_UDP_BAD; | |
1024 | 1020 | |||
1025 | return flags; | 1021 | return flags; | |
1026 | } | 1022 | } | |
1027 | 1023 | |||
1028 | static unsigned | 1024 | static unsigned | |
1029 | ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 1025 | ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
1030 | { | 1026 | { | |
1031 | struct ure_txpkt txhdr; | 1027 | struct ure_txpkt txhdr; | |
1032 | uint32_t frm_len = 0; | 1028 | uint32_t frm_len = 0; | |
1033 | uint8_t *buf = c->unc_buf; | 1029 | uint8_t *buf = c->unc_buf; | |
1034 | 1030 | |||
1035 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr)) | 1031 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr)) | |
1036 | return 0; | 1032 | return 0; | |
1037 | 1033 | |||
1038 | /* header */ | 1034 | /* header */ | |
1039 | txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS | | 1035 | txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS | | |
1040 | URE_TXPKT_TX_LS); | 1036 | URE_TXPKT_TX_LS); | |
1041 | txhdr.ure_csum = htole32(ure_txcsum(m)); | 1037 | txhdr.ure_csum = htole32(ure_txcsum(m)); | |
1042 | memcpy(buf, &txhdr, sizeof(txhdr)); | 1038 | memcpy(buf, &txhdr, sizeof(txhdr)); | |
1043 | buf += sizeof(txhdr); | 1039 | buf += sizeof(txhdr); | |
1044 | frm_len = sizeof(txhdr); | 1040 | frm_len = sizeof(txhdr); | |
1045 | 1041 | |||
1046 | /* packet */ | 1042 | /* packet */ | |
1047 | m_copydata(m, 0, m->m_pkthdr.len, buf); | 1043 | m_copydata(m, 0, m->m_pkthdr.len, buf); | |
1048 | frm_len += m->m_pkthdr.len; | 1044 | frm_len += m->m_pkthdr.len; | |
1049 | 1045 | |||
1050 | DPRINTFN(2, ("tx %d bytes\n", frm_len)); | 1046 | DPRINTFN(2, ("tx %d bytes\n", frm_len)); | |
1051 | 1047 | |||
1052 | return frm_len; | 1048 | return frm_len; | |
1053 | } | 1049 | } | |
1054 | 1050 | |||
1055 | /* | 1051 | /* | |
1056 | * We need to calculate L4 checksum in software, if the offset of | 1052 | * We need to calculate L4 checksum in software, if the offset of | |
1057 | * L4 header is larger than 0x7ff = 2047. | 1053 | * L4 header is larger than 0x7ff = 2047. | |
1058 | */ | 1054 | */ | |
1059 | static uint32_t | 1055 | static uint32_t | |
1060 | ure_txcsum(struct mbuf *m) | 1056 | ure_txcsum(struct mbuf *m) | |
1061 | { | 1057 | { | |
1062 | struct ether_header *eh; | 1058 | struct ether_header *eh; | |
1063 | int flags = m->m_pkthdr.csum_flags; | 1059 | int flags = m->m_pkthdr.csum_flags; | |
1064 | uint32_t data = m->m_pkthdr.csum_data; | 1060 | uint32_t data = m->m_pkthdr.csum_data; | |
1065 | uint32_t reg = 0; | 1061 | uint32_t reg = 0; | |
1066 | int l3off, l4off; | 1062 | int l3off, l4off; | |
1067 | uint16_t type; | 1063 | uint16_t type; | |
1068 | 1064 | |||
1069 | if (flags == 0) | 1065 | if (flags == 0) | |
1070 | return 0; | 1066 | return 0; | |
1071 | 1067 | |||
1072 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | 1068 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | |
1073 | eh = mtod(m, struct ether_header *); | 1069 | eh = mtod(m, struct ether_header *); | |
1074 | type = eh->ether_type; | 1070 | type = eh->ether_type; | |
1075 | } else | 1071 | } else | |
1076 | m_copydata(m, offsetof(struct ether_header, ether_type), | 1072 | m_copydata(m, offsetof(struct ether_header, ether_type), | |
1077 | sizeof(type), &type); | 1073 | sizeof(type), &type); | |
1078 | switch (type = htons(type)) { | 1074 | switch (type = htons(type)) { | |
1079 | case ETHERTYPE_IP: | 1075 | case ETHERTYPE_IP: | |
1080 | case ETHERTYPE_IPV6: | 1076 | case ETHERTYPE_IPV6: | |
1081 | l3off = ETHER_HDR_LEN; | 1077 | l3off = ETHER_HDR_LEN; | |
1082 | break; | 1078 | break; | |
1083 | case ETHERTYPE_VLAN: | 1079 | case ETHERTYPE_VLAN: | |
1084 | l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | 1080 | l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | |
1085 | break; | 1081 | break; | |
1086 | default: | 1082 | default: | |
1087 | return 0; | 1083 | return 0; | |
1088 | } | 1084 | } | |
1089 | 1085 | |||
1090 | if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { | 1086 | if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { | |
1091 | l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data); | 1087 | l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data); | |
1092 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | 1088 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | |
1093 | in_undefer_cksum(m, l3off, flags); | 1089 | in_undefer_cksum(m, l3off, flags); | |
1094 | return 0; | 1090 | return 0; | |
1095 | } | 1091 | } | |
1096 | reg |= URE_TXPKT_IPV4_CS; | 1092 | reg |= URE_TXPKT_IPV4_CS; | |
1097 | if (flags & M_CSUM_TCPv4) | 1093 | if (flags & M_CSUM_TCPv4) | |
1098 | reg |= URE_TXPKT_TCP_CS; | 1094 | reg |= URE_TXPKT_TCP_CS; | |
1099 | else | 1095 | else | |
1100 | reg |= URE_TXPKT_UDP_CS; | 1096 | reg |= URE_TXPKT_UDP_CS; | |
1101 | reg |= l4off << URE_L4_OFFSET_SHIFT; | 1097 | reg |= l4off << URE_L4_OFFSET_SHIFT; | |
1102 | } | 1098 | } | |
1103 | #ifdef INET6 | 1099 | #ifdef INET6 | |
1104 | else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) { | 1100 | else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) { | |
1105 | l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data); | 1101 | l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data); | |
1106 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | 1102 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | |
1107 | in6_undefer_cksum(m, l3off, flags); | 1103 | in6_undefer_cksum(m, l3off, flags); | |
1108 | return 0; | 1104 | return 0; | |
1109 | } | 1105 | } | |
1110 | reg |= URE_TXPKT_IPV6_CS; | 1106 | reg |= URE_TXPKT_IPV6_CS; | |
1111 | if (flags & M_CSUM_TCPv6) | 1107 | if (flags & M_CSUM_TCPv6) | |
1112 | reg |= URE_TXPKT_TCP_CS; | 1108 | reg |= URE_TXPKT_TCP_CS; | |
1113 | else | 1109 | else | |
1114 | reg |= URE_TXPKT_UDP_CS; | 1110 | reg |= URE_TXPKT_UDP_CS; | |
1115 | reg |= l4off << URE_L4_OFFSET_SHIFT; | 1111 | reg |= l4off << URE_L4_OFFSET_SHIFT; | |
1116 | } | 1112 | } | |
1117 | #endif | 1113 | #endif | |
1118 | else if (flags & M_CSUM_IPv4) | 1114 | else if (flags & M_CSUM_IPv4) | |
1119 | reg |= URE_TXPKT_IPV4_CS; | 1115 | reg |= URE_TXPKT_IPV4_CS; | |
1120 | 1116 | |||
1121 | return reg; | 1117 | return reg; | |
1122 | } | 1118 | } | |
1123 | 1119 | |||
1124 | #ifdef _MODULE | 1120 | #ifdef _MODULE | |
1125 | #include "ioconf.c" | 1121 | #include "ioconf.c" | |
1126 | #endif | 1122 | #endif | |
1127 | 1123 | |||
1128 | USBNET_MODULE(ure) | 1124 | USBNET_MODULE(ure) |
--- src/sys/dev/usb/if_urndis.c 2022/03/03 05:54:45 1.41
+++ src/sys/dev/usb/if_urndis.c 2022/03/03 05:55:19 1.42
@@ -1,1090 +1,1087 @@ | @@ -1,1090 +1,1087 @@ | |||
1 | /* $NetBSD: if_urndis.c,v 1.41 2022/03/03 05:54:45 riastradh Exp $ */ | 1 | /* $NetBSD: if_urndis.c,v 1.42 2022/03/03 05:55:19 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_urndis.c,v 1.31 2011/07/03 15:47:17 matthew Exp $ */ | 2 | /* $OpenBSD: if_urndis.c,v 1.31 2011/07/03 15:47:17 matthew Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2010 Jonathan Armani <armani@openbsd.org> | 5 | * Copyright (c) 2010 Jonathan Armani <armani@openbsd.org> | |
6 | * Copyright (c) 2010 Fabien Romano <fabien@openbsd.org> | 6 | * Copyright (c) 2010 Fabien Romano <fabien@openbsd.org> | |
7 | * Copyright (c) 2010 Michael Knudsen <mk@openbsd.org> | 7 | * Copyright (c) 2010 Michael Knudsen <mk@openbsd.org> | |
8 | * All rights reserved. | 8 | * All rights reserved. | |
9 | * | 9 | * | |
10 | * Permission to use, copy, modify, and distribute this software for any | 10 | * Permission to use, copy, modify, and distribute this software for any | |
11 | * purpose with or without fee is hereby granted, provided that the above | 11 | * purpose with or without fee is hereby granted, provided that the above | |
12 | * copyright notice and this permission notice appear in all copies. | 12 | * copyright notice and this permission notice appear in all copies. | |
13 | * | 13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 14 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
15 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 15 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
16 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 16 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
17 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 17 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
18 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 18 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
19 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 19 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
20 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 20 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
21 | */ | 21 | */ | |
22 | 22 | |||
23 | #include <sys/cdefs.h> | 23 | #include <sys/cdefs.h> | |
24 | __KERNEL_RCSID(0, "$NetBSD: if_urndis.c,v 1.41 2022/03/03 05:54:45 riastradh Exp $"); | 24 | __KERNEL_RCSID(0, "$NetBSD: if_urndis.c,v 1.42 2022/03/03 05:55:19 riastradh Exp $"); | |
25 | 25 | |||
26 | #ifdef _KERNEL_OPT | 26 | #ifdef _KERNEL_OPT | |
27 | #include "opt_usb.h" | 27 | #include "opt_usb.h" | |
28 | #endif | 28 | #endif | |
29 | 29 | |||
30 | #include <sys/param.h> | 30 | #include <sys/param.h> | |
31 | #include <sys/kmem.h> | 31 | #include <sys/kmem.h> | |
32 | 32 | |||
33 | #include <dev/usb/usbnet.h> | 33 | #include <dev/usb/usbnet.h> | |
34 | #include <dev/usb/usbdevs.h> | 34 | #include <dev/usb/usbdevs.h> | |
35 | #include <dev/usb/usbcdc.h> | 35 | #include <dev/usb/usbcdc.h> | |
36 | 36 | |||
37 | #include <dev/ic/rndisreg.h> | 37 | #include <dev/ic/rndisreg.h> | |
38 | 38 | |||
39 | #define RNDIS_RX_LIST_CNT 1 | 39 | #define RNDIS_RX_LIST_CNT 1 | |
40 | #define RNDIS_TX_LIST_CNT 1 | 40 | #define RNDIS_TX_LIST_CNT 1 | |
41 | #define RNDIS_BUFSZ 1562 | 41 | #define RNDIS_BUFSZ 1562 | |
42 | 42 | |||
43 | struct urndis_softc { | 43 | struct urndis_softc { | |
44 | struct usbnet sc_un; | 44 | struct usbnet sc_un; | |
45 | 45 | |||
46 | int sc_ifaceno_ctl; | 46 | int sc_ifaceno_ctl; | |
47 | 47 | |||
48 | /* RNDIS device info */ | 48 | /* RNDIS device info */ | |
49 | uint32_t sc_filter; | 49 | uint32_t sc_filter; | |
50 | uint32_t sc_maxppt; | 50 | uint32_t sc_maxppt; | |
51 | uint32_t sc_maxtsz; | 51 | uint32_t sc_maxtsz; | |
52 | uint32_t sc_palign; | 52 | uint32_t sc_palign; | |
53 | }; | 53 | }; | |
54 | 54 | |||
55 | #ifdef URNDIS_DEBUG | 55 | #ifdef URNDIS_DEBUG | |
56 | #define DPRINTF(x) do { printf x; } while (0) | 56 | #define DPRINTF(x) do { printf x; } while (0) | |
57 | #else | 57 | #else | |
58 | #define DPRINTF(x) | 58 | #define DPRINTF(x) | |
59 | #endif | 59 | #endif | |
60 | 60 | |||
61 | #define DEVNAME(un) (device_xname(un->un_dev)) | 61 | #define DEVNAME(un) (device_xname(un->un_dev)) | |
62 | 62 | |||
63 | #define URNDIS_RESPONSE_LEN 0x400 | 63 | #define URNDIS_RESPONSE_LEN 0x400 | |
64 | 64 | |||
65 | #if 0 | 65 | #if 0 | |
66 | static void urndis_watchdog(struct ifnet *); | 66 | static void urndis_watchdog(struct ifnet *); | |
67 | #endif | 67 | #endif | |
68 | 68 | |||
69 | static int urndis_uno_init(struct ifnet *); | 69 | static int urndis_uno_init(struct ifnet *); | |
70 | static void urndis_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 70 | static void urndis_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
71 | uint32_t); | 71 | uint32_t); | |
72 | static unsigned urndis_uno_tx_prepare(struct usbnet *, struct mbuf *, | 72 | static unsigned urndis_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
73 | struct usbnet_chain *); | 73 | struct usbnet_chain *); | |
74 | 74 | |||
75 | static int urndis_init_un(struct ifnet *, struct usbnet *); | 75 | static int urndis_init_un(struct ifnet *, struct usbnet *); | |
76 | 76 | |||
77 | static uint32_t urndis_ctrl_handle_init(struct usbnet *, | 77 | static uint32_t urndis_ctrl_handle_init(struct usbnet *, | |
78 | const struct rndis_comp_hdr *); | 78 | const struct rndis_comp_hdr *); | |
79 | static uint32_t urndis_ctrl_handle_query(struct usbnet *, | 79 | static uint32_t urndis_ctrl_handle_query(struct usbnet *, | |
80 | const struct rndis_comp_hdr *, void **, size_t *); | 80 | const struct rndis_comp_hdr *, void **, size_t *); | |
81 | static uint32_t urndis_ctrl_handle_reset(struct usbnet *, | 81 | static uint32_t urndis_ctrl_handle_reset(struct usbnet *, | |
82 | const struct rndis_comp_hdr *); | 82 | const struct rndis_comp_hdr *); | |
83 | static uint32_t urndis_ctrl_handle_status(struct usbnet *, | 83 | static uint32_t urndis_ctrl_handle_status(struct usbnet *, | |
84 | const struct rndis_comp_hdr *); | 84 | const struct rndis_comp_hdr *); | |
85 | 85 | |||
86 | static uint32_t urndis_ctrl_set(struct usbnet *, uint32_t, void *, | 86 | static uint32_t urndis_ctrl_set(struct usbnet *, uint32_t, void *, | |
87 | size_t); | 87 | size_t); | |
88 | 88 | |||
89 | static int urndis_match(device_t, cfdata_t, void *); | 89 | static int urndis_match(device_t, cfdata_t, void *); | |
90 | static void urndis_attach(device_t, device_t, void *); | 90 | static void urndis_attach(device_t, device_t, void *); | |
91 | 91 | |||
92 | static const struct usbnet_ops urndis_ops = { | 92 | static const struct usbnet_ops urndis_ops = { | |
93 | .uno_init = urndis_uno_init, | 93 | .uno_init = urndis_uno_init, | |
94 | .uno_tx_prepare = urndis_uno_tx_prepare, | 94 | .uno_tx_prepare = urndis_uno_tx_prepare, | |
95 | .uno_rx_loop = urndis_uno_rx_loop, | 95 | .uno_rx_loop = urndis_uno_rx_loop, | |
96 | }; | 96 | }; | |
97 | 97 | |||
98 | CFATTACH_DECL_NEW(urndis, sizeof(struct urndis_softc), | 98 | CFATTACH_DECL_NEW(urndis, sizeof(struct urndis_softc), | |
99 | urndis_match, urndis_attach, usbnet_detach, usbnet_activate); | 99 | urndis_match, urndis_attach, usbnet_detach, usbnet_activate); | |
100 | 100 | |||
101 | /* | 101 | /* | |
102 | * Supported devices that we can't match by class IDs. | 102 | * Supported devices that we can't match by class IDs. | |
103 | */ | 103 | */ | |
104 | static const struct usb_devno urndis_devs[] = { | 104 | static const struct usb_devno urndis_devs[] = { | |
105 | { USB_VENDOR_HTC, USB_PRODUCT_HTC_ANDROID }, | 105 | { USB_VENDOR_HTC, USB_PRODUCT_HTC_ANDROID }, | |
106 | { USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_ANDROID2 }, | 106 | { USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_ANDROID2 }, | |
107 | { USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_ANDROID }, | 107 | { USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_ANDROID }, | |
108 | }; | 108 | }; | |
109 | 109 | |||
110 | static usbd_status | 110 | static usbd_status | |
111 | urndis_ctrl_msg(struct usbnet *un, uint8_t rt, uint8_t r, | 111 | urndis_ctrl_msg(struct usbnet *un, uint8_t rt, uint8_t r, | |
112 | uint16_t index, uint16_t value, void *buf, size_t buflen) | 112 | uint16_t index, uint16_t value, void *buf, size_t buflen) | |
113 | { | 113 | { | |
114 | usb_device_request_t req; | 114 | usb_device_request_t req; | |
115 | 115 | |||
116 | req.bmRequestType = rt; | 116 | req.bmRequestType = rt; | |
117 | req.bRequest = r; | 117 | req.bRequest = r; | |
118 | USETW(req.wValue, value); | 118 | USETW(req.wValue, value); | |
119 | USETW(req.wIndex, index); | 119 | USETW(req.wIndex, index); | |
120 | USETW(req.wLength, buflen); | 120 | USETW(req.wLength, buflen); | |
121 | 121 | |||
122 | return usbd_do_request(un->un_udev, &req, buf); | 122 | return usbd_do_request(un->un_udev, &req, buf); | |
123 | } | 123 | } | |
124 | 124 | |||
125 | static usbd_status | 125 | static usbd_status | |
126 | urndis_ctrl_send(struct usbnet *un, void *buf, size_t len) | 126 | urndis_ctrl_send(struct usbnet *un, void *buf, size_t len) | |
127 | { | 127 | { | |
128 | struct urndis_softc *sc = usbnet_softc(un); | 128 | struct urndis_softc *sc = usbnet_softc(un); | |
129 | usbd_status err; | 129 | usbd_status err; | |
130 | 130 | |||
131 | if (usbnet_isdying(un)) | 131 | if (usbnet_isdying(un)) | |
132 | return(0); | 132 | return(0); | |
133 | 133 | |||
134 | err = urndis_ctrl_msg(un, UT_WRITE_CLASS_INTERFACE, UR_GET_STATUS, | 134 | err = urndis_ctrl_msg(un, UT_WRITE_CLASS_INTERFACE, UR_GET_STATUS, | |
135 | sc->sc_ifaceno_ctl, 0, buf, len); | 135 | sc->sc_ifaceno_ctl, 0, buf, len); | |
136 | 136 | |||
137 | if (err != USBD_NORMAL_COMPLETION) | 137 | if (err != USBD_NORMAL_COMPLETION) | |
138 | printf("%s: %s\n", DEVNAME(un), usbd_errstr(err)); | 138 | printf("%s: %s\n", DEVNAME(un), usbd_errstr(err)); | |
139 | 139 | |||
140 | return err; | 140 | return err; | |
141 | } | 141 | } | |
142 | 142 | |||
143 | static struct rndis_comp_hdr * | 143 | static struct rndis_comp_hdr * | |
144 | urndis_ctrl_recv(struct usbnet *un) | 144 | urndis_ctrl_recv(struct usbnet *un) | |
145 | { | 145 | { | |
146 | struct urndis_softc *sc = usbnet_softc(un); | 146 | struct urndis_softc *sc = usbnet_softc(un); | |
147 | struct rndis_comp_hdr *hdr; | 147 | struct rndis_comp_hdr *hdr; | |
148 | char *buf; | 148 | char *buf; | |
149 | usbd_status err; | 149 | usbd_status err; | |
150 | 150 | |||
151 | if (usbnet_isdying(un)) | 151 | if (usbnet_isdying(un)) | |
152 | return(0); | 152 | return(0); | |
153 | 153 | |||
154 | buf = kmem_alloc(URNDIS_RESPONSE_LEN, KM_SLEEP); | 154 | buf = kmem_alloc(URNDIS_RESPONSE_LEN, KM_SLEEP); | |
155 | err = urndis_ctrl_msg(un, UT_READ_CLASS_INTERFACE, UR_CLEAR_FEATURE, | 155 | err = urndis_ctrl_msg(un, UT_READ_CLASS_INTERFACE, UR_CLEAR_FEATURE, | |
156 | sc->sc_ifaceno_ctl, 0, buf, URNDIS_RESPONSE_LEN); | 156 | sc->sc_ifaceno_ctl, 0, buf, URNDIS_RESPONSE_LEN); | |
157 | 157 | |||
158 | if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER) { | 158 | if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER) { | |
159 | printf("%s: %s\n", DEVNAME(un), usbd_errstr(err)); | 159 | printf("%s: %s\n", DEVNAME(un), usbd_errstr(err)); | |
160 | kmem_free(buf, URNDIS_RESPONSE_LEN); | 160 | kmem_free(buf, URNDIS_RESPONSE_LEN); | |
161 | return NULL; | 161 | return NULL; | |
162 | } | 162 | } | |
163 | 163 | |||
164 | hdr = (struct rndis_comp_hdr *)buf; | 164 | hdr = (struct rndis_comp_hdr *)buf; | |
165 | DPRINTF(("%s: urndis_ctrl_recv: type %#x len %u\n", | 165 | DPRINTF(("%s: urndis_ctrl_recv: type %#x len %u\n", | |
166 | DEVNAME(un), | 166 | DEVNAME(un), | |
167 | le32toh(hdr->rm_type), | 167 | le32toh(hdr->rm_type), | |
168 | le32toh(hdr->rm_len))); | 168 | le32toh(hdr->rm_len))); | |
169 | 169 | |||
170 | if (le32toh(hdr->rm_len) > URNDIS_RESPONSE_LEN) { | 170 | if (le32toh(hdr->rm_len) > URNDIS_RESPONSE_LEN) { | |
171 | printf("%s: ctrl message error: wrong size %u > %u\n", | 171 | printf("%s: ctrl message error: wrong size %u > %u\n", | |
172 | DEVNAME(un), | 172 | DEVNAME(un), | |
173 | le32toh(hdr->rm_len), | 173 | le32toh(hdr->rm_len), | |
174 | URNDIS_RESPONSE_LEN); | 174 | URNDIS_RESPONSE_LEN); | |
175 | kmem_free(buf, URNDIS_RESPONSE_LEN); | 175 | kmem_free(buf, URNDIS_RESPONSE_LEN); | |
176 | return NULL; | 176 | return NULL; | |
177 | } | 177 | } | |
178 | 178 | |||
179 | return hdr; | 179 | return hdr; | |
180 | } | 180 | } | |
181 | 181 | |||
182 | static uint32_t | 182 | static uint32_t | |
183 | urndis_ctrl_handle(struct usbnet *un, struct rndis_comp_hdr *hdr, | 183 | urndis_ctrl_handle(struct usbnet *un, struct rndis_comp_hdr *hdr, | |
184 | void **buf, size_t *bufsz) | 184 | void **buf, size_t *bufsz) | |
185 | { | 185 | { | |
186 | uint32_t rval; | 186 | uint32_t rval; | |
187 | 187 | |||
188 | DPRINTF(("%s: urndis_ctrl_handle\n", DEVNAME(un))); | 188 | DPRINTF(("%s: urndis_ctrl_handle\n", DEVNAME(un))); | |
189 | 189 | |||
190 | if (buf && bufsz) { | 190 | if (buf && bufsz) { | |
191 | *buf = NULL; | 191 | *buf = NULL; | |
192 | *bufsz = 0; | 192 | *bufsz = 0; | |
193 | } | 193 | } | |
194 | 194 | |||
195 | switch (le32toh(hdr->rm_type)) { | 195 | switch (le32toh(hdr->rm_type)) { | |
196 | case REMOTE_NDIS_INITIALIZE_CMPLT: | 196 | case REMOTE_NDIS_INITIALIZE_CMPLT: | |
197 | rval = urndis_ctrl_handle_init(un, hdr); | 197 | rval = urndis_ctrl_handle_init(un, hdr); | |
198 | break; | 198 | break; | |
199 | 199 | |||
200 | case REMOTE_NDIS_QUERY_CMPLT: | 200 | case REMOTE_NDIS_QUERY_CMPLT: | |
201 | rval = urndis_ctrl_handle_query(un, hdr, buf, bufsz); | 201 | rval = urndis_ctrl_handle_query(un, hdr, buf, bufsz); | |
202 | break; | 202 | break; | |
203 | 203 | |||
204 | case REMOTE_NDIS_RESET_CMPLT: | 204 | case REMOTE_NDIS_RESET_CMPLT: | |
205 | rval = urndis_ctrl_handle_reset(un, hdr); | 205 | rval = urndis_ctrl_handle_reset(un, hdr); | |
206 | break; | 206 | break; | |
207 | 207 | |||
208 | case REMOTE_NDIS_KEEPALIVE_CMPLT: | 208 | case REMOTE_NDIS_KEEPALIVE_CMPLT: | |
209 | case REMOTE_NDIS_SET_CMPLT: | 209 | case REMOTE_NDIS_SET_CMPLT: | |
210 | rval = le32toh(hdr->rm_status); | 210 | rval = le32toh(hdr->rm_status); | |
211 | break; | 211 | break; | |
212 | 212 | |||
213 | case REMOTE_NDIS_INDICATE_STATUS_MSG: | 213 | case REMOTE_NDIS_INDICATE_STATUS_MSG: | |
214 | rval = urndis_ctrl_handle_status(un, hdr); | 214 | rval = urndis_ctrl_handle_status(un, hdr); | |
215 | break; | 215 | break; | |
216 | 216 | |||
217 | default: | 217 | default: | |
218 | printf("%s: ctrl message error: unknown event %#x\n", | 218 | printf("%s: ctrl message error: unknown event %#x\n", | |
219 | DEVNAME(un), le32toh(hdr->rm_type)); | 219 | DEVNAME(un), le32toh(hdr->rm_type)); | |
220 | rval = RNDIS_STATUS_FAILURE; | 220 | rval = RNDIS_STATUS_FAILURE; | |
221 | } | 221 | } | |
222 | 222 | |||
223 | kmem_free(hdr, URNDIS_RESPONSE_LEN); | 223 | kmem_free(hdr, URNDIS_RESPONSE_LEN); | |
224 | 224 | |||
225 | return rval; | 225 | return rval; | |
226 | } | 226 | } | |
227 | 227 | |||
228 | static uint32_t | 228 | static uint32_t | |
229 | urndis_ctrl_handle_init(struct usbnet *un, const struct rndis_comp_hdr *hdr) | 229 | urndis_ctrl_handle_init(struct usbnet *un, const struct rndis_comp_hdr *hdr) | |
230 | { | 230 | { | |
231 | struct urndis_softc *sc = usbnet_softc(un); | 231 | struct urndis_softc *sc = usbnet_softc(un); | |
232 | const struct rndis_init_comp *msg; | 232 | const struct rndis_init_comp *msg; | |
233 | 233 | |||
234 | msg = (const struct rndis_init_comp *) hdr; | 234 | msg = (const struct rndis_init_comp *) hdr; | |
235 | 235 | |||
236 | DPRINTF(("%s: urndis_ctrl_handle_init: len %u rid %u status %#x " | 236 | DPRINTF(("%s: urndis_ctrl_handle_init: len %u rid %u status %#x " | |
237 | "ver_major %u ver_minor %u devflags %#x medium %#x pktmaxcnt %u " | 237 | "ver_major %u ver_minor %u devflags %#x medium %#x pktmaxcnt %u " | |
238 | "pktmaxsz %u align %u aflistoffset %u aflistsz %u\n", | 238 | "pktmaxsz %u align %u aflistoffset %u aflistsz %u\n", | |
239 | DEVNAME(un), | 239 | DEVNAME(un), | |
240 | le32toh(msg->rm_len), | 240 | le32toh(msg->rm_len), | |
241 | le32toh(msg->rm_rid), | 241 | le32toh(msg->rm_rid), | |
242 | le32toh(msg->rm_status), | 242 | le32toh(msg->rm_status), | |
243 | le32toh(msg->rm_ver_major), | 243 | le32toh(msg->rm_ver_major), | |
244 | le32toh(msg->rm_ver_minor), | 244 | le32toh(msg->rm_ver_minor), | |
245 | le32toh(msg->rm_devflags), | 245 | le32toh(msg->rm_devflags), | |
246 | le32toh(msg->rm_medium), | 246 | le32toh(msg->rm_medium), | |
247 | le32toh(msg->rm_pktmaxcnt), | 247 | le32toh(msg->rm_pktmaxcnt), | |
248 | le32toh(msg->rm_pktmaxsz), | 248 | le32toh(msg->rm_pktmaxsz), | |
249 | le32toh(msg->rm_align), | 249 | le32toh(msg->rm_align), | |
250 | le32toh(msg->rm_aflistoffset), | 250 | le32toh(msg->rm_aflistoffset), | |
251 | le32toh(msg->rm_aflistsz))); | 251 | le32toh(msg->rm_aflistsz))); | |
252 | 252 | |||
253 | if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) { | 253 | if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) { | |
254 | printf("%s: init failed %#x\n", | 254 | printf("%s: init failed %#x\n", | |
255 | DEVNAME(un), | 255 | DEVNAME(un), | |
256 | le32toh(msg->rm_status)); | 256 | le32toh(msg->rm_status)); | |
257 | 257 | |||
258 | return le32toh(msg->rm_status); | 258 | return le32toh(msg->rm_status); | |
259 | } | 259 | } | |
260 | 260 | |||
261 | if (le32toh(msg->rm_devflags) != RNDIS_DF_CONNECTIONLESS) { | 261 | if (le32toh(msg->rm_devflags) != RNDIS_DF_CONNECTIONLESS) { | |
262 | printf("%s: wrong device type (current type: %#x)\n", | 262 | printf("%s: wrong device type (current type: %#x)\n", | |
263 | DEVNAME(un), | 263 | DEVNAME(un), | |
264 | le32toh(msg->rm_devflags)); | 264 | le32toh(msg->rm_devflags)); | |
265 | 265 | |||
266 | return RNDIS_STATUS_FAILURE; | 266 | return RNDIS_STATUS_FAILURE; | |
267 | } | 267 | } | |
268 | 268 | |||
269 | if (le32toh(msg->rm_medium) != RNDIS_MEDIUM_802_3) { | 269 | if (le32toh(msg->rm_medium) != RNDIS_MEDIUM_802_3) { | |
270 | printf("%s: medium not 802.3 (current medium: %#x)\n", | 270 | printf("%s: medium not 802.3 (current medium: %#x)\n", | |
271 | DEVNAME(un), le32toh(msg->rm_medium)); | 271 | DEVNAME(un), le32toh(msg->rm_medium)); | |
272 | 272 | |||
273 | return RNDIS_STATUS_FAILURE; | 273 | return RNDIS_STATUS_FAILURE; | |
274 | } | 274 | } | |
275 | 275 | |||
276 | if (le32toh(msg->rm_ver_major) != RNDIS_MAJOR_VERSION || | 276 | if (le32toh(msg->rm_ver_major) != RNDIS_MAJOR_VERSION || | |
277 | le32toh(msg->rm_ver_minor) != RNDIS_MINOR_VERSION) { | 277 | le32toh(msg->rm_ver_minor) != RNDIS_MINOR_VERSION) { | |
278 | printf("%s: version not %u.%u (current version: %u.%u)\n", | 278 | printf("%s: version not %u.%u (current version: %u.%u)\n", | |
279 | DEVNAME(un), RNDIS_MAJOR_VERSION, RNDIS_MINOR_VERSION, | 279 | DEVNAME(un), RNDIS_MAJOR_VERSION, RNDIS_MINOR_VERSION, | |
280 | le32toh(msg->rm_ver_major), le32toh(msg->rm_ver_minor)); | 280 | le32toh(msg->rm_ver_major), le32toh(msg->rm_ver_minor)); | |
281 | 281 | |||
282 | return RNDIS_STATUS_FAILURE; | 282 | return RNDIS_STATUS_FAILURE; | |
283 | } | 283 | } | |
284 | 284 | |||
285 | sc->sc_maxppt = le32toh(msg->rm_pktmaxcnt); | 285 | sc->sc_maxppt = le32toh(msg->rm_pktmaxcnt); | |
286 | sc->sc_maxtsz = le32toh(msg->rm_pktmaxsz); | 286 | sc->sc_maxtsz = le32toh(msg->rm_pktmaxsz); | |
287 | sc->sc_palign = 1U << le32toh(msg->rm_align); | 287 | sc->sc_palign = 1U << le32toh(msg->rm_align); | |
288 | 288 | |||
289 | return le32toh(msg->rm_status); | 289 | return le32toh(msg->rm_status); | |
290 | } | 290 | } | |
291 | 291 | |||
292 | static uint32_t | 292 | static uint32_t | |
293 | urndis_ctrl_handle_query(struct usbnet *un, | 293 | urndis_ctrl_handle_query(struct usbnet *un, | |
294 | const struct rndis_comp_hdr *hdr, void **buf, size_t *bufsz) | 294 | const struct rndis_comp_hdr *hdr, void **buf, size_t *bufsz) | |
295 | { | 295 | { | |
296 | const struct rndis_query_comp *msg; | 296 | const struct rndis_query_comp *msg; | |
297 | 297 | |||
298 | msg = (const struct rndis_query_comp *) hdr; | 298 | msg = (const struct rndis_query_comp *) hdr; | |
299 | 299 | |||
300 | DPRINTF(("%s: urndis_ctrl_handle_query: len %u rid %u status %#x " | 300 | DPRINTF(("%s: urndis_ctrl_handle_query: len %u rid %u status %#x " | |
301 | "buflen %u bufoff %u\n", | 301 | "buflen %u bufoff %u\n", | |
302 | DEVNAME(un), | 302 | DEVNAME(un), | |
303 | le32toh(msg->rm_len), | 303 | le32toh(msg->rm_len), | |
304 | le32toh(msg->rm_rid), | 304 | le32toh(msg->rm_rid), | |
305 | le32toh(msg->rm_status), | 305 | le32toh(msg->rm_status), | |
306 | le32toh(msg->rm_infobuflen), | 306 | le32toh(msg->rm_infobuflen), | |
307 | le32toh(msg->rm_infobufoffset))); | 307 | le32toh(msg->rm_infobufoffset))); | |
308 | 308 | |||
309 | if (buf && bufsz) { | 309 | if (buf && bufsz) { | |
310 | *buf = NULL; | 310 | *buf = NULL; | |
311 | *bufsz = 0; | 311 | *bufsz = 0; | |
312 | } | 312 | } | |
313 | 313 | |||
314 | if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) { | 314 | if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) { | |
315 | printf("%s: query failed %#x\n", | 315 | printf("%s: query failed %#x\n", | |
316 | DEVNAME(un), | 316 | DEVNAME(un), | |
317 | le32toh(msg->rm_status)); | 317 | le32toh(msg->rm_status)); | |
318 | 318 | |||
319 | return le32toh(msg->rm_status); | 319 | return le32toh(msg->rm_status); | |
320 | } | 320 | } | |
321 | 321 | |||
322 | if (le32toh(msg->rm_infobuflen) + le32toh(msg->rm_infobufoffset) + | 322 | if (le32toh(msg->rm_infobuflen) + le32toh(msg->rm_infobufoffset) + | |
323 | RNDIS_HEADER_OFFSET > le32toh(msg->rm_len)) { | 323 | RNDIS_HEADER_OFFSET > le32toh(msg->rm_len)) { | |
324 | printf("%s: ctrl message error: invalid query info " | 324 | printf("%s: ctrl message error: invalid query info " | |
325 | "len/offset/end_position(%u/%u/%u) -> " | 325 | "len/offset/end_position(%u/%u/%u) -> " | |
326 | "go out of buffer limit %u\n", | 326 | "go out of buffer limit %u\n", | |
327 | DEVNAME(un), | 327 | DEVNAME(un), | |
328 | le32toh(msg->rm_infobuflen), | 328 | le32toh(msg->rm_infobuflen), | |
329 | le32toh(msg->rm_infobufoffset), | 329 | le32toh(msg->rm_infobufoffset), | |
330 | le32toh(msg->rm_infobuflen) + | 330 | le32toh(msg->rm_infobuflen) + | |
331 | le32toh(msg->rm_infobufoffset) + (uint32_t)RNDIS_HEADER_OFFSET, | 331 | le32toh(msg->rm_infobufoffset) + (uint32_t)RNDIS_HEADER_OFFSET, | |
332 | le32toh(msg->rm_len)); | 332 | le32toh(msg->rm_len)); | |
333 | return RNDIS_STATUS_FAILURE; | 333 | return RNDIS_STATUS_FAILURE; | |
334 | } | 334 | } | |
335 | 335 | |||
336 | if (buf && bufsz) { | 336 | if (buf && bufsz) { | |
337 | const char *p; | 337 | const char *p; | |
338 | 338 | |||
339 | *buf = kmem_alloc(le32toh(msg->rm_infobuflen), KM_SLEEP); | 339 | *buf = kmem_alloc(le32toh(msg->rm_infobuflen), KM_SLEEP); | |
340 | *bufsz = le32toh(msg->rm_infobuflen); | 340 | *bufsz = le32toh(msg->rm_infobuflen); | |
341 | 341 | |||
342 | p = (const char *)&msg->rm_rid; | 342 | p = (const char *)&msg->rm_rid; | |
343 | p += le32toh(msg->rm_infobufoffset); | 343 | p += le32toh(msg->rm_infobufoffset); | |
344 | memcpy(*buf, p, le32toh(msg->rm_infobuflen)); | 344 | memcpy(*buf, p, le32toh(msg->rm_infobuflen)); | |
345 | } | 345 | } | |
346 | 346 | |||
347 | return le32toh(msg->rm_status); | 347 | return le32toh(msg->rm_status); | |
348 | } | 348 | } | |
349 | 349 | |||
350 | static uint32_t | 350 | static uint32_t | |
351 | urndis_ctrl_handle_reset(struct usbnet *un, const struct rndis_comp_hdr *hdr) | 351 | urndis_ctrl_handle_reset(struct usbnet *un, const struct rndis_comp_hdr *hdr) | |
352 | { | 352 | { | |
353 | struct urndis_softc *sc = usbnet_softc(un); | 353 | struct urndis_softc *sc = usbnet_softc(un); | |
354 | const struct rndis_reset_comp *msg; | 354 | const struct rndis_reset_comp *msg; | |
355 | uint32_t rval; | 355 | uint32_t rval; | |
356 | 356 | |||
357 | msg = (const struct rndis_reset_comp *) hdr; | 357 | msg = (const struct rndis_reset_comp *) hdr; | |
358 | 358 | |||
359 | rval = le32toh(msg->rm_status); | 359 | rval = le32toh(msg->rm_status); | |
360 | 360 | |||
361 | DPRINTF(("%s: urndis_ctrl_handle_reset: len %u status %#x " | 361 | DPRINTF(("%s: urndis_ctrl_handle_reset: len %u status %#x " | |
362 | "adrreset %u\n", | 362 | "adrreset %u\n", | |
363 | DEVNAME(un), | 363 | DEVNAME(un), | |
364 | le32toh(msg->rm_len), | 364 | le32toh(msg->rm_len), | |
365 | rval, | 365 | rval, | |
366 | le32toh(msg->rm_adrreset))); | 366 | le32toh(msg->rm_adrreset))); | |
367 | 367 | |||
368 | if (rval != RNDIS_STATUS_SUCCESS) { | 368 | if (rval != RNDIS_STATUS_SUCCESS) { | |
369 | printf("%s: reset failed %#x\n", DEVNAME(un), rval); | 369 | printf("%s: reset failed %#x\n", DEVNAME(un), rval); | |
370 | return rval; | 370 | return rval; | |
371 | } | 371 | } | |
372 | 372 | |||
373 | if (le32toh(msg->rm_adrreset) != 0) { | 373 | if (le32toh(msg->rm_adrreset) != 0) { | |
374 | uint32_t filter; | 374 | uint32_t filter; | |
375 | 375 | |||
376 | filter = htole32(sc->sc_filter); | 376 | filter = htole32(sc->sc_filter); | |
377 | rval = urndis_ctrl_set(un, OID_GEN_CURRENT_PACKET_FILTER, | 377 | rval = urndis_ctrl_set(un, OID_GEN_CURRENT_PACKET_FILTER, | |
378 | &filter, sizeof(filter)); | 378 | &filter, sizeof(filter)); | |
379 | if (rval != RNDIS_STATUS_SUCCESS) { | 379 | if (rval != RNDIS_STATUS_SUCCESS) { | |
380 | printf("%s: unable to reset data filters\n", | 380 | printf("%s: unable to reset data filters\n", | |
381 | DEVNAME(un)); | 381 | DEVNAME(un)); | |
382 | return rval; | 382 | return rval; | |
383 | } | 383 | } | |
384 | } | 384 | } | |
385 | 385 | |||
386 | return rval; | 386 | return rval; | |
387 | } | 387 | } | |
388 | 388 | |||
389 | static uint32_t | 389 | static uint32_t | |
390 | urndis_ctrl_handle_status(struct usbnet *un, | 390 | urndis_ctrl_handle_status(struct usbnet *un, | |
391 | const struct rndis_comp_hdr *hdr) | 391 | const struct rndis_comp_hdr *hdr) | |
392 | { | 392 | { | |
393 | const struct rndis_status_msg *msg; | 393 | const struct rndis_status_msg *msg; | |
394 | uint32_t rval; | 394 | uint32_t rval; | |
395 | 395 | |||
396 | msg = (const struct rndis_status_msg *)hdr; | 396 | msg = (const struct rndis_status_msg *)hdr; | |
397 | 397 | |||
398 | rval = le32toh(msg->rm_status); | 398 | rval = le32toh(msg->rm_status); | |
399 | 399 | |||
400 | DPRINTF(("%s: urndis_ctrl_handle_status: len %u status %#x " | 400 | DPRINTF(("%s: urndis_ctrl_handle_status: len %u status %#x " | |
401 | "stbuflen %u\n", | 401 | "stbuflen %u\n", | |
402 | DEVNAME(un), | 402 | DEVNAME(un), | |
403 | le32toh(msg->rm_len), | 403 | le32toh(msg->rm_len), | |
404 | rval, | 404 | rval, | |
405 | le32toh(msg->rm_stbuflen))); | 405 | le32toh(msg->rm_stbuflen))); | |
406 | 406 | |||
407 | switch (rval) { | 407 | switch (rval) { | |
408 | case RNDIS_STATUS_MEDIA_CONNECT: | 408 | case RNDIS_STATUS_MEDIA_CONNECT: | |
409 | case RNDIS_STATUS_MEDIA_DISCONNECT: | 409 | case RNDIS_STATUS_MEDIA_DISCONNECT: | |
410 | case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG: | 410 | case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG: | |
411 | rval = RNDIS_STATUS_SUCCESS; | 411 | rval = RNDIS_STATUS_SUCCESS; | |
412 | break; | 412 | break; | |
413 | 413 | |||
414 | default: | 414 | default: | |
415 | printf("%s: status %#x\n", DEVNAME(un), rval); | 415 | printf("%s: status %#x\n", DEVNAME(un), rval); | |
416 | } | 416 | } | |
417 | 417 | |||
418 | return rval; | 418 | return rval; | |
419 | } | 419 | } | |
420 | 420 | |||
421 | static uint32_t | 421 | static uint32_t | |
422 | urndis_ctrl_init(struct usbnet *un) | 422 | urndis_ctrl_init(struct usbnet *un) | |
423 | { | 423 | { | |
424 | struct rndis_init_req *msg; | 424 | struct rndis_init_req *msg; | |
425 | uint32_t rval; | 425 | uint32_t rval; | |
426 | struct rndis_comp_hdr *hdr; | 426 | struct rndis_comp_hdr *hdr; | |
427 | 427 | |||
428 | msg = kmem_alloc(sizeof(*msg), KM_SLEEP); | 428 | msg = kmem_alloc(sizeof(*msg), KM_SLEEP); | |
429 | msg->rm_type = htole32(REMOTE_NDIS_INITIALIZE_MSG); | 429 | msg->rm_type = htole32(REMOTE_NDIS_INITIALIZE_MSG); | |
430 | msg->rm_len = htole32(sizeof(*msg)); | 430 | msg->rm_len = htole32(sizeof(*msg)); | |
431 | msg->rm_rid = htole32(0); | 431 | msg->rm_rid = htole32(0); | |
432 | msg->rm_ver_major = htole32(RNDIS_MAJOR_VERSION); | 432 | msg->rm_ver_major = htole32(RNDIS_MAJOR_VERSION); | |
433 | msg->rm_ver_minor = htole32(RNDIS_MINOR_VERSION); | 433 | msg->rm_ver_minor = htole32(RNDIS_MINOR_VERSION); | |
434 | msg->rm_max_xfersz = htole32(RNDIS_BUFSZ); | 434 | msg->rm_max_xfersz = htole32(RNDIS_BUFSZ); | |
435 | 435 | |||
436 | DPRINTF(("%s: urndis_ctrl_init send: type %u len %u rid %u ver_major %u " | 436 | DPRINTF(("%s: urndis_ctrl_init send: type %u len %u rid %u ver_major %u " | |
437 | "ver_minor %u max_xfersz %u\n", | 437 | "ver_minor %u max_xfersz %u\n", | |
438 | DEVNAME(un), | 438 | DEVNAME(un), | |
439 | le32toh(msg->rm_type), | 439 | le32toh(msg->rm_type), | |
440 | le32toh(msg->rm_len), | 440 | le32toh(msg->rm_len), | |
441 | le32toh(msg->rm_rid), | 441 | le32toh(msg->rm_rid), | |
442 | le32toh(msg->rm_ver_major), | 442 | le32toh(msg->rm_ver_major), | |
443 | le32toh(msg->rm_ver_minor), | 443 | le32toh(msg->rm_ver_minor), | |
444 | le32toh(msg->rm_max_xfersz))); | 444 | le32toh(msg->rm_max_xfersz))); | |
445 | 445 | |||
446 | rval = urndis_ctrl_send(un, msg, sizeof(*msg)); | 446 | rval = urndis_ctrl_send(un, msg, sizeof(*msg)); | |
447 | kmem_free(msg, sizeof(*msg)); | 447 | kmem_free(msg, sizeof(*msg)); | |
448 | 448 | |||
449 | if (rval != RNDIS_STATUS_SUCCESS) { | 449 | if (rval != RNDIS_STATUS_SUCCESS) { | |
450 | printf("%s: init failed\n", DEVNAME(un)); | 450 | printf("%s: init failed\n", DEVNAME(un)); | |
451 | return rval; | 451 | return rval; | |
452 | } | 452 | } | |
453 | 453 | |||
454 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | 454 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | |
455 | printf("%s: unable to get init response\n", DEVNAME(un)); | 455 | printf("%s: unable to get init response\n", DEVNAME(un)); | |
456 | return RNDIS_STATUS_FAILURE; | 456 | return RNDIS_STATUS_FAILURE; | |
457 | } | 457 | } | |
458 | rval = urndis_ctrl_handle(un, hdr, NULL, NULL); | 458 | rval = urndis_ctrl_handle(un, hdr, NULL, NULL); | |
459 | 459 | |||
460 | return rval; | 460 | return rval; | |
461 | } | 461 | } | |
462 | 462 | |||
463 | #if 0 | 463 | #if 0 | |
464 | static uint32_t | 464 | static uint32_t | |
465 | urndis_ctrl_halt(struct usbnet *un) | 465 | urndis_ctrl_halt(struct usbnet *un) | |
466 | { | 466 | { | |
467 | struct rndis_halt_req *msg; | 467 | struct rndis_halt_req *msg; | |
468 | uint32_t rval; | 468 | uint32_t rval; | |
469 | 469 | |||
470 | msg = kmem_alloc(sizeof(*msg), KM_SLEEP); | 470 | msg = kmem_alloc(sizeof(*msg), KM_SLEEP); | |
471 | msg->rm_type = htole32(REMOTE_NDIS_HALT_MSG); | 471 | msg->rm_type = htole32(REMOTE_NDIS_HALT_MSG); | |
472 | msg->rm_len = htole32(sizeof(*msg)); | 472 | msg->rm_len = htole32(sizeof(*msg)); | |
473 | msg->rm_rid = 0; | 473 | msg->rm_rid = 0; | |
474 | 474 | |||
475 | DPRINTF(("%s: urndis_ctrl_halt send: type %u len %u rid %u\n", | 475 | DPRINTF(("%s: urndis_ctrl_halt send: type %u len %u rid %u\n", | |
476 | DEVNAME(un), | 476 | DEVNAME(un), | |
477 | le32toh(msg->rm_type), | 477 | le32toh(msg->rm_type), | |
478 | le32toh(msg->rm_len), | 478 | le32toh(msg->rm_len), | |
479 | le32toh(msg->rm_rid))); | 479 | le32toh(msg->rm_rid))); | |
480 | 480 | |||
481 | rval = urndis_ctrl_send(un, msg, sizeof(*msg)); | 481 | rval = urndis_ctrl_send(un, msg, sizeof(*msg)); | |
482 | kmem_free(msg, sizeof(*msg)); | 482 | kmem_free(msg, sizeof(*msg)); | |
483 | 483 | |||
484 | if (rval != RNDIS_STATUS_SUCCESS) | 484 | if (rval != RNDIS_STATUS_SUCCESS) | |
485 | printf("%s: halt failed\n", DEVNAME(un)); | 485 | printf("%s: halt failed\n", DEVNAME(un)); | |
486 | 486 | |||
487 | return rval; | 487 | return rval; | |
488 | } | 488 | } | |
489 | #endif | 489 | #endif | |
490 | 490 | |||
491 | static uint32_t | 491 | static uint32_t | |
492 | urndis_ctrl_query(struct usbnet *un, uint32_t oid, | 492 | urndis_ctrl_query(struct usbnet *un, uint32_t oid, | |
493 | void *qbuf, size_t qlen, | 493 | void *qbuf, size_t qlen, | |
494 | void **rbuf, size_t *rbufsz) | 494 | void **rbuf, size_t *rbufsz) | |
495 | { | 495 | { | |
496 | struct rndis_query_req *msg; | 496 | struct rndis_query_req *msg; | |
497 | uint32_t rval; | 497 | uint32_t rval; | |
498 | struct rndis_comp_hdr *hdr; | 498 | struct rndis_comp_hdr *hdr; | |
499 | 499 | |||
500 | msg = kmem_alloc(sizeof(*msg) + qlen, KM_SLEEP); | 500 | msg = kmem_alloc(sizeof(*msg) + qlen, KM_SLEEP); | |
501 | msg->rm_type = htole32(REMOTE_NDIS_QUERY_MSG); | 501 | msg->rm_type = htole32(REMOTE_NDIS_QUERY_MSG); | |
502 | msg->rm_len = htole32(sizeof(*msg) + qlen); | 502 | msg->rm_len = htole32(sizeof(*msg) + qlen); | |
503 | msg->rm_rid = 0; /* XXX */ | 503 | msg->rm_rid = 0; /* XXX */ | |
504 | msg->rm_oid = htole32(oid); | 504 | msg->rm_oid = htole32(oid); | |
505 | msg->rm_infobuflen = htole32(qlen); | 505 | msg->rm_infobuflen = htole32(qlen); | |
506 | if (qlen != 0) { | 506 | if (qlen != 0) { | |
507 | msg->rm_infobufoffset = htole32(20); | 507 | msg->rm_infobufoffset = htole32(20); | |
508 | memcpy((char*)msg + 20, qbuf, qlen); | 508 | memcpy((char*)msg + 20, qbuf, qlen); | |
509 | } else | 509 | } else | |
510 | msg->rm_infobufoffset = 0; | 510 | msg->rm_infobufoffset = 0; | |
511 | msg->rm_devicevchdl = 0; | 511 | msg->rm_devicevchdl = 0; | |
512 | 512 | |||
513 | DPRINTF(("%s: urndis_ctrl_query send: type %u len %u rid %u oid %#x " | 513 | DPRINTF(("%s: urndis_ctrl_query send: type %u len %u rid %u oid %#x " | |
514 | "infobuflen %u infobufoffset %u devicevchdl %u\n", | 514 | "infobuflen %u infobufoffset %u devicevchdl %u\n", | |
515 | DEVNAME(un), | 515 | DEVNAME(un), | |
516 | le32toh(msg->rm_type), | 516 | le32toh(msg->rm_type), | |
517 | le32toh(msg->rm_len), | 517 | le32toh(msg->rm_len), | |
518 | le32toh(msg->rm_rid), | 518 | le32toh(msg->rm_rid), | |
519 | le32toh(msg->rm_oid), | 519 | le32toh(msg->rm_oid), | |
520 | le32toh(msg->rm_infobuflen), | 520 | le32toh(msg->rm_infobuflen), | |
521 | le32toh(msg->rm_infobufoffset), | 521 | le32toh(msg->rm_infobufoffset), | |
522 | le32toh(msg->rm_devicevchdl))); | 522 | le32toh(msg->rm_devicevchdl))); | |
523 | 523 | |||
524 | rval = urndis_ctrl_send(un, msg, sizeof(*msg)); | 524 | rval = urndis_ctrl_send(un, msg, sizeof(*msg)); | |
525 | kmem_free(msg, sizeof(*msg) + qlen); | 525 | kmem_free(msg, sizeof(*msg) + qlen); | |
526 | 526 | |||
527 | if (rval != RNDIS_STATUS_SUCCESS) { | 527 | if (rval != RNDIS_STATUS_SUCCESS) { | |
528 | printf("%s: query failed\n", DEVNAME(un)); | 528 | printf("%s: query failed\n", DEVNAME(un)); | |
529 | return rval; | 529 | return rval; | |
530 | } | 530 | } | |
531 | 531 | |||
532 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | 532 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | |
533 | printf("%s: unable to get query response\n", DEVNAME(un)); | 533 | printf("%s: unable to get query response\n", DEVNAME(un)); | |
534 | return RNDIS_STATUS_FAILURE; | 534 | return RNDIS_STATUS_FAILURE; | |
535 | } | 535 | } | |
536 | rval = urndis_ctrl_handle(un, hdr, rbuf, rbufsz); | 536 | rval = urndis_ctrl_handle(un, hdr, rbuf, rbufsz); | |
537 | 537 | |||
538 | return rval; | 538 | return rval; | |
539 | } | 539 | } | |
540 | 540 | |||
541 | static uint32_t | 541 | static uint32_t | |
542 | urndis_ctrl_set(struct usbnet *un, uint32_t oid, void *buf, size_t len) | 542 | urndis_ctrl_set(struct usbnet *un, uint32_t oid, void *buf, size_t len) | |
543 | { | 543 | { | |
544 | struct rndis_set_req *msg; | 544 | struct rndis_set_req *msg; | |
545 | uint32_t rval; | 545 | uint32_t rval; | |
546 | struct rndis_comp_hdr *hdr; | 546 | struct rndis_comp_hdr *hdr; | |
547 | 547 | |||
548 | msg = kmem_alloc(sizeof(*msg) + len, KM_SLEEP); | 548 | msg = kmem_alloc(sizeof(*msg) + len, KM_SLEEP); | |
549 | msg->rm_type = htole32(REMOTE_NDIS_SET_MSG); | 549 | msg->rm_type = htole32(REMOTE_NDIS_SET_MSG); | |
550 | msg->rm_len = htole32(sizeof(*msg) + len); | 550 | msg->rm_len = htole32(sizeof(*msg) + len); | |
551 | msg->rm_rid = 0; /* XXX */ | 551 | msg->rm_rid = 0; /* XXX */ | |
552 | msg->rm_oid = htole32(oid); | 552 | msg->rm_oid = htole32(oid); | |
553 | msg->rm_infobuflen = htole32(len); | 553 | msg->rm_infobuflen = htole32(len); | |
554 | if (len != 0) { | 554 | if (len != 0) { | |
555 | msg->rm_infobufoffset = htole32(20); | 555 | msg->rm_infobufoffset = htole32(20); | |
556 | memcpy((char*)msg + 20, buf, len); | 556 | memcpy((char*)msg + 20, buf, len); | |
557 | } else | 557 | } else | |
558 | msg->rm_infobufoffset = 0; | 558 | msg->rm_infobufoffset = 0; | |
559 | msg->rm_devicevchdl = 0; | 559 | msg->rm_devicevchdl = 0; | |
560 | 560 | |||
561 | DPRINTF(("%s: urndis_ctrl_set send: type %u len %u rid %u oid %#x " | 561 | DPRINTF(("%s: urndis_ctrl_set send: type %u len %u rid %u oid %#x " | |
562 | "infobuflen %u infobufoffset %u devicevchdl %u\n", | 562 | "infobuflen %u infobufoffset %u devicevchdl %u\n", | |
563 | DEVNAME(un), | 563 | DEVNAME(un), | |
564 | le32toh(msg->rm_type), | 564 | le32toh(msg->rm_type), | |
565 | le32toh(msg->rm_len), | 565 | le32toh(msg->rm_len), | |
566 | le32toh(msg->rm_rid), | 566 | le32toh(msg->rm_rid), | |
567 | le32toh(msg->rm_oid), | 567 | le32toh(msg->rm_oid), | |
568 | le32toh(msg->rm_infobuflen), | 568 | le32toh(msg->rm_infobuflen), | |
569 | le32toh(msg->rm_infobufoffset), | 569 | le32toh(msg->rm_infobufoffset), | |
570 | le32toh(msg->rm_devicevchdl))); | 570 | le32toh(msg->rm_devicevchdl))); | |
571 | 571 | |||
572 | rval = urndis_ctrl_send(un, msg, sizeof(*msg)); | 572 | rval = urndis_ctrl_send(un, msg, sizeof(*msg)); | |
573 | kmem_free(msg, sizeof(*msg) + len); | 573 | kmem_free(msg, sizeof(*msg) + len); | |
574 | 574 | |||
575 | if (rval != RNDIS_STATUS_SUCCESS) { | 575 | if (rval != RNDIS_STATUS_SUCCESS) { | |
576 | printf("%s: set failed\n", DEVNAME(un)); | 576 | printf("%s: set failed\n", DEVNAME(un)); | |
577 | return rval; | 577 | return rval; | |
578 | } | 578 | } | |
579 | 579 | |||
580 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | 580 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | |
581 | printf("%s: unable to get set response\n", DEVNAME(un)); | 581 | printf("%s: unable to get set response\n", DEVNAME(un)); | |
582 | return RNDIS_STATUS_FAILURE; | 582 | return RNDIS_STATUS_FAILURE; | |
583 | } | 583 | } | |
584 | rval = urndis_ctrl_handle(un, hdr, NULL, NULL); | 584 | rval = urndis_ctrl_handle(un, hdr, NULL, NULL); | |
585 | if (rval != RNDIS_STATUS_SUCCESS) | 585 | if (rval != RNDIS_STATUS_SUCCESS) | |
586 | printf("%s: set failed %#x\n", DEVNAME(un), rval); | 586 | printf("%s: set failed %#x\n", DEVNAME(un), rval); | |
587 | 587 | |||
588 | return rval; | 588 | return rval; | |
589 | } | 589 | } | |
590 | 590 | |||
591 | #if 0 | 591 | #if 0 | |
592 | static uint32_t | 592 | static uint32_t | |
593 | urndis_ctrl_set_param(struct urndis_softc *un, | 593 | urndis_ctrl_set_param(struct urndis_softc *un, | |
594 | const char *name, | 594 | const char *name, | |
595 | uint32_t type, | 595 | uint32_t type, | |
596 | void *buf, | 596 | void *buf, | |
597 | size_t len) | 597 | size_t len) | |
598 | { | 598 | { | |
599 | struct rndis_set_parameter *param; | 599 | struct rndis_set_parameter *param; | |
600 | uint32_t rval; | 600 | uint32_t rval; | |
601 | size_t namelen, tlen; | 601 | size_t namelen, tlen; | |
602 | 602 | |||
603 | if (name) | 603 | if (name) | |
604 | namelen = strlen(name); | 604 | namelen = strlen(name); | |
605 | else | 605 | else | |
606 | namelen = 0; | 606 | namelen = 0; | |
607 | tlen = sizeof(*param) + len + namelen; | 607 | tlen = sizeof(*param) + len + namelen; | |
608 | param = kmem_alloc(tlen, KM_SLEEP); | 608 | param = kmem_alloc(tlen, KM_SLEEP); | |
609 | param->rm_namelen = htole32(namelen); | 609 | param->rm_namelen = htole32(namelen); | |
610 | param->rm_valuelen = htole32(len); | 610 | param->rm_valuelen = htole32(len); | |
611 | param->rm_type = htole32(type); | 611 | param->rm_type = htole32(type); | |
612 | if (namelen != 0) { | 612 | if (namelen != 0) { | |
613 | param->rm_nameoffset = htole32(20); | 613 | param->rm_nameoffset = htole32(20); | |
614 | memcpy(param + 20, name, namelen); | 614 | memcpy(param + 20, name, namelen); | |
615 | } else | 615 | } else | |
616 | param->rm_nameoffset = 0; | 616 | param->rm_nameoffset = 0; | |
617 | if (len != 0) { | 617 | if (len != 0) { | |
618 | param->rm_valueoffset = htole32(20 + namelen); | 618 | param->rm_valueoffset = htole32(20 + namelen); | |
619 | memcpy(param + 20 + namelen, buf, len); | 619 | memcpy(param + 20 + namelen, buf, len); | |
620 | } else | 620 | } else | |
621 | param->rm_valueoffset = 0; | 621 | param->rm_valueoffset = 0; | |
622 | 622 | |||
623 | DPRINTF(("%s: urndis_ctrl_set_param send: nameoffset %u namelen %u " | 623 | DPRINTF(("%s: urndis_ctrl_set_param send: nameoffset %u namelen %u " | |
624 | "type %#x valueoffset %u valuelen %u\n", | 624 | "type %#x valueoffset %u valuelen %u\n", | |
625 | DEVNAME(un), | 625 | DEVNAME(un), | |
626 | le32toh(param->rm_nameoffset), | 626 | le32toh(param->rm_nameoffset), | |
627 | le32toh(param->rm_namelen), | 627 | le32toh(param->rm_namelen), | |
628 | le32toh(param->rm_type), | 628 | le32toh(param->rm_type), | |
629 | le32toh(param->rm_valueoffset), | 629 | le32toh(param->rm_valueoffset), | |
630 | le32toh(param->rm_valuelen))); | 630 | le32toh(param->rm_valuelen))); | |
631 | 631 | |||
632 | rval = urndis_ctrl_set(un, OID_GEN_RNDIS_CONFIG_PARAMETER, param, tlen); | 632 | rval = urndis_ctrl_set(un, OID_GEN_RNDIS_CONFIG_PARAMETER, param, tlen); | |
633 | kmem_free(param, tlen); | 633 | kmem_free(param, tlen); | |
634 | if (rval != RNDIS_STATUS_SUCCESS) | 634 | if (rval != RNDIS_STATUS_SUCCESS) | |
635 | printf("%s: set param failed %#x\n", DEVNAME(un), rval); | 635 | printf("%s: set param failed %#x\n", DEVNAME(un), rval); | |
636 | 636 | |||
637 | return rval; | 637 | return rval; | |
638 | } | 638 | } | |
639 | 639 | |||
640 | /* XXX : adrreset, get it from response */ | 640 | /* XXX : adrreset, get it from response */ | |
641 | static uint32_t | 641 | static uint32_t | |
642 | urndis_ctrl_reset(struct usbnet *un) | 642 | urndis_ctrl_reset(struct usbnet *un) | |
643 | { | 643 | { | |
644 | struct rndis_reset_req *reset; | 644 | struct rndis_reset_req *reset; | |
645 | uint32_t rval; | 645 | uint32_t rval; | |
646 | struct rndis_comp_hdr *hdr; | 646 | struct rndis_comp_hdr *hdr; | |
647 | 647 | |||
648 | reset = kmem_alloc(sizeof(*reset), KM_SLEEP); | 648 | reset = kmem_alloc(sizeof(*reset), KM_SLEEP); | |
649 | reset->rm_type = htole32(REMOTE_NDIS_RESET_MSG); | 649 | reset->rm_type = htole32(REMOTE_NDIS_RESET_MSG); | |
650 | reset->rm_len = htole32(sizeof(*reset)); | 650 | reset->rm_len = htole32(sizeof(*reset)); | |
651 | reset->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */ | 651 | reset->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */ | |
652 | 652 | |||
653 | DPRINTF(("%s: urndis_ctrl_reset send: type %u len %u rid %u\n", | 653 | DPRINTF(("%s: urndis_ctrl_reset send: type %u len %u rid %u\n", | |
654 | DEVNAME(un), | 654 | DEVNAME(un), | |
655 | le32toh(reset->rm_type), | 655 | le32toh(reset->rm_type), | |
656 | le32toh(reset->rm_len), | 656 | le32toh(reset->rm_len), | |
657 | le32toh(reset->rm_rid))); | 657 | le32toh(reset->rm_rid))); | |
658 | 658 | |||
659 | rval = urndis_ctrl_send(un, reset, sizeof(*reset)); | 659 | rval = urndis_ctrl_send(un, reset, sizeof(*reset)); | |
660 | kmem_free(reset, sizeof(*reset)); | 660 | kmem_free(reset, sizeof(*reset)); | |
661 | 661 | |||
662 | if (rval != RNDIS_STATUS_SUCCESS) { | 662 | if (rval != RNDIS_STATUS_SUCCESS) { | |
663 | printf("%s: reset failed\n", DEVNAME(un)); | 663 | printf("%s: reset failed\n", DEVNAME(un)); | |
664 | return rval; | 664 | return rval; | |
665 | } | 665 | } | |
666 | 666 | |||
667 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | 667 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | |
668 | printf("%s: unable to get reset response\n", DEVNAME(un)); | 668 | printf("%s: unable to get reset response\n", DEVNAME(un)); | |
669 | return RNDIS_STATUS_FAILURE; | 669 | return RNDIS_STATUS_FAILURE; | |
670 | } | 670 | } | |
671 | rval = urndis_ctrl_handle(un, hdr, NULL, NULL); | 671 | rval = urndis_ctrl_handle(un, hdr, NULL, NULL); | |
672 | 672 | |||
673 | return rval; | 673 | return rval; | |
674 | } | 674 | } | |
675 | 675 | |||
676 | static uint32_t | 676 | static uint32_t | |
677 | urndis_ctrl_keepalive(struct usbnet *un) | 677 | urndis_ctrl_keepalive(struct usbnet *un) | |
678 | { | 678 | { | |
679 | struct rndis_keepalive_req *keep; | 679 | struct rndis_keepalive_req *keep; | |
680 | uint32_t rval; | 680 | uint32_t rval; | |
681 | struct rndis_comp_hdr *hdr; | 681 | struct rndis_comp_hdr *hdr; | |
682 | 682 | |||
683 | keep = kmem_alloc(sizeof(*keep), KM_SLEEP); | 683 | keep = kmem_alloc(sizeof(*keep), KM_SLEEP); | |
684 | keep->rm_type = htole32(REMOTE_NDIS_KEEPALIVE_MSG); | 684 | keep->rm_type = htole32(REMOTE_NDIS_KEEPALIVE_MSG); | |
685 | keep->rm_len = htole32(sizeof(*keep)); | 685 | keep->rm_len = htole32(sizeof(*keep)); | |
686 | keep->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */ | 686 | keep->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */ | |
687 | 687 | |||
688 | DPRINTF(("%s: urndis_ctrl_keepalive: type %u len %u rid %u\n", | 688 | DPRINTF(("%s: urndis_ctrl_keepalive: type %u len %u rid %u\n", | |
689 | DEVNAME(un), | 689 | DEVNAME(un), | |
690 | le32toh(keep->rm_type), | 690 | le32toh(keep->rm_type), | |
691 | le32toh(keep->rm_len), | 691 | le32toh(keep->rm_len), | |
692 | le32toh(keep->rm_rid))); | 692 | le32toh(keep->rm_rid))); | |
693 | 693 | |||
694 | rval = urndis_ctrl_send(un, keep, sizeof(*keep)); | 694 | rval = urndis_ctrl_send(un, keep, sizeof(*keep)); | |
695 | kmem_free(keep, sizeof(*keep)); | 695 | kmem_free(keep, sizeof(*keep)); | |
696 | 696 | |||
697 | if (rval != RNDIS_STATUS_SUCCESS) { | 697 | if (rval != RNDIS_STATUS_SUCCESS) { | |
698 | printf("%s: keepalive failed\n", DEVNAME(un)); | 698 | printf("%s: keepalive failed\n", DEVNAME(un)); | |
699 | return rval; | 699 | return rval; | |
700 | } | 700 | } | |
701 | 701 | |||
702 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | 702 | if ((hdr = urndis_ctrl_recv(un)) == NULL) { | |
703 | printf("%s: unable to get keepalive response\n", DEVNAME(un)); | 703 | printf("%s: unable to get keepalive response\n", DEVNAME(un)); | |
704 | return RNDIS_STATUS_FAILURE; | 704 | return RNDIS_STATUS_FAILURE; | |
705 | } | 705 | } | |
706 | rval = urndis_ctrl_handle(un, hdr, NULL, NULL); | 706 | rval = urndis_ctrl_handle(un, hdr, NULL, NULL); | |
707 | if (rval != RNDIS_STATUS_SUCCESS) { | 707 | if (rval != RNDIS_STATUS_SUCCESS) { | |
708 | printf("%s: keepalive failed %#x\n", DEVNAME(un), rval); | 708 | printf("%s: keepalive failed %#x\n", DEVNAME(un), rval); | |
709 | urndis_ctrl_reset(un); | 709 | urndis_ctrl_reset(un); | |
710 | } | 710 | } | |
711 | 711 | |||
712 | return rval; | 712 | return rval; | |
713 | } | 713 | } | |
714 | #endif | 714 | #endif | |
715 | 715 | |||
716 | static unsigned | 716 | static unsigned | |
717 | urndis_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 717 | urndis_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
718 | { | 718 | { | |
719 | struct rndis_packet_msg *msg; | 719 | struct rndis_packet_msg *msg; | |
720 | 720 | |||
721 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(*msg)) | 721 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(*msg)) | |
722 | return 0; | 722 | return 0; | |
723 | 723 | |||
724 | msg = (struct rndis_packet_msg *)c->unc_buf; | 724 | msg = (struct rndis_packet_msg *)c->unc_buf; | |
725 | 725 | |||
726 | memset(msg, 0, sizeof(*msg)); | 726 | memset(msg, 0, sizeof(*msg)); | |
727 | msg->rm_type = htole32(REMOTE_NDIS_PACKET_MSG); | 727 | msg->rm_type = htole32(REMOTE_NDIS_PACKET_MSG); | |
728 | msg->rm_len = htole32(sizeof(*msg) + m->m_pkthdr.len); | 728 | msg->rm_len = htole32(sizeof(*msg) + m->m_pkthdr.len); | |
729 | 729 | |||
730 | msg->rm_dataoffset = htole32(RNDIS_DATA_OFFSET); | 730 | msg->rm_dataoffset = htole32(RNDIS_DATA_OFFSET); | |
731 | msg->rm_datalen = htole32(m->m_pkthdr.len); | 731 | msg->rm_datalen = htole32(m->m_pkthdr.len); | |
732 | 732 | |||
733 | m_copydata(m, 0, m->m_pkthdr.len, | 733 | m_copydata(m, 0, m->m_pkthdr.len, | |
734 | ((char*)msg + RNDIS_DATA_OFFSET + RNDIS_HEADER_OFFSET)); | 734 | ((char*)msg + RNDIS_DATA_OFFSET + RNDIS_HEADER_OFFSET)); | |
735 | 735 | |||
736 | DPRINTF(("%s: %s type %#x len %u data(off %u len %u)\n", | 736 | DPRINTF(("%s: %s type %#x len %u data(off %u len %u)\n", | |
737 | __func__, | 737 | __func__, | |
738 | DEVNAME(un), | 738 | DEVNAME(un), | |
739 | le32toh(msg->rm_type), | 739 | le32toh(msg->rm_type), | |
740 | le32toh(msg->rm_len), | 740 | le32toh(msg->rm_len), | |
741 | le32toh(msg->rm_dataoffset), | 741 | le32toh(msg->rm_dataoffset), | |
742 | le32toh(msg->rm_datalen))); | 742 | le32toh(msg->rm_datalen))); | |
743 | 743 | |||
744 | return le32toh(msg->rm_len); | 744 | return le32toh(msg->rm_len); | |
745 | } | 745 | } | |
746 | 746 | |||
747 | static void | 747 | static void | |
748 | urndis_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, | 748 | urndis_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, | |
749 | uint32_t total_len) | 749 | uint32_t total_len) | |
750 | { | 750 | { | |
751 | struct rndis_packet_msg *msg; | 751 | struct rndis_packet_msg *msg; | |
752 | struct ifnet *ifp = usbnet_ifp(un); | 752 | struct ifnet *ifp = usbnet_ifp(un); | |
753 | int offset; | 753 | int offset; | |
754 | 754 | |||
755 | offset = 0; | 755 | offset = 0; | |
756 | 756 | |||
757 | while (total_len > 1) { | 757 | while (total_len > 1) { | |
758 | msg = (struct rndis_packet_msg *)((char*)c->unc_buf + offset); | 758 | msg = (struct rndis_packet_msg *)((char*)c->unc_buf + offset); | |
759 | 759 | |||
760 | DPRINTF(("%s: %s buffer size left %u\n", DEVNAME(un), __func__, | 760 | DPRINTF(("%s: %s buffer size left %u\n", DEVNAME(un), __func__, | |
761 | total_len)); | 761 | total_len)); | |
762 | 762 | |||
763 | if (total_len < sizeof(*msg)) { | 763 | if (total_len < sizeof(*msg)) { | |
764 | printf("%s: urndis_decap invalid buffer total_len %u < " | 764 | printf("%s: urndis_decap invalid buffer total_len %u < " | |
765 | "minimum header %zu\n", | 765 | "minimum header %zu\n", | |
766 | DEVNAME(un), | 766 | DEVNAME(un), | |
767 | total_len, | 767 | total_len, | |
768 | sizeof(*msg)); | 768 | sizeof(*msg)); | |
769 | return; | 769 | return; | |
770 | } | 770 | } | |
771 | 771 | |||
772 | DPRINTF(("%s: urndis_decap total_len %u data(off:%u len:%u) " | 772 | DPRINTF(("%s: urndis_decap total_len %u data(off:%u len:%u) " | |
773 | "oobdata(off:%u len:%u nb:%u) perpacket(off:%u len:%u)\n", | 773 | "oobdata(off:%u len:%u nb:%u) perpacket(off:%u len:%u)\n", | |
774 | DEVNAME(un), | 774 | DEVNAME(un), | |
775 | le32toh(msg->rm_len), | 775 | le32toh(msg->rm_len), | |
776 | le32toh(msg->rm_dataoffset), | 776 | le32toh(msg->rm_dataoffset), | |
777 | le32toh(msg->rm_datalen), | 777 | le32toh(msg->rm_datalen), | |
778 | le32toh(msg->rm_oobdataoffset), | 778 | le32toh(msg->rm_oobdataoffset), | |
779 | le32toh(msg->rm_oobdatalen), | 779 | le32toh(msg->rm_oobdatalen), | |
780 | le32toh(msg->rm_oobdataelements), | 780 | le32toh(msg->rm_oobdataelements), | |
781 | le32toh(msg->rm_pktinfooffset), | 781 | le32toh(msg->rm_pktinfooffset), | |
782 | le32toh(msg->rm_pktinfooffset))); | 782 | le32toh(msg->rm_pktinfooffset))); | |
783 | 783 | |||
784 | if (le32toh(msg->rm_type) != REMOTE_NDIS_PACKET_MSG) { | 784 | if (le32toh(msg->rm_type) != REMOTE_NDIS_PACKET_MSG) { | |
785 | printf("%s: urndis_decap invalid type %#x != %#x\n", | 785 | printf("%s: urndis_decap invalid type %#x != %#x\n", | |
786 | DEVNAME(un), | 786 | DEVNAME(un), | |
787 | le32toh(msg->rm_type), | 787 | le32toh(msg->rm_type), | |
788 | REMOTE_NDIS_PACKET_MSG); | 788 | REMOTE_NDIS_PACKET_MSG); | |
789 | return; | 789 | return; | |
790 | } | 790 | } | |
791 | if (le32toh(msg->rm_len) < sizeof(*msg)) { | 791 | if (le32toh(msg->rm_len) < sizeof(*msg)) { | |
792 | printf("%s: urndis_decap invalid msg len %u < %zu\n", | 792 | printf("%s: urndis_decap invalid msg len %u < %zu\n", | |
793 | DEVNAME(un), | 793 | DEVNAME(un), | |
794 | le32toh(msg->rm_len), | 794 | le32toh(msg->rm_len), | |
795 | sizeof(*msg)); | 795 | sizeof(*msg)); | |
796 | return; | 796 | return; | |
797 | } | 797 | } | |
798 | if (le32toh(msg->rm_len) > total_len) { | 798 | if (le32toh(msg->rm_len) > total_len) { | |
799 | printf("%s: urndis_decap invalid msg len %u > buffer " | 799 | printf("%s: urndis_decap invalid msg len %u > buffer " | |
800 | "total_len %u\n", | 800 | "total_len %u\n", | |
801 | DEVNAME(un), | 801 | DEVNAME(un), | |
802 | le32toh(msg->rm_len), | 802 | le32toh(msg->rm_len), | |
803 | total_len); | 803 | total_len); | |
804 | return; | 804 | return; | |
805 | } | 805 | } | |
806 | 806 | |||
807 | if (le32toh(msg->rm_dataoffset) + | 807 | if (le32toh(msg->rm_dataoffset) + | |
808 | le32toh(msg->rm_datalen) + RNDIS_HEADER_OFFSET | 808 | le32toh(msg->rm_datalen) + RNDIS_HEADER_OFFSET | |
809 | > le32toh(msg->rm_len)) { | 809 | > le32toh(msg->rm_len)) { | |
810 | printf("%s: urndis_decap invalid data " | 810 | printf("%s: urndis_decap invalid data " | |
811 | "len/offset/end_position(%u/%u/%u) -> " | 811 | "len/offset/end_position(%u/%u/%u) -> " | |
812 | "go out of receive buffer limit %u\n", | 812 | "go out of receive buffer limit %u\n", | |
813 | DEVNAME(un), | 813 | DEVNAME(un), | |
814 | le32toh(msg->rm_datalen), | 814 | le32toh(msg->rm_datalen), | |
815 | le32toh(msg->rm_dataoffset), | 815 | le32toh(msg->rm_dataoffset), | |
816 | le32toh(msg->rm_dataoffset) + | 816 | le32toh(msg->rm_dataoffset) + | |
817 | le32toh(msg->rm_datalen) + (uint32_t)RNDIS_HEADER_OFFSET, | 817 | le32toh(msg->rm_datalen) + (uint32_t)RNDIS_HEADER_OFFSET, | |
818 | le32toh(msg->rm_len)); | 818 | le32toh(msg->rm_len)); | |
819 | return; | 819 | return; | |
820 | } | 820 | } | |
821 | 821 | |||
822 | if (le32toh(msg->rm_datalen) < sizeof(struct ether_header)) { | 822 | if (le32toh(msg->rm_datalen) < sizeof(struct ether_header)) { | |
823 | if_statinc(ifp, if_ierrors); | 823 | if_statinc(ifp, if_ierrors); | |
824 | printf("%s: urndis_decap invalid ethernet size " | 824 | printf("%s: urndis_decap invalid ethernet size " | |
825 | "%d < %zu\n", | 825 | "%d < %zu\n", | |
826 | DEVNAME(un), | 826 | DEVNAME(un), | |
827 | le32toh(msg->rm_datalen), | 827 | le32toh(msg->rm_datalen), | |
828 | sizeof(struct ether_header)); | 828 | sizeof(struct ether_header)); | |
829 | return; | 829 | return; | |
830 | } | 830 | } | |
831 | 831 | |||
832 | usbnet_enqueue(un, | 832 | usbnet_enqueue(un, | |
833 | ((char*)&msg->rm_dataoffset + le32toh(msg->rm_dataoffset)), | 833 | ((char*)&msg->rm_dataoffset + le32toh(msg->rm_dataoffset)), | |
834 | le32toh(msg->rm_datalen), 0, 0, 0); | 834 | le32toh(msg->rm_datalen), 0, 0, 0); | |
835 | 835 | |||
836 | offset += le32toh(msg->rm_len); | 836 | offset += le32toh(msg->rm_len); | |
837 | total_len -= le32toh(msg->rm_len); | 837 | total_len -= le32toh(msg->rm_len); | |
838 | } | 838 | } | |
839 | } | 839 | } | |
840 | 840 | |||
841 | #if 0 | 841 | #if 0 | |
842 | static void | 842 | static void | |
843 | urndis_watchdog(struct ifnet *ifp) | 843 | urndis_watchdog(struct ifnet *ifp) | |
844 | { | 844 | { | |
845 | struct urndis_softc *sc = usbnet_softc(un); | 845 | struct urndis_softc *sc = usbnet_softc(un); | |
846 | 846 | |||
847 | if (un->un_dying) | 847 | if (un->un_dying) | |
848 | return; | 848 | return; | |
849 | 849 | |||
850 | if_statinc(ifp, if_oerrors); | 850 | if_statinc(ifp, if_oerrors); | |
851 | printf("%s: watchdog timeout\n", DEVNAME(un)); | 851 | printf("%s: watchdog timeout\n", DEVNAME(un)); | |
852 | 852 | |||
853 | urndis_ctrl_keepalive(un); | 853 | urndis_ctrl_keepalive(un); | |
854 | } | 854 | } | |
855 | #endif | 855 | #endif | |
856 | 856 | |||
857 | static int | 857 | static int | |
858 | urndis_init_un(struct ifnet *ifp, struct usbnet *un) | 858 | urndis_init_un(struct ifnet *ifp, struct usbnet *un) | |
859 | { | 859 | { | |
860 | int err; | 860 | int err; | |
861 | 861 | |||
862 | if (ifp->if_flags & IFF_RUNNING) | |||
863 | return 0; | |||
864 | ||||
865 | err = urndis_ctrl_init(un); | 862 | err = urndis_ctrl_init(un); | |
866 | if (err != RNDIS_STATUS_SUCCESS) | 863 | if (err != RNDIS_STATUS_SUCCESS) | |
867 | return EIO; | 864 | return EIO; | |
868 | 865 | |||
869 | return err; | 866 | return err; | |
870 | } | 867 | } | |
871 | 868 | |||
872 | static int | 869 | static int | |
873 | urndis_uno_init(struct ifnet *ifp) | 870 | urndis_uno_init(struct ifnet *ifp) | |
874 | { | 871 | { | |
875 | struct usbnet *un = ifp->if_softc; | 872 | struct usbnet *un = ifp->if_softc; | |
876 | int error; | 873 | int error; | |
877 | 874 | |||
878 | KASSERT(IFNET_LOCKED(ifp)); | 875 | KASSERT(IFNET_LOCKED(ifp)); | |
879 | 876 | |||
880 | error = urndis_init_un(ifp, un); | 877 | error = urndis_init_un(ifp, un); | |
881 | if (error) | 878 | if (error) | |
882 | return EIO; /* XXX */ | 879 | return EIO; /* XXX */ | |
883 | error = usbnet_init_rx_tx(un); | 880 | error = usbnet_init_rx_tx(un); | |
884 | usbnet_set_link(un, error == 0); | 881 | usbnet_set_link(un, error == 0); | |
885 | 882 | |||
886 | return error; | 883 | return error; | |
887 | } | 884 | } | |
888 | 885 | |||
889 | static int | 886 | static int | |
890 | urndis_match(device_t parent, cfdata_t match, void *aux) | 887 | urndis_match(device_t parent, cfdata_t match, void *aux) | |
891 | { | 888 | { | |
892 | struct usbif_attach_arg *uiaa = aux; | 889 | struct usbif_attach_arg *uiaa = aux; | |
893 | usb_interface_descriptor_t *id; | 890 | usb_interface_descriptor_t *id; | |
894 | 891 | |||
895 | if (!uiaa->uiaa_iface) | 892 | if (!uiaa->uiaa_iface) | |
896 | return UMATCH_NONE; | 893 | return UMATCH_NONE; | |
897 | 894 | |||
898 | id = usbd_get_interface_descriptor(uiaa->uiaa_iface); | 895 | id = usbd_get_interface_descriptor(uiaa->uiaa_iface); | |
899 | if (id == NULL) | 896 | if (id == NULL) | |
900 | return UMATCH_NONE; | 897 | return UMATCH_NONE; | |
901 | 898 | |||
902 | if (id->bInterfaceClass == UICLASS_WIRELESS && | 899 | if (id->bInterfaceClass == UICLASS_WIRELESS && | |
903 | id->bInterfaceSubClass == UISUBCLASS_RF && | 900 | id->bInterfaceSubClass == UISUBCLASS_RF && | |
904 | id->bInterfaceProtocol == UIPROTO_RNDIS) | 901 | id->bInterfaceProtocol == UIPROTO_RNDIS) | |
905 | return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; | 902 | return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; | |
906 | 903 | |||
907 | return usb_lookup(urndis_devs, uiaa->uiaa_vendor, uiaa->uiaa_product) != NULL ? | 904 | return usb_lookup(urndis_devs, uiaa->uiaa_vendor, uiaa->uiaa_product) != NULL ? | |
908 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 905 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
909 | } | 906 | } | |
910 | 907 | |||
911 | static void | 908 | static void | |
912 | urndis_attach(device_t parent, device_t self, void *aux) | 909 | urndis_attach(device_t parent, device_t self, void *aux) | |
913 | { | 910 | { | |
914 | struct urndis_softc *sc = device_private(self); | 911 | struct urndis_softc *sc = device_private(self); | |
915 | struct usbnet * const un = &sc->sc_un; | 912 | struct usbnet * const un = &sc->sc_un; | |
916 | struct usbif_attach_arg *uiaa = aux; | 913 | struct usbif_attach_arg *uiaa = aux; | |
917 | struct usbd_device *dev = uiaa->uiaa_device; | 914 | struct usbd_device *dev = uiaa->uiaa_device; | |
918 | usb_interface_descriptor_t *id; | 915 | usb_interface_descriptor_t *id; | |
919 | usb_endpoint_descriptor_t *ed; | 916 | usb_endpoint_descriptor_t *ed; | |
920 | usb_config_descriptor_t *cd; | 917 | usb_config_descriptor_t *cd; | |
921 | struct usbd_interface *iface_ctl; | 918 | struct usbd_interface *iface_ctl; | |
922 | const usb_cdc_union_descriptor_t *ud; | 919 | const usb_cdc_union_descriptor_t *ud; | |
923 | const usb_cdc_header_descriptor_t *desc; | 920 | const usb_cdc_header_descriptor_t *desc; | |
924 | usbd_desc_iter_t iter; | 921 | usbd_desc_iter_t iter; | |
925 | int if_ctl, if_data; | 922 | int if_ctl, if_data; | |
926 | int i, j, altcnt; | 923 | int i, j, altcnt; | |
927 | void *buf; | 924 | void *buf; | |
928 | size_t bufsz; | 925 | size_t bufsz; | |
929 | uint32_t filter; | 926 | uint32_t filter; | |
930 | char *devinfop; | 927 | char *devinfop; | |
931 | 928 | |||
932 | KASSERT((void *)sc == un); | 929 | KASSERT((void *)sc == un); | |
933 | 930 | |||
934 | aprint_naive("\n"); | 931 | aprint_naive("\n"); | |
935 | aprint_normal("\n"); | 932 | aprint_normal("\n"); | |
936 | devinfop = usbd_devinfo_alloc(dev, 0); | 933 | devinfop = usbd_devinfo_alloc(dev, 0); | |
937 | aprint_normal_dev(self, "%s\n", devinfop); | 934 | aprint_normal_dev(self, "%s\n", devinfop); | |
938 | usbd_devinfo_free(devinfop); | 935 | usbd_devinfo_free(devinfop); | |
939 | 936 | |||
940 | un->un_dev = self; | 937 | un->un_dev = self; | |
941 | un->un_udev = dev; | 938 | un->un_udev = dev; | |
942 | un->un_sc = sc; | 939 | un->un_sc = sc; | |
943 | un->un_ops = &urndis_ops; | 940 | un->un_ops = &urndis_ops; | |
944 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 941 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
945 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 942 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
946 | un->un_rx_list_cnt = RNDIS_RX_LIST_CNT; | 943 | un->un_rx_list_cnt = RNDIS_RX_LIST_CNT; | |
947 | un->un_tx_list_cnt = RNDIS_TX_LIST_CNT; | 944 | un->un_tx_list_cnt = RNDIS_TX_LIST_CNT; | |
948 | un->un_rx_bufsz = RNDIS_BUFSZ; | 945 | un->un_rx_bufsz = RNDIS_BUFSZ; | |
949 | un->un_tx_bufsz = RNDIS_BUFSZ; | 946 | un->un_tx_bufsz = RNDIS_BUFSZ; | |
950 | 947 | |||
951 | iface_ctl = uiaa->uiaa_iface; | 948 | iface_ctl = uiaa->uiaa_iface; | |
952 | un->un_iface = uiaa->uiaa_iface; | 949 | un->un_iface = uiaa->uiaa_iface; | |
953 | id = usbd_get_interface_descriptor(iface_ctl); | 950 | id = usbd_get_interface_descriptor(iface_ctl); | |
954 | if_ctl = id->bInterfaceNumber; | 951 | if_ctl = id->bInterfaceNumber; | |
955 | sc->sc_ifaceno_ctl = if_ctl; | 952 | sc->sc_ifaceno_ctl = if_ctl; | |
956 | if_data = -1; | 953 | if_data = -1; | |
957 | 954 | |||
958 | usb_desc_iter_init(un->un_udev, &iter); | 955 | usb_desc_iter_init(un->un_udev, &iter); | |
959 | while ((desc = (const void *)usb_desc_iter_next(&iter)) != NULL) { | 956 | while ((desc = (const void *)usb_desc_iter_next(&iter)) != NULL) { | |
960 | 957 | |||
961 | if (desc->bDescriptorType != UDESC_CS_INTERFACE) { | 958 | if (desc->bDescriptorType != UDESC_CS_INTERFACE) { | |
962 | continue; | 959 | continue; | |
963 | } | 960 | } | |
964 | switch (desc->bDescriptorSubtype) { | 961 | switch (desc->bDescriptorSubtype) { | |
965 | case UDESCSUB_CDC_UNION: | 962 | case UDESCSUB_CDC_UNION: | |
966 | /* XXX bail out when found first? */ | 963 | /* XXX bail out when found first? */ | |
967 | ud = (const usb_cdc_union_descriptor_t *)desc; | 964 | ud = (const usb_cdc_union_descriptor_t *)desc; | |
968 | if (if_data == -1) | 965 | if (if_data == -1) | |
969 | if_data = ud->bSlaveInterface[0]; | 966 | if_data = ud->bSlaveInterface[0]; | |
970 | break; | 967 | break; | |
971 | } | 968 | } | |
972 | } | 969 | } | |
973 | 970 | |||
974 | if (if_data == -1) { | 971 | if (if_data == -1) { | |
975 | DPRINTF(("urndis_attach: no union interface\n")); | 972 | DPRINTF(("urndis_attach: no union interface\n")); | |
976 | un->un_iface = iface_ctl; | 973 | un->un_iface = iface_ctl; | |
977 | } else { | 974 | } else { | |
978 | DPRINTF(("urndis_attach: union interface: ctl %u, data %u\n", | 975 | DPRINTF(("urndis_attach: union interface: ctl %u, data %u\n", | |
979 | if_ctl, if_data)); | 976 | if_ctl, if_data)); | |
980 | for (i = 0; i < uiaa->uiaa_nifaces; i++) { | 977 | for (i = 0; i < uiaa->uiaa_nifaces; i++) { | |
981 | if (uiaa->uiaa_ifaces[i] != NULL) { | 978 | if (uiaa->uiaa_ifaces[i] != NULL) { | |
982 | id = usbd_get_interface_descriptor( | 979 | id = usbd_get_interface_descriptor( | |
983 | uiaa->uiaa_ifaces[i]); | 980 | uiaa->uiaa_ifaces[i]); | |
984 | if (id != NULL && id->bInterfaceNumber == | 981 | if (id != NULL && id->bInterfaceNumber == | |
985 | if_data) { | 982 | if_data) { | |
986 | un->un_iface = uiaa->uiaa_ifaces[i]; | 983 | un->un_iface = uiaa->uiaa_ifaces[i]; | |
987 | uiaa->uiaa_ifaces[i] = NULL; | 984 | uiaa->uiaa_ifaces[i] = NULL; | |
988 | } | 985 | } | |
989 | } | 986 | } | |
990 | } | 987 | } | |
991 | } | 988 | } | |
992 | 989 | |||
993 | if (un->un_iface == NULL) { | 990 | if (un->un_iface == NULL) { | |
994 | aprint_error("%s: no data interface\n", DEVNAME(un)); | 991 | aprint_error("%s: no data interface\n", DEVNAME(un)); | |
995 | return; | 992 | return; | |
996 | } | 993 | } | |
997 | 994 | |||
998 | id = usbd_get_interface_descriptor(un->un_iface); | 995 | id = usbd_get_interface_descriptor(un->un_iface); | |
999 | cd = usbd_get_config_descriptor(un->un_udev); | 996 | cd = usbd_get_config_descriptor(un->un_udev); | |
1000 | altcnt = usbd_get_no_alts(cd, id->bInterfaceNumber); | 997 | altcnt = usbd_get_no_alts(cd, id->bInterfaceNumber); | |
1001 | 998 | |||
1002 | for (j = 0; j < altcnt; j++) { | 999 | for (j = 0; j < altcnt; j++) { | |
1003 | if (usbd_set_interface(un->un_iface, j)) { | 1000 | if (usbd_set_interface(un->un_iface, j)) { | |
1004 | aprint_error("%s: interface alternate setting %u " | 1001 | aprint_error("%s: interface alternate setting %u " | |
1005 | "failed\n", DEVNAME(un), j); | 1002 | "failed\n", DEVNAME(un), j); | |
1006 | return; | 1003 | return; | |
1007 | } | 1004 | } | |
1008 | /* Find endpoints. */ | 1005 | /* Find endpoints. */ | |
1009 | id = usbd_get_interface_descriptor(un->un_iface); | 1006 | id = usbd_get_interface_descriptor(un->un_iface); | |
1010 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = 0; | 1007 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = 0; | |
1011 | for (i = 0; i < id->bNumEndpoints; i++) { | 1008 | for (i = 0; i < id->bNumEndpoints; i++) { | |
1012 | ed = usbd_interface2endpoint_descriptor( | 1009 | ed = usbd_interface2endpoint_descriptor( | |
1013 | un->un_iface, i); | 1010 | un->un_iface, i); | |
1014 | if (!ed) { | 1011 | if (!ed) { | |
1015 | aprint_error("%s: no descriptor for bulk " | 1012 | aprint_error("%s: no descriptor for bulk " | |
1016 | "endpoint %u\n", DEVNAME(un), i); | 1013 | "endpoint %u\n", DEVNAME(un), i); | |
1017 | return; | 1014 | return; | |
1018 | } | 1015 | } | |
1019 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 1016 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
1020 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 1017 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
1021 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 1018 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
1022 | } | 1019 | } | |
1023 | else if ( | 1020 | else if ( | |
1024 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 1021 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
1025 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 1022 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
1026 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 1023 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
1027 | } | 1024 | } | |
1028 | } | 1025 | } | |
1029 | 1026 | |||
1030 | if (un->un_ed[USBNET_ENDPT_RX] != 0 && un->un_ed[USBNET_ENDPT_TX] != 0) { | 1027 | if (un->un_ed[USBNET_ENDPT_RX] != 0 && un->un_ed[USBNET_ENDPT_TX] != 0) { | |
1031 | DPRINTF(("%s: in=%#x, out=%#x\n", | 1028 | DPRINTF(("%s: in=%#x, out=%#x\n", | |
1032 | DEVNAME(un), | 1029 | DEVNAME(un), | |
1033 | un->un_ed[USBNET_ENDPT_RX], | 1030 | un->un_ed[USBNET_ENDPT_RX], | |
1034 | un->un_ed[USBNET_ENDPT_TX])); | 1031 | un->un_ed[USBNET_ENDPT_TX])); | |
1035 | break; | 1032 | break; | |
1036 | } | 1033 | } | |
1037 | } | 1034 | } | |
1038 | 1035 | |||
1039 | if (un->un_ed[USBNET_ENDPT_RX] == 0) | 1036 | if (un->un_ed[USBNET_ENDPT_RX] == 0) | |
1040 | aprint_error("%s: could not find data bulk in\n", DEVNAME(un)); | 1037 | aprint_error("%s: could not find data bulk in\n", DEVNAME(un)); | |
1041 | if (un->un_ed[USBNET_ENDPT_TX] == 0) | 1038 | if (un->un_ed[USBNET_ENDPT_TX] == 0) | |
1042 | aprint_error("%s: could not find data bulk out\n",DEVNAME(un)); | 1039 | aprint_error("%s: could not find data bulk out\n",DEVNAME(un)); | |
1043 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || un->un_ed[USBNET_ENDPT_TX] == 0) | 1040 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || un->un_ed[USBNET_ENDPT_TX] == 0) | |
1044 | return; | 1041 | return; | |
1045 | 1042 | |||
1046 | #if 0 | 1043 | #if 0 | |
1047 | ifp->if_watchdog = urndis_watchdog; | 1044 | ifp->if_watchdog = urndis_watchdog; | |
1048 | #endif | 1045 | #endif | |
1049 | 1046 | |||
1050 | usbnet_attach(un, "urndisdet"); | 1047 | usbnet_attach(un, "urndisdet"); | |
1051 | 1048 | |||
1052 | struct ifnet *ifp = usbnet_ifp(un); | 1049 | struct ifnet *ifp = usbnet_ifp(un); | |
1053 | urndis_init_un(ifp, un); | 1050 | urndis_init_un(ifp, un); | |
1054 | 1051 | |||
1055 | if (urndis_ctrl_query(un, OID_802_3_PERMANENT_ADDRESS, NULL, 0, | 1052 | if (urndis_ctrl_query(un, OID_802_3_PERMANENT_ADDRESS, NULL, 0, | |
1056 | &buf, &bufsz) != RNDIS_STATUS_SUCCESS) { | 1053 | &buf, &bufsz) != RNDIS_STATUS_SUCCESS) { | |
1057 | aprint_error("%s: unable to get hardware address\n", | 1054 | aprint_error("%s: unable to get hardware address\n", | |
1058 | DEVNAME(un)); | 1055 | DEVNAME(un)); | |
1059 | return; | 1056 | return; | |
1060 | } | 1057 | } | |
1061 | 1058 | |||
1062 | if (bufsz == ETHER_ADDR_LEN) { | 1059 | if (bufsz == ETHER_ADDR_LEN) { | |
1063 | memcpy(un->un_eaddr, buf, ETHER_ADDR_LEN); | 1060 | memcpy(un->un_eaddr, buf, ETHER_ADDR_LEN); | |
1064 | kmem_free(buf, bufsz); | 1061 | kmem_free(buf, bufsz); | |
1065 | } else { | 1062 | } else { | |
1066 | aprint_error("%s: invalid address\n", DEVNAME(un)); | 1063 | aprint_error("%s: invalid address\n", DEVNAME(un)); | |
1067 | if (buf && bufsz) | 1064 | if (buf && bufsz) | |
1068 | kmem_free(buf, bufsz); | 1065 | kmem_free(buf, bufsz); | |
1069 | return; | 1066 | return; | |
1070 | } | 1067 | } | |
1071 | 1068 | |||
1072 | /* Initialize packet filter */ | 1069 | /* Initialize packet filter */ | |
1073 | sc->sc_filter = RNDIS_PACKET_TYPE_BROADCAST; | 1070 | sc->sc_filter = RNDIS_PACKET_TYPE_BROADCAST; | |
1074 | sc->sc_filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; | 1071 | sc->sc_filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; | |
1075 | filter = htole32(sc->sc_filter); | 1072 | filter = htole32(sc->sc_filter); | |
1076 | if (urndis_ctrl_set(un, OID_GEN_CURRENT_PACKET_FILTER, &filter, | 1073 | if (urndis_ctrl_set(un, OID_GEN_CURRENT_PACKET_FILTER, &filter, | |
1077 | sizeof(filter)) != RNDIS_STATUS_SUCCESS) { | 1074 | sizeof(filter)) != RNDIS_STATUS_SUCCESS) { | |
1078 | aprint_error("%s: unable to set data filters\n", DEVNAME(un)); | 1075 | aprint_error("%s: unable to set data filters\n", DEVNAME(un)); | |
1079 | return; | 1076 | return; | |
1080 | } | 1077 | } | |
1081 | 1078 | |||
1082 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 1079 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
1083 | 0, NULL); | 1080 | 0, NULL); | |
1084 | } | 1081 | } | |
1085 | 1082 | |||
1086 | #ifdef _MODULE | 1083 | #ifdef _MODULE | |
1087 | #include "ioconf.c" | 1084 | #include "ioconf.c" | |
1088 | #endif | 1085 | #endif | |
1089 | 1086 | |||
1090 | USBNET_MODULE(urndis) | 1087 | USBNET_MODULE(urndis) |