usb: usbd_abort_pipe never fails. Make it return void. Prune dead branches as a result of this change.diff -r1.73 -r1.74 src/sys/dev/usb/if_atu.c
(riastradh)
--- src/sys/dev/usb/if_atu.c 2020/08/28 19:02:19 1.73
+++ src/sys/dev/usb/if_atu.c 2022/03/03 06:05:38 1.74
@@ -1,1050 +1,1050 @@ | @@ -1,1050 +1,1050 @@ | |||
1 | /* $NetBSD: if_atu.c,v 1.73 2020/08/28 19:02:19 riastradh Exp $ */ | 1 | /* $NetBSD: if_atu.c,v 1.74 2022/03/03 06:05:38 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_atu.c,v 1.48 2004/12/30 01:53:21 dlg Exp $ */ | 2 | /* $OpenBSD: if_atu.c,v 1.48 2004/12/30 01:53:21 dlg Exp $ */ | |
3 | /* | 3 | /* | |
4 | * Copyright (c) 2003, 2004 | 4 | * Copyright (c) 2003, 2004 | |
5 | * Daan Vreeken <Danovitsch@Vitsch.net>. All rights reserved. | 5 | * Daan Vreeken <Danovitsch@Vitsch.net>. 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 Daan Vreeken. | 17 | * This product includes software developed by Daan Vreeken. | |
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 Daan Vreeken AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY Daan Vreeken 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 Daan Vreeken OR THE VOICES IN HIS HEAD | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL Daan Vreeken 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 | 34 | |||
35 | /* | 35 | /* | |
36 | * Atmel AT76c503 / AT76c503a / AT76c505 / AT76c505a USB WLAN driver | 36 | * Atmel AT76c503 / AT76c503a / AT76c505 / AT76c505a USB WLAN driver | |
37 | * version 0.5 - 2004-08-03 | 37 | * version 0.5 - 2004-08-03 | |
38 | * | 38 | * | |
39 | * Originally written by Daan Vreeken <Danovitsch @ Vitsch . net> | 39 | * Originally written by Daan Vreeken <Danovitsch @ Vitsch . net> | |
40 | * http://vitsch.net/bsd/atuwi | 40 | * http://vitsch.net/bsd/atuwi | |
41 | * | 41 | * | |
42 | * Contributed to by : | 42 | * Contributed to by : | |
43 | * Chris Whitehouse, Alistair Phillips, Peter Pilka, Martijn van Buul, | 43 | * Chris Whitehouse, Alistair Phillips, Peter Pilka, Martijn van Buul, | |
44 | * Suihong Liang, Arjan van Leeuwen, Stuart Walsh | 44 | * Suihong Liang, Arjan van Leeuwen, Stuart Walsh | |
45 | * | 45 | * | |
46 | * Ported to OpenBSD by Theo de Raadt and David Gwynne. | 46 | * Ported to OpenBSD by Theo de Raadt and David Gwynne. | |
47 | * Ported to NetBSD by Jesse Off | 47 | * Ported to NetBSD by Jesse Off | |
48 | */ | 48 | */ | |
49 | 49 | |||
50 | #include <sys/cdefs.h> | 50 | #include <sys/cdefs.h> | |
51 | __KERNEL_RCSID(0, "$NetBSD: if_atu.c,v 1.73 2020/08/28 19:02:19 riastradh Exp $"); | 51 | __KERNEL_RCSID(0, "$NetBSD: if_atu.c,v 1.74 2022/03/03 06:05:38 riastradh Exp $"); | |
52 | 52 | |||
53 | #ifdef _KERNEL_OPT | 53 | #ifdef _KERNEL_OPT | |
54 | #include "opt_usb.h" | 54 | #include "opt_usb.h" | |
55 | #endif | 55 | #endif | |
56 | 56 | |||
57 | #include <sys/param.h> | 57 | #include <sys/param.h> | |
58 | #include <sys/sockio.h> | 58 | #include <sys/sockio.h> | |
59 | #include <sys/mbuf.h> | 59 | #include <sys/mbuf.h> | |
60 | #include <sys/kernel.h> | 60 | #include <sys/kernel.h> | |
61 | #include <sys/socket.h> | 61 | #include <sys/socket.h> | |
62 | #include <sys/systm.h> | 62 | #include <sys/systm.h> | |
63 | #include <sys/kthread.h> | 63 | #include <sys/kthread.h> | |
64 | #include <sys/queue.h> | 64 | #include <sys/queue.h> | |
65 | #include <sys/device.h> | 65 | #include <sys/device.h> | |
66 | #include <sys/bus.h> | 66 | #include <sys/bus.h> | |
67 | 67 | |||
68 | #include <dev/usb/usb.h> | 68 | #include <dev/usb/usb.h> | |
69 | #include <dev/usb/usbdi.h> | 69 | #include <dev/usb/usbdi.h> | |
70 | #include <dev/usb/usbdi_util.h> | 70 | #include <dev/usb/usbdi_util.h> | |
71 | #include <dev/usb/usbdivar.h> | 71 | #include <dev/usb/usbdivar.h> | |
72 | #include <dev/usb/usbdevs.h> | 72 | #include <dev/usb/usbdevs.h> | |
73 | 73 | |||
74 | #include <dev/microcode/atmel/atmel_intersil_fw.h> | 74 | #include <dev/microcode/atmel/atmel_intersil_fw.h> | |
75 | #include <dev/microcode/atmel/atmel_rfmd2958-smc_fw.h> | 75 | #include <dev/microcode/atmel/atmel_rfmd2958-smc_fw.h> | |
76 | #include <dev/microcode/atmel/atmel_rfmd2958_fw.h> | 76 | #include <dev/microcode/atmel/atmel_rfmd2958_fw.h> | |
77 | #include <dev/microcode/atmel/atmel_rfmd_fw.h> | 77 | #include <dev/microcode/atmel/atmel_rfmd_fw.h> | |
78 | 78 | |||
79 | #include <net/bpf.h> | 79 | #include <net/bpf.h> | |
80 | #include <net/if.h> | 80 | #include <net/if.h> | |
81 | #include <net/if_dl.h> | 81 | #include <net/if_dl.h> | |
82 | #include <net/if_media.h> | 82 | #include <net/if_media.h> | |
83 | #include <net/if_ether.h> | 83 | #include <net/if_ether.h> | |
84 | 84 | |||
85 | #ifdef INET | 85 | #ifdef INET | |
86 | #include <netinet/in.h> | 86 | #include <netinet/in.h> | |
87 | #include <netinet/if_ether.h> | 87 | #include <netinet/if_ether.h> | |
88 | #endif | 88 | #endif | |
89 | 89 | |||
90 | #include <net80211/ieee80211_var.h> | 90 | #include <net80211/ieee80211_var.h> | |
91 | #include <net80211/ieee80211_radiotap.h> | 91 | #include <net80211/ieee80211_radiotap.h> | |
92 | 92 | |||
93 | #include <dev/usb/if_atureg.h> | 93 | #include <dev/usb/if_atureg.h> | |
94 | 94 | |||
95 | #ifdef ATU_DEBUG | 95 | #ifdef ATU_DEBUG | |
96 | #define DPRINTF(x) do { if (atudebug) printf x; } while (0) | 96 | #define DPRINTF(x) do { if (atudebug) printf x; } while (0) | |
97 | #define DPRINTFN(n,x) do { if (atudebug>(n)) printf x; } while (0) | 97 | #define DPRINTFN(n,x) do { if (atudebug>(n)) printf x; } while (0) | |
98 | int atudebug = 1; | 98 | int atudebug = 1; | |
99 | #else | 99 | #else | |
100 | #define DPRINTF(x) | 100 | #define DPRINTF(x) | |
101 | #define DPRINTFN(n,x) | 101 | #define DPRINTFN(n,x) | |
102 | #endif | 102 | #endif | |
103 | 103 | |||
104 | /* | 104 | /* | |
105 | * Various supported device vendors/products/radio type. | 105 | * Various supported device vendors/products/radio type. | |
106 | */ | 106 | */ | |
107 | static const struct atu_type atu_devs[] = { | 107 | static const struct atu_type atu_devs[] = { | |
108 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3CRSHEW696, | 108 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3CRSHEW696, | |
109 | RadioRFMD, ATU_NO_QUIRK }, | 109 | RadioRFMD, ATU_NO_QUIRK }, | |
110 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_BWU613, | 110 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_BWU613, | |
111 | RadioRFMD, ATU_NO_QUIRK }, | 111 | RadioRFMD, ATU_NO_QUIRK }, | |
112 | { USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_2664W, | 112 | { USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_2664W, | |
113 | AT76C503_rfmd_acc, ATU_NO_QUIRK }, | 113 | AT76C503_rfmd_acc, ATU_NO_QUIRK }, | |
114 | { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL300, | 114 | { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL300, | |
115 | RadioIntersil, ATU_NO_QUIRK }, | 115 | RadioIntersil, ATU_NO_QUIRK }, | |
116 | { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL400, | 116 | { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL400, | |
117 | RadioRFMD, ATU_NO_QUIRK }, | 117 | RadioRFMD, ATU_NO_QUIRK }, | |
118 | { USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_UAT1, | 118 | { USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_UAT1, | |
119 | RadioRFMD, ATU_NO_QUIRK }, | 119 | RadioRFMD, ATU_NO_QUIRK }, | |
120 | { USB_VENDOR_ADDTRON, USB_PRODUCT_ADDTRON_AWU120, | 120 | { USB_VENDOR_ADDTRON, USB_PRODUCT_ADDTRON_AWU120, | |
121 | RadioIntersil, ATU_NO_QUIRK }, | 121 | RadioIntersil, ATU_NO_QUIRK }, | |
122 | { USB_VENDOR_AINCOMM, USB_PRODUCT_AINCOMM_AWU2000B, | 122 | { USB_VENDOR_AINCOMM, USB_PRODUCT_AINCOMM_AWU2000B, | |
123 | RadioRFMD2958, ATU_NO_QUIRK }, | 123 | RadioRFMD2958, ATU_NO_QUIRK }, | |
124 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_VOYAGER1010, | 124 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_VOYAGER1010, | |
125 | RadioIntersil, ATU_NO_QUIRK }, | 125 | RadioIntersil, ATU_NO_QUIRK }, | |
126 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013I, | 126 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013I, | |
127 | RadioIntersil, ATU_NO_QUIRK }, | 127 | RadioIntersil, ATU_NO_QUIRK }, | |
128 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013, | 128 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013, | |
129 | RadioRFMD, ATU_NO_QUIRK }, | 129 | RadioRFMD, ATU_NO_QUIRK }, | |
130 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I1, | 130 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I1, | |
131 | RadioIntersil, ATU_NO_QUIRK }, | 131 | RadioIntersil, ATU_NO_QUIRK }, | |
132 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I2, | 132 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I2, | |
133 | AT76C503_i3863, ATU_NO_QUIRK }, | 133 | AT76C503_i3863, ATU_NO_QUIRK }, | |
134 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503RFMD, | 134 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503RFMD, | |
135 | RadioRFMD, ATU_NO_QUIRK }, | 135 | RadioRFMD, ATU_NO_QUIRK }, | |
136 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD, | 136 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD, | |
137 | AT76C505_rfmd, ATU_NO_QUIRK }, | 137 | AT76C505_rfmd, ATU_NO_QUIRK }, | |
138 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD2958, | 138 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD2958, | |
139 | RadioRFMD2958, ATU_NO_QUIRK }, | 139 | RadioRFMD2958, ATU_NO_QUIRK }, | |
140 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505A, /* SMC2662 V.4 */ | 140 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505A, /* SMC2662 V.4 */ | |
141 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | 141 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | |
142 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505AS, /* quirk? */ | 142 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505AS, /* quirk? */ | |
143 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | 143 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | |
144 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_WN210, | 144 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_WN210, | |
145 | RadioRFMD, ATU_NO_QUIRK }, | 145 | RadioRFMD, ATU_NO_QUIRK }, | |
146 | { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D6050, | 146 | { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D6050, | |
147 | RadioRFMD, ATU_NO_QUIRK }, | 147 | RadioRFMD, ATU_NO_QUIRK }, | |
148 | { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_C11U, | 148 | { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_C11U, | |
149 | RadioIntersil, ATU_NO_QUIRK }, | 149 | RadioIntersil, ATU_NO_QUIRK }, | |
150 | { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_WL210, | 150 | { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_WL210, | |
151 | RadioIntersil, ATU_NO_QUIRK }, | 151 | RadioIntersil, ATU_NO_QUIRK }, | |
152 | { USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQWLAN, | 152 | { USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQWLAN, | |
153 | RadioRFMD, ATU_NO_QUIRK }, | 153 | RadioRFMD, ATU_NO_QUIRK }, | |
154 | { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLUSB_11_STICK, | 154 | { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLUSB_11_STICK, | |
155 | RadioRFMD2958, ATU_NO_QUIRK }, | 155 | RadioRFMD2958, ATU_NO_QUIRK }, | |
156 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_CHUSB611G, | 156 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_CHUSB611G, | |
157 | RadioRFMD2958, ATU_NO_QUIRK }, | 157 | RadioRFMD2958, ATU_NO_QUIRK }, | |
158 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL200U, | 158 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL200U, | |
159 | RadioRFMD, ATU_NO_QUIRK }, | 159 | RadioRFMD, ATU_NO_QUIRK }, | |
160 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL240U, | 160 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL240U, | |
161 | RadioRFMD2958, ATU_NO_QUIRK }, | 161 | RadioRFMD2958, ATU_NO_QUIRK }, | |
162 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_XH1153, | 162 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_XH1153, | |
163 | RadioRFMD, ATU_NO_QUIRK }, | 163 | RadioRFMD, ATU_NO_QUIRK }, | |
164 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL120E, | 164 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL120E, | |
165 | RadioRFMD, ATU_NO_QUIRK }, | 165 | RadioRFMD, ATU_NO_QUIRK }, | |
166 | { USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWLBM101, | 166 | { USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWLBM101, | |
167 | RadioRFMD, ATU_NO_QUIRK }, | 167 | RadioRFMD, ATU_NO_QUIRK }, | |
168 | { USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_WLAN, /* quirk? */ | 168 | { USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_WLAN, /* quirk? */ | |
169 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | 169 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | |
170 | { USB_VENDOR_HP, USB_PRODUCT_HP_HN210W, | 170 | { USB_VENDOR_HP, USB_PRODUCT_HP_HN210W, | |
171 | RadioIntersil, ATU_NO_QUIRK }, | 171 | RadioIntersil, ATU_NO_QUIRK }, | |
172 | { USB_VENDOR_INTEL, USB_PRODUCT_INTEL_AP310, | 172 | { USB_VENDOR_INTEL, USB_PRODUCT_INTEL_AP310, | |
173 | RadioIntersil, ATU_NO_QUIRK }, | 173 | RadioIntersil, ATU_NO_QUIRK }, | |
174 | { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBWNB11A, | 174 | { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBWNB11A, | |
175 | RadioIntersil, ATU_NO_QUIRK }, | 175 | RadioIntersil, ATU_NO_QUIRK }, | |
176 | { USB_VENDOR_LEXAR, USB_PRODUCT_LEXAR_2662WAR, | 176 | { USB_VENDOR_LEXAR, USB_PRODUCT_LEXAR_2662WAR, | |
177 | RadioRFMD, ATU_NO_QUIRK }, | 177 | RadioRFMD, ATU_NO_QUIRK }, | |
178 | { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB11, | 178 | { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB11, | |
179 | RadioIntersil, ATU_NO_QUIRK }, | 179 | RadioIntersil, ATU_NO_QUIRK }, | |
180 | { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_WUSB11, | 180 | { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_WUSB11, | |
181 | RadioRFMD, ATU_NO_QUIRK }, | 181 | RadioRFMD, ATU_NO_QUIRK }, | |
182 | { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_NWU11B, | 182 | { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_NWU11B, | |
183 | RadioRFMD, ATU_NO_QUIRK }, | 183 | RadioRFMD, ATU_NO_QUIRK }, | |
184 | { USB_VENDOR_LINKSYS3, USB_PRODUCT_LINKSYS3_WUSB11V28, | 184 | { USB_VENDOR_LINKSYS3, USB_PRODUCT_LINKSYS3_WUSB11V28, | |
185 | RadioRFMD2958, ATU_NO_QUIRK }, | 185 | RadioRFMD2958, ATU_NO_QUIRK }, | |
186 | { USB_VENDOR_MSI, USB_PRODUCT_MSI_WLAN, | 186 | { USB_VENDOR_MSI, USB_PRODUCT_MSI_WLAN, | |
187 | RadioRFMD2958, ATU_NO_QUIRK }, | 187 | RadioRFMD2958, ATU_NO_QUIRK }, | |
188 | { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101, | 188 | { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101, | |
189 | RadioIntersil, ATU_NO_QUIRK }, | 189 | RadioIntersil, ATU_NO_QUIRK }, | |
190 | { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101B, | 190 | { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101B, | |
191 | RadioRFMD, ATU_NO_QUIRK }, | 191 | RadioRFMD, ATU_NO_QUIRK }, | |
192 | { USB_VENDOR_OQO, USB_PRODUCT_OQO_WIFI01, | 192 | { USB_VENDOR_OQO, USB_PRODUCT_OQO_WIFI01, | |
193 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | 193 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | |
194 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GW_US11S, | 194 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GW_US11S, | |
195 | RadioRFMD, ATU_NO_QUIRK }, | 195 | RadioRFMD, ATU_NO_QUIRK }, | |
196 | { USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_SWL2100W, | 196 | { USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_SWL2100W, | |
197 | AT76C503_i3863, ATU_NO_QUIRK }, | 197 | AT76C503_i3863, ATU_NO_QUIRK }, | |
198 | { USB_VENDOR_SIEMENS2, USB_PRODUCT_SIEMENS2_WLL013, | 198 | { USB_VENDOR_SIEMENS2, USB_PRODUCT_SIEMENS2_WLL013, | |
199 | RadioRFMD, ATU_NO_QUIRK }, | 199 | RadioRFMD, ATU_NO_QUIRK }, | |
200 | { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV1, | 200 | { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV1, | |
201 | RadioIntersil, ATU_NO_QUIRK }, | 201 | RadioIntersil, ATU_NO_QUIRK }, | |
202 | { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV2, | 202 | { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV2, | |
203 | AT76C503_rfmd_acc, ATU_NO_QUIRK }, | 203 | AT76C503_rfmd_acc, ATU_NO_QUIRK }, | |
204 | { USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_U300C, | 204 | { USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_U300C, | |
205 | RadioIntersil, ATU_NO_QUIRK }, | 205 | RadioIntersil, ATU_NO_QUIRK }, | |
206 | { USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_M4Y750, | 206 | { USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_M4Y750, | |
207 | RadioIntersil, ATU_NO_QUIRK }, | 207 | RadioIntersil, ATU_NO_QUIRK }, | |
208 | }; | 208 | }; | |
209 | 209 | |||
210 | static const struct atu_radfirm { | 210 | static const struct atu_radfirm { | |
211 | enum atu_radio_type atur_type; | 211 | enum atu_radio_type atur_type; | |
212 | unsigned char *atur_internal; | 212 | unsigned char *atur_internal; | |
213 | size_t atur_internal_sz; | 213 | size_t atur_internal_sz; | |
214 | unsigned char *atur_external; | 214 | unsigned char *atur_external; | |
215 | size_t atur_external_sz; | 215 | size_t atur_external_sz; | |
216 | } atu_radfirm[] = { | 216 | } atu_radfirm[] = { | |
217 | { RadioRFMD, | 217 | { RadioRFMD, | |
218 | atmel_fw_rfmd_int, sizeof(atmel_fw_rfmd_int), | 218 | atmel_fw_rfmd_int, sizeof(atmel_fw_rfmd_int), | |
219 | atmel_fw_rfmd_ext, sizeof(atmel_fw_rfmd_ext) }, | 219 | atmel_fw_rfmd_ext, sizeof(atmel_fw_rfmd_ext) }, | |
220 | { RadioRFMD2958, | 220 | { RadioRFMD2958, | |
221 | atmel_fw_rfmd2958_int, sizeof(atmel_fw_rfmd2958_int), | 221 | atmel_fw_rfmd2958_int, sizeof(atmel_fw_rfmd2958_int), | |
222 | atmel_fw_rfmd2958_ext, sizeof(atmel_fw_rfmd2958_ext) }, | 222 | atmel_fw_rfmd2958_ext, sizeof(atmel_fw_rfmd2958_ext) }, | |
223 | { RadioRFMD2958_SMC, | 223 | { RadioRFMD2958_SMC, | |
224 | atmel_fw_rfmd2958_smc_int, sizeof(atmel_fw_rfmd2958_smc_int), | 224 | atmel_fw_rfmd2958_smc_int, sizeof(atmel_fw_rfmd2958_smc_int), | |
225 | atmel_fw_rfmd2958_smc_ext, sizeof(atmel_fw_rfmd2958_smc_ext) }, | 225 | atmel_fw_rfmd2958_smc_ext, sizeof(atmel_fw_rfmd2958_smc_ext) }, | |
226 | { RadioIntersil, | 226 | { RadioIntersil, | |
227 | atmel_fw_intersil_int, sizeof(atmel_fw_intersil_int), | 227 | atmel_fw_intersil_int, sizeof(atmel_fw_intersil_int), | |
228 | atmel_fw_intersil_ext, sizeof(atmel_fw_intersil_ext) } | 228 | atmel_fw_intersil_ext, sizeof(atmel_fw_intersil_ext) } | |
229 | }; | 229 | }; | |
230 | 230 | |||
231 | static int atu_newbuf(struct atu_softc *, struct atu_chain *, struct mbuf *); | 231 | static int atu_newbuf(struct atu_softc *, struct atu_chain *, struct mbuf *); | |
232 | static void atu_rxeof(struct usbd_xfer *, void *, usbd_status); | 232 | static void atu_rxeof(struct usbd_xfer *, void *, usbd_status); | |
233 | static void atu_txeof(struct usbd_xfer *, void *, usbd_status); | 233 | static void atu_txeof(struct usbd_xfer *, void *, usbd_status); | |
234 | static void atu_start(struct ifnet *); | 234 | static void atu_start(struct ifnet *); | |
235 | static int atu_ioctl(struct ifnet *, u_long, void *); | 235 | static int atu_ioctl(struct ifnet *, u_long, void *); | |
236 | static int atu_init(struct ifnet *); | 236 | static int atu_init(struct ifnet *); | |
237 | static void atu_stop(struct ifnet *, int); | 237 | static void atu_stop(struct ifnet *, int); | |
238 | static void atu_watchdog(struct ifnet *); | 238 | static void atu_watchdog(struct ifnet *); | |
239 | static usbd_status atu_usb_request(struct atu_softc *, uint8_t, | 239 | static usbd_status atu_usb_request(struct atu_softc *, uint8_t, | |
240 | uint8_t, uint16_t, uint16_t, | 240 | uint8_t, uint16_t, uint16_t, | |
241 | uint16_t, uint8_t *); | 241 | uint16_t, uint8_t *); | |
242 | static int atu_send_command(struct atu_softc *, uint8_t *, int); | 242 | static int atu_send_command(struct atu_softc *, uint8_t *, int); | |
243 | static int atu_get_cmd_status(struct atu_softc *, uint8_t, | 243 | static int atu_get_cmd_status(struct atu_softc *, uint8_t, | |
244 | uint8_t *); | 244 | uint8_t *); | |
245 | static int atu_wait_completion(struct atu_softc *, uint8_t, | 245 | static int atu_wait_completion(struct atu_softc *, uint8_t, | |
246 | uint8_t *); | 246 | uint8_t *); | |
247 | static int atu_send_mib(struct atu_softc *, uint8_t, | 247 | static int atu_send_mib(struct atu_softc *, uint8_t, | |
248 | uint8_t, uint8_t, void *); | 248 | uint8_t, uint8_t, void *); | |
249 | static int atu_get_mib(struct atu_softc *, uint8_t, | 249 | static int atu_get_mib(struct atu_softc *, uint8_t, | |
250 | uint8_t, uint8_t, uint8_t *); | 250 | uint8_t, uint8_t, uint8_t *); | |
251 | #if 0 | 251 | #if 0 | |
252 | int atu_start_ibss(struct atu_softc *); | 252 | int atu_start_ibss(struct atu_softc *); | |
253 | #endif | 253 | #endif | |
254 | static int atu_start_scan(struct atu_softc *); | 254 | static int atu_start_scan(struct atu_softc *); | |
255 | static int atu_switch_radio(struct atu_softc *, int); | 255 | static int atu_switch_radio(struct atu_softc *, int); | |
256 | static int atu_initial_config(struct atu_softc *); | 256 | static int atu_initial_config(struct atu_softc *); | |
257 | static int atu_join(struct atu_softc *, struct ieee80211_node *); | 257 | static int atu_join(struct atu_softc *, struct ieee80211_node *); | |
258 | static int8_t atu_get_dfu_state(struct atu_softc *); | 258 | static int8_t atu_get_dfu_state(struct atu_softc *); | |
259 | static uint8_t atu_get_opmode(struct atu_softc *, uint8_t *); | 259 | static uint8_t atu_get_opmode(struct atu_softc *, uint8_t *); | |
260 | static void atu_internal_firmware(device_t); | 260 | static void atu_internal_firmware(device_t); | |
261 | static void atu_external_firmware(device_t); | 261 | static void atu_external_firmware(device_t); | |
262 | static int atu_get_card_config(struct atu_softc *); | 262 | static int atu_get_card_config(struct atu_softc *); | |
263 | static int atu_media_change(struct ifnet *); | 263 | static int atu_media_change(struct ifnet *); | |
264 | static void atu_media_status(struct ifnet *, struct ifmediareq *); | 264 | static void atu_media_status(struct ifnet *, struct ifmediareq *); | |
265 | static int atu_tx_list_init(struct atu_softc *); | 265 | static int atu_tx_list_init(struct atu_softc *); | |
266 | static int atu_rx_list_init(struct atu_softc *); | 266 | static int atu_rx_list_init(struct atu_softc *); | |
267 | static void atu_xfer_list_free(struct atu_softc *, struct atu_chain *, | 267 | static void atu_xfer_list_free(struct atu_softc *, struct atu_chain *, | |
268 | int); | 268 | int); | |
269 | 269 | |||
270 | static void atu_task(void *); | 270 | static void atu_task(void *); | |
271 | static int atu_newstate(struct ieee80211com *, enum ieee80211_state, int); | 271 | static int atu_newstate(struct ieee80211com *, enum ieee80211_state, int); | |
272 | static int atu_tx_start(struct atu_softc *, struct ieee80211_node *, | 272 | static int atu_tx_start(struct atu_softc *, struct ieee80211_node *, | |
273 | struct atu_chain *, struct mbuf *); | 273 | struct atu_chain *, struct mbuf *); | |
274 | static void atu_complete_attach(struct atu_softc *); | 274 | static void atu_complete_attach(struct atu_softc *); | |
275 | static uint8_t atu_calculate_padding(int); | 275 | static uint8_t atu_calculate_padding(int); | |
276 | 276 | |||
277 | static int atu_match(device_t, cfdata_t, void *); | 277 | static int atu_match(device_t, cfdata_t, void *); | |
278 | static void atu_attach(device_t, device_t, void *); | 278 | static void atu_attach(device_t, device_t, void *); | |
279 | static int atu_detach(device_t, int); | 279 | static int atu_detach(device_t, int); | |
280 | static int atu_activate(device_t, enum devact); | 280 | static int atu_activate(device_t, enum devact); | |
281 | 281 | |||
282 | CFATTACH_DECL_NEW(atu, sizeof(struct atu_softc), atu_match, atu_attach, | 282 | CFATTACH_DECL_NEW(atu, sizeof(struct atu_softc), atu_match, atu_attach, | |
283 | atu_detach, atu_activate); | 283 | atu_detach, atu_activate); | |
284 | 284 | |||
285 | static usbd_status | 285 | static usbd_status | |
286 | atu_usb_request(struct atu_softc *sc, uint8_t type, | 286 | atu_usb_request(struct atu_softc *sc, uint8_t type, | |
287 | uint8_t request, uint16_t value, uint16_t index, uint16_t length, | 287 | uint8_t request, uint16_t value, uint16_t index, uint16_t length, | |
288 | uint8_t *data) | 288 | uint8_t *data) | |
289 | { | 289 | { | |
290 | usb_device_request_t req; | 290 | usb_device_request_t req; | |
291 | struct usbd_xfer *xfer; | 291 | struct usbd_xfer *xfer; | |
292 | usbd_status err; | 292 | usbd_status err; | |
293 | int total_len = 0, s; | 293 | int total_len = 0, s; | |
294 | 294 | |||
295 | req.bmRequestType = type; | 295 | req.bmRequestType = type; | |
296 | req.bRequest = request; | 296 | req.bRequest = request; | |
297 | USETW(req.wValue, value); | 297 | USETW(req.wValue, value); | |
298 | USETW(req.wIndex, index); | 298 | USETW(req.wIndex, index); | |
299 | USETW(req.wLength, length); | 299 | USETW(req.wLength, length); | |
300 | 300 | |||
301 | #ifdef ATU_DEBUG | 301 | #ifdef ATU_DEBUG | |
302 | if (atudebug) { | 302 | if (atudebug) { | |
303 | DPRINTFN(20, ("%s: req=%02x val=%02x ind=%02x " | 303 | DPRINTFN(20, ("%s: req=%02x val=%02x ind=%02x " | |
304 | "len=%02x\n", device_xname(sc->atu_dev), request, | 304 | "len=%02x\n", device_xname(sc->atu_dev), request, | |
305 | value, index, length)); | 305 | value, index, length)); | |
306 | } | 306 | } | |
307 | #endif /* ATU_DEBUG */ | 307 | #endif /* ATU_DEBUG */ | |
308 | 308 | |||
309 | s = splnet(); | 309 | s = splnet(); | |
310 | 310 | |||
311 | struct usbd_pipe *pipe0 = usbd_get_pipe0(sc->atu_udev); | 311 | struct usbd_pipe *pipe0 = usbd_get_pipe0(sc->atu_udev); | |
312 | int error = usbd_create_xfer(pipe0, length, 0, 0, | 312 | int error = usbd_create_xfer(pipe0, length, 0, 0, | |
313 | &xfer); | 313 | &xfer); | |
314 | if (error) { | 314 | if (error) { | |
315 | splx(s); | 315 | splx(s); | |
316 | return USBD_IOERROR; | 316 | return USBD_IOERROR; | |
317 | } | 317 | } | |
318 | usbd_setup_default_xfer(xfer, sc->atu_udev, 0, 500000, &req, data, | 318 | usbd_setup_default_xfer(xfer, sc->atu_udev, 0, 500000, &req, data, | |
319 | length, USBD_SHORT_XFER_OK, NULL); | 319 | length, USBD_SHORT_XFER_OK, NULL); | |
320 | 320 | |||
321 | err = usbd_sync_transfer(xfer); | 321 | err = usbd_sync_transfer(xfer); | |
322 | 322 | |||
323 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); | 323 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); | |
324 | 324 | |||
325 | #ifdef ATU_DEBUG | 325 | #ifdef ATU_DEBUG | |
326 | if (atudebug) { | 326 | if (atudebug) { | |
327 | if (type & UT_READ) { | 327 | if (type & UT_READ) { | |
328 | DPRINTFN(20, ("%s: transferred %#x bytes in\n", | 328 | DPRINTFN(20, ("%s: transferred %#x bytes in\n", | |
329 | device_xname(sc->atu_dev), total_len)); | 329 | device_xname(sc->atu_dev), total_len)); | |
330 | } else { | 330 | } else { | |
331 | if (total_len != length) | 331 | if (total_len != length) | |
332 | DPRINTF(("%s: wrote only %x bytes\n", | 332 | DPRINTF(("%s: wrote only %x bytes\n", | |
333 | device_xname(sc->atu_dev), total_len)); | 333 | device_xname(sc->atu_dev), total_len)); | |
334 | } | 334 | } | |
335 | } | 335 | } | |
336 | #endif /* ATU_DEBUG */ | 336 | #endif /* ATU_DEBUG */ | |
337 | 337 | |||
338 | usbd_destroy_xfer(xfer); | 338 | usbd_destroy_xfer(xfer); | |
339 | 339 | |||
340 | splx(s); | 340 | splx(s); | |
341 | return err; | 341 | return err; | |
342 | } | 342 | } | |
343 | 343 | |||
344 | static int | 344 | static int | |
345 | atu_send_command(struct atu_softc *sc, uint8_t *command, int size) | 345 | atu_send_command(struct atu_softc *sc, uint8_t *command, int size) | |
346 | { | 346 | { | |
347 | return atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, | 347 | return atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, | |
348 | 0x0000, size, command); | 348 | 0x0000, size, command); | |
349 | } | 349 | } | |
350 | 350 | |||
351 | static int | 351 | static int | |
352 | atu_get_cmd_status(struct atu_softc *sc, uint8_t cmd, uint8_t *status) | 352 | atu_get_cmd_status(struct atu_softc *sc, uint8_t cmd, uint8_t *status) | |
353 | { | 353 | { | |
354 | /* | 354 | /* | |
355 | * all other drivers (including Windoze) request 40 bytes of status | 355 | * all other drivers (including Windoze) request 40 bytes of status | |
356 | * and get a short-xfer of just 6 bytes. we can save 34 bytes of | 356 | * and get a short-xfer of just 6 bytes. we can save 34 bytes of | |
357 | * buffer if we just request those 6 bytes in the first place :) | 357 | * buffer if we just request those 6 bytes in the first place :) | |
358 | */ | 358 | */ | |
359 | /* | 359 | /* | |
360 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd, | 360 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd, | |
361 | 0x0000, 40, status); | 361 | 0x0000, 40, status); | |
362 | */ | 362 | */ | |
363 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd, | 363 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd, | |
364 | 0x0000, 6, status); | 364 | 0x0000, 6, status); | |
365 | } | 365 | } | |
366 | 366 | |||
367 | static int | 367 | static int | |
368 | atu_wait_completion(struct atu_softc *sc, uint8_t cmd, uint8_t *status) | 368 | atu_wait_completion(struct atu_softc *sc, uint8_t cmd, uint8_t *status) | |
369 | { | 369 | { | |
370 | int idle_count = 0, err; | 370 | int idle_count = 0, err; | |
371 | uint8_t statusreq[6]; | 371 | uint8_t statusreq[6]; | |
372 | 372 | |||
373 | DPRINTFN(15, ("%s: wait-completion: cmd=%02x\n", | 373 | DPRINTFN(15, ("%s: wait-completion: cmd=%02x\n", | |
374 | device_xname(sc->atu_dev), cmd)); | 374 | device_xname(sc->atu_dev), cmd)); | |
375 | 375 | |||
376 | while (1) { | 376 | while (1) { | |
377 | err = atu_get_cmd_status(sc, cmd, statusreq); | 377 | err = atu_get_cmd_status(sc, cmd, statusreq); | |
378 | if (err) | 378 | if (err) | |
379 | return err; | 379 | return err; | |
380 | 380 | |||
381 | #ifdef ATU_DEBUG | 381 | #ifdef ATU_DEBUG | |
382 | if (atudebug) { | 382 | if (atudebug) { | |
383 | DPRINTFN(20, ("%s: status=%s cmd=%02x\n", | 383 | DPRINTFN(20, ("%s: status=%s cmd=%02x\n", | |
384 | device_xname(sc->atu_dev), | 384 | device_xname(sc->atu_dev), | |
385 | ether_sprintf(statusreq), cmd)); | 385 | ether_sprintf(statusreq), cmd)); | |
386 | } | 386 | } | |
387 | #endif /* ATU_DEBUG */ | 387 | #endif /* ATU_DEBUG */ | |
388 | 388 | |||
389 | /* | 389 | /* | |
390 | * during normal operations waiting on STATUS_IDLE | 390 | * during normal operations waiting on STATUS_IDLE | |
391 | * will never happen more than once | 391 | * will never happen more than once | |
392 | */ | 392 | */ | |
393 | if ((statusreq[5] == STATUS_IDLE) && (idle_count++ > 20)) { | 393 | if ((statusreq[5] == STATUS_IDLE) && (idle_count++ > 20)) { | |
394 | DPRINTF(("%s: idle_count > 20!\n", | 394 | DPRINTF(("%s: idle_count > 20!\n", | |
395 | device_xname(sc->atu_dev))); | 395 | device_xname(sc->atu_dev))); | |
396 | return 0; | 396 | return 0; | |
397 | } | 397 | } | |
398 | 398 | |||
399 | if ((statusreq[5] != STATUS_IN_PROGRESS) && | 399 | if ((statusreq[5] != STATUS_IN_PROGRESS) && | |
400 | (statusreq[5] != STATUS_IDLE)) { | 400 | (statusreq[5] != STATUS_IDLE)) { | |
401 | if (status != NULL) | 401 | if (status != NULL) | |
402 | *status = statusreq[5]; | 402 | *status = statusreq[5]; | |
403 | return 0; | 403 | return 0; | |
404 | } | 404 | } | |
405 | usbd_delay_ms(sc->atu_udev, 25); | 405 | usbd_delay_ms(sc->atu_udev, 25); | |
406 | } | 406 | } | |
407 | } | 407 | } | |
408 | 408 | |||
409 | static int | 409 | static int | |
410 | atu_send_mib(struct atu_softc *sc, uint8_t type, uint8_t size, | 410 | atu_send_mib(struct atu_softc *sc, uint8_t type, uint8_t size, | |
411 | uint8_t index, void *data) | 411 | uint8_t index, void *data) | |
412 | { | 412 | { | |
413 | int err; | 413 | int err; | |
414 | struct atu_cmd_set_mib request; | 414 | struct atu_cmd_set_mib request; | |
415 | 415 | |||
416 | /* | 416 | /* | |
417 | * We don't construct a MIB packet first and then memcpy it into an | 417 | * We don't construct a MIB packet first and then memcpy it into an | |
418 | * Atmel-command-packet, we just construct it the right way at once :) | 418 | * Atmel-command-packet, we just construct it the right way at once :) | |
419 | */ | 419 | */ | |
420 | 420 | |||
421 | memset(&request, 0, sizeof(request)); | 421 | memset(&request, 0, sizeof(request)); | |
422 | 422 | |||
423 | request.AtCmd = CMD_SET_MIB; | 423 | request.AtCmd = CMD_SET_MIB; | |
424 | USETW(request.AtSize, size + 4); | 424 | USETW(request.AtSize, size + 4); | |
425 | 425 | |||
426 | request.MIBType = type; | 426 | request.MIBType = type; | |
427 | request.MIBSize = size; | 427 | request.MIBSize = size; | |
428 | request.MIBIndex = index; | 428 | request.MIBIndex = index; | |
429 | request.MIBReserved = 0; | 429 | request.MIBReserved = 0; | |
430 | 430 | |||
431 | /* | 431 | /* | |
432 | * For 1 and 2 byte requests we assume a direct value, | 432 | * For 1 and 2 byte requests we assume a direct value, | |
433 | * everything bigger than 2 bytes we assume a pointer to the data | 433 | * everything bigger than 2 bytes we assume a pointer to the data | |
434 | */ | 434 | */ | |
435 | switch (size) { | 435 | switch (size) { | |
436 | case 0: | 436 | case 0: | |
437 | break; | 437 | break; | |
438 | case 1: | 438 | case 1: | |
439 | request.data[0]=(long)data & 0x000000ff; | 439 | request.data[0]=(long)data & 0x000000ff; | |
440 | break; | 440 | break; | |
441 | case 2: | 441 | case 2: | |
442 | request.data[0]=(long)data & 0x000000ff; | 442 | request.data[0]=(long)data & 0x000000ff; | |
443 | request.data[1]=(long)data >> 8; | 443 | request.data[1]=(long)data >> 8; | |
444 | break; | 444 | break; | |
445 | default: | 445 | default: | |
446 | memcpy(request.data, data, size); | 446 | memcpy(request.data, data, size); | |
447 | break; | 447 | break; | |
448 | } | 448 | } | |
449 | 449 | |||
450 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, | 450 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, | |
451 | 0x0000, size+8, (uByte *)&request); | 451 | 0x0000, size+8, (uByte *)&request); | |
452 | if (err) | 452 | if (err) | |
453 | return err; | 453 | return err; | |
454 | 454 | |||
455 | DPRINTFN(15, ("%s: sendmib : waitcompletion...\n", | 455 | DPRINTFN(15, ("%s: sendmib : waitcompletion...\n", | |
456 | device_xname(sc->atu_dev))); | 456 | device_xname(sc->atu_dev))); | |
457 | return atu_wait_completion(sc, CMD_SET_MIB, NULL); | 457 | return atu_wait_completion(sc, CMD_SET_MIB, NULL); | |
458 | } | 458 | } | |
459 | 459 | |||
460 | static int | 460 | static int | |
461 | atu_get_mib(struct atu_softc *sc, uint8_t type, uint8_t size, | 461 | atu_get_mib(struct atu_softc *sc, uint8_t type, uint8_t size, | |
462 | uint8_t index, uint8_t *buf) | 462 | uint8_t index, uint8_t *buf) | |
463 | { | 463 | { | |
464 | 464 | |||
465 | /* linux/at76c503.c - 478 */ | 465 | /* linux/at76c503.c - 478 */ | |
466 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x033, | 466 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x033, | |
467 | type << 8, index, size, buf); | 467 | type << 8, index, size, buf); | |
468 | } | 468 | } | |
469 | 469 | |||
470 | #if 0 | 470 | #if 0 | |
471 | int | 471 | int | |
472 | atu_start_ibss(struct atu_softc *sc) | 472 | atu_start_ibss(struct atu_softc *sc) | |
473 | { | 473 | { | |
474 | struct ieee80211com *ic = &sc->sc_ic; | 474 | struct ieee80211com *ic = &sc->sc_ic; | |
475 | int err; | 475 | int err; | |
476 | struct atu_cmd_start_ibss Request; | 476 | struct atu_cmd_start_ibss Request; | |
477 | 477 | |||
478 | Request.Cmd = CMD_START_IBSS; | 478 | Request.Cmd = CMD_START_IBSS; | |
479 | Request.Reserved = 0; | 479 | Request.Reserved = 0; | |
480 | Request.Size = sizeof(Request) - 4; | 480 | Request.Size = sizeof(Request) - 4; | |
481 | 481 | |||
482 | memset(Request.BSSID, 0x00, sizeof(Request.BSSID)); | 482 | memset(Request.BSSID, 0x00, sizeof(Request.BSSID)); | |
483 | memset(Request.SSID, 0x00, sizeof(Request.SSID)); | 483 | memset(Request.SSID, 0x00, sizeof(Request.SSID)); | |
484 | memcpy(Request.SSID, ic->ic_des_ssid, ic->ic_des_ssidlen); | 484 | memcpy(Request.SSID, ic->ic_des_ssid, ic->ic_des_ssidlen); | |
485 | Request.SSIDSize = ic->ic_des_ssidlen; | 485 | Request.SSIDSize = ic->ic_des_ssidlen; | |
486 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | 486 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | |
487 | Request.Channel = (uint8_t)sc->atu_desired_channel; | 487 | Request.Channel = (uint8_t)sc->atu_desired_channel; | |
488 | else | 488 | else | |
489 | Request.Channel = ATU_DEFAULT_CHANNEL; | 489 | Request.Channel = ATU_DEFAULT_CHANNEL; | |
490 | Request.BSSType = AD_HOC_MODE; | 490 | Request.BSSType = AD_HOC_MODE; | |
491 | memset(Request.Res, 0x00, sizeof(Request.Res)); | 491 | memset(Request.Res, 0x00, sizeof(Request.Res)); | |
492 | 492 | |||
493 | /* Write config to adapter */ | 493 | /* Write config to adapter */ | |
494 | err = atu_send_command(sc, (uint8_t *)&Request, sizeof(Request)); | 494 | err = atu_send_command(sc, (uint8_t *)&Request, sizeof(Request)); | |
495 | if (err) { | 495 | if (err) { | |
496 | DPRINTF(("%s: start ibss failed!\n", | 496 | DPRINTF(("%s: start ibss failed!\n", | |
497 | device_xname(sc->atu_dev))); | 497 | device_xname(sc->atu_dev))); | |
498 | return err; | 498 | return err; | |
499 | } | 499 | } | |
500 | 500 | |||
501 | /* Wait for the adapter to do its thing */ | 501 | /* Wait for the adapter to do its thing */ | |
502 | err = atu_wait_completion(sc, CMD_START_IBSS, NULL); | 502 | err = atu_wait_completion(sc, CMD_START_IBSS, NULL); | |
503 | if (err) { | 503 | if (err) { | |
504 | DPRINTF(("%s: error waiting for start_ibss\n", | 504 | DPRINTF(("%s: error waiting for start_ibss\n", | |
505 | device_xname(sc->atu_dev))); | 505 | device_xname(sc->atu_dev))); | |
506 | return err; | 506 | return err; | |
507 | } | 507 | } | |
508 | 508 | |||
509 | /* Get the current BSSID */ | 509 | /* Get the current BSSID */ | |
510 | err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_BSSID, sc->atu_bssid); | 510 | err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_BSSID, sc->atu_bssid); | |
511 | if (err) { | 511 | if (err) { | |
512 | DPRINTF(("%s: could not get BSSID!\n", | 512 | DPRINTF(("%s: could not get BSSID!\n", | |
513 | device_xname(sc->atu_dev))); | 513 | device_xname(sc->atu_dev))); | |
514 | return err; | 514 | return err; | |
515 | } | 515 | } | |
516 | 516 | |||
517 | DPRINTF(("%s: started a new IBSS (BSSID=%s)\n", | 517 | DPRINTF(("%s: started a new IBSS (BSSID=%s)\n", | |
518 | device_xname(sc->atu_dev), ether_sprintf(sc->atu_bssid))); | 518 | device_xname(sc->atu_dev), ether_sprintf(sc->atu_bssid))); | |
519 | return 0; | 519 | return 0; | |
520 | } | 520 | } | |
521 | #endif | 521 | #endif | |
522 | 522 | |||
523 | static int | 523 | static int | |
524 | atu_start_scan(struct atu_softc *sc) | 524 | atu_start_scan(struct atu_softc *sc) | |
525 | { | 525 | { | |
526 | struct ieee80211com *ic = &sc->sc_ic; | 526 | struct ieee80211com *ic = &sc->sc_ic; | |
527 | struct atu_cmd_do_scan Scan; | 527 | struct atu_cmd_do_scan Scan; | |
528 | usbd_status err; | 528 | usbd_status err; | |
529 | int Cnt; | 529 | int Cnt; | |
530 | 530 | |||
531 | memset(&Scan, 0, sizeof(Scan)); | 531 | memset(&Scan, 0, sizeof(Scan)); | |
532 | 532 | |||
533 | Scan.Cmd = CMD_START_SCAN; | 533 | Scan.Cmd = CMD_START_SCAN; | |
534 | Scan.Reserved = 0; | 534 | Scan.Reserved = 0; | |
535 | USETW(Scan.Size, sizeof(Scan) - 4); | 535 | USETW(Scan.Size, sizeof(Scan) - 4); | |
536 | 536 | |||
537 | /* use the broadcast BSSID (in active scan) */ | 537 | /* use the broadcast BSSID (in active scan) */ | |
538 | for (Cnt=0; Cnt<6; Cnt++) | 538 | for (Cnt=0; Cnt<6; Cnt++) | |
539 | Scan.BSSID[Cnt] = 0xff; | 539 | Scan.BSSID[Cnt] = 0xff; | |
540 | 540 | |||
541 | memset(Scan.SSID, 0x00, sizeof(Scan.SSID)); | 541 | memset(Scan.SSID, 0x00, sizeof(Scan.SSID)); | |
542 | memcpy(Scan.SSID, ic->ic_des_essid, ic->ic_des_esslen); | 542 | memcpy(Scan.SSID, ic->ic_des_essid, ic->ic_des_esslen); | |
543 | Scan.SSID_Len = ic->ic_des_esslen; | 543 | Scan.SSID_Len = ic->ic_des_esslen; | |
544 | 544 | |||
545 | /* default values for scan */ | 545 | /* default values for scan */ | |
546 | Scan.ScanType = ATU_SCAN_ACTIVE; | 546 | Scan.ScanType = ATU_SCAN_ACTIVE; | |
547 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | 547 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | |
548 | Scan.Channel = (uint8_t)sc->atu_desired_channel; | 548 | Scan.Channel = (uint8_t)sc->atu_desired_channel; | |
549 | else | 549 | else | |
550 | Scan.Channel = sc->atu_channel; | 550 | Scan.Channel = sc->atu_channel; | |
551 | 551 | |||
552 | ic->ic_curchan = &ic->ic_channels[Scan.Channel]; | 552 | ic->ic_curchan = &ic->ic_channels[Scan.Channel]; | |
553 | 553 | |||
554 | /* we like scans to be quick :) */ | 554 | /* we like scans to be quick :) */ | |
555 | /* the time we wait before sending probe's */ | 555 | /* the time we wait before sending probe's */ | |
556 | USETW(Scan.ProbeDelay, 0); | 556 | USETW(Scan.ProbeDelay, 0); | |
557 | /* the time we stay on one channel */ | 557 | /* the time we stay on one channel */ | |
558 | USETW(Scan.MinChannelTime, 100); | 558 | USETW(Scan.MinChannelTime, 100); | |
559 | USETW(Scan.MaxChannelTime, 200); | 559 | USETW(Scan.MaxChannelTime, 200); | |
560 | /* whether or not we scan all channels */ | 560 | /* whether or not we scan all channels */ | |
561 | Scan.InternationalScan = 0xc1; | 561 | Scan.InternationalScan = 0xc1; | |
562 | 562 | |||
563 | #ifdef ATU_DEBUG | 563 | #ifdef ATU_DEBUG | |
564 | if (atudebug) { | 564 | if (atudebug) { | |
565 | DPRINTFN(20, ("%s: scan cmd len=%02zx\n", | 565 | DPRINTFN(20, ("%s: scan cmd len=%02zx\n", | |
566 | device_xname(sc->atu_dev), sizeof(Scan))); | 566 | device_xname(sc->atu_dev), sizeof(Scan))); | |
567 | } | 567 | } | |
568 | #endif /* ATU_DEBUG */ | 568 | #endif /* ATU_DEBUG */ | |
569 | 569 | |||
570 | /* Write config to adapter */ | 570 | /* Write config to adapter */ | |
571 | err = atu_send_command(sc, (uint8_t *)&Scan, sizeof(Scan)); | 571 | err = atu_send_command(sc, (uint8_t *)&Scan, sizeof(Scan)); | |
572 | if (err) | 572 | if (err) | |
573 | return err; | 573 | return err; | |
574 | 574 | |||
575 | /* | 575 | /* | |
576 | * We don't wait for the command to finish... the mgmt-thread will do | 576 | * We don't wait for the command to finish... the mgmt-thread will do | |
577 | * that for us | 577 | * that for us | |
578 | */ | 578 | */ | |
579 | /* | 579 | /* | |
580 | err = atu_wait_completion(sc, CMD_START_SCAN, NULL); | 580 | err = atu_wait_completion(sc, CMD_START_SCAN, NULL); | |
581 | if (err) | 581 | if (err) | |
582 | return err; | 582 | return err; | |
583 | */ | 583 | */ | |
584 | return 0; | 584 | return 0; | |
585 | } | 585 | } | |
586 | 586 | |||
587 | static int | 587 | static int | |
588 | atu_switch_radio(struct atu_softc *sc, int state) | 588 | atu_switch_radio(struct atu_softc *sc, int state) | |
589 | { | 589 | { | |
590 | usbd_status err; | 590 | usbd_status err; | |
591 | struct atu_cmd CmdRadio; | 591 | struct atu_cmd CmdRadio; | |
592 | 592 | |||
593 | if (sc->atu_radio == RadioIntersil) { | 593 | if (sc->atu_radio == RadioIntersil) { | |
594 | /* | 594 | /* | |
595 | * Intersil doesn't seem to need/support switching the radio | 595 | * Intersil doesn't seem to need/support switching the radio | |
596 | * on/off | 596 | * on/off | |
597 | */ | 597 | */ | |
598 | return 0; | 598 | return 0; | |
599 | } | 599 | } | |
600 | 600 | |||
601 | memset(&CmdRadio, 0, sizeof(CmdRadio)); | 601 | memset(&CmdRadio, 0, sizeof(CmdRadio)); | |
602 | CmdRadio.Cmd = CMD_RADIO_ON; | 602 | CmdRadio.Cmd = CMD_RADIO_ON; | |
603 | 603 | |||
604 | if (sc->atu_radio_on != state) { | 604 | if (sc->atu_radio_on != state) { | |
605 | if (state == 0) | 605 | if (state == 0) | |
606 | CmdRadio.Cmd = CMD_RADIO_OFF; | 606 | CmdRadio.Cmd = CMD_RADIO_OFF; | |
607 | 607 | |||
608 | err = atu_send_command(sc, (uint8_t *)&CmdRadio, | 608 | err = atu_send_command(sc, (uint8_t *)&CmdRadio, | |
609 | sizeof(CmdRadio)); | 609 | sizeof(CmdRadio)); | |
610 | if (err) | 610 | if (err) | |
611 | return err; | 611 | return err; | |
612 | 612 | |||
613 | err = atu_wait_completion(sc, CmdRadio.Cmd, NULL); | 613 | err = atu_wait_completion(sc, CmdRadio.Cmd, NULL); | |
614 | if (err) | 614 | if (err) | |
615 | return err; | 615 | return err; | |
616 | 616 | |||
617 | DPRINTFN(10, ("%s: radio turned %s\n", | 617 | DPRINTFN(10, ("%s: radio turned %s\n", | |
618 | device_xname(sc->atu_dev), state ? "on" : "off")); | 618 | device_xname(sc->atu_dev), state ? "on" : "off")); | |
619 | sc->atu_radio_on = state; | 619 | sc->atu_radio_on = state; | |
620 | } | 620 | } | |
621 | return 0; | 621 | return 0; | |
622 | } | 622 | } | |
623 | 623 | |||
624 | static int | 624 | static int | |
625 | atu_initial_config(struct atu_softc *sc) | 625 | atu_initial_config(struct atu_softc *sc) | |
626 | { | 626 | { | |
627 | struct ieee80211com *ic = &sc->sc_ic; | 627 | struct ieee80211com *ic = &sc->sc_ic; | |
628 | uint32_t i; | 628 | uint32_t i; | |
629 | usbd_status err; | 629 | usbd_status err; | |
630 | /* uint8_t rates[4] = {0x82, 0x84, 0x8B, 0x96};*/ | 630 | /* uint8_t rates[4] = {0x82, 0x84, 0x8B, 0x96};*/ | |
631 | uint8_t rates[4] = {0x82, 0x04, 0x0B, 0x16}; | 631 | uint8_t rates[4] = {0x82, 0x04, 0x0B, 0x16}; | |
632 | struct atu_cmd_card_config cmd; | 632 | struct atu_cmd_card_config cmd; | |
633 | uint8_t reg_domain; | 633 | uint8_t reg_domain; | |
634 | 634 | |||
635 | DPRINTFN(10, ("%s: sending mac-addr\n", device_xname(sc->atu_dev))); | 635 | DPRINTFN(10, ("%s: sending mac-addr\n", device_xname(sc->atu_dev))); | |
636 | err = atu_send_mib(sc, MIB_MAC_ADDR__ADDR, ic->ic_myaddr); | 636 | err = atu_send_mib(sc, MIB_MAC_ADDR__ADDR, ic->ic_myaddr); | |
637 | if (err) { | 637 | if (err) { | |
638 | DPRINTF(("%s: error setting mac-addr\n", | 638 | DPRINTF(("%s: error setting mac-addr\n", | |
639 | device_xname(sc->atu_dev))); | 639 | device_xname(sc->atu_dev))); | |
640 | return err; | 640 | return err; | |
641 | } | 641 | } | |
642 | 642 | |||
643 | /* | 643 | /* | |
644 | DPRINTF(("%s: sending reg-domain\n", device_xname(sc->atu_dev))); | 644 | DPRINTF(("%s: sending reg-domain\n", device_xname(sc->atu_dev))); | |
645 | err = atu_send_mib(sc, MIB_PHY__REG_DOMAIN, NR(0x30)); | 645 | err = atu_send_mib(sc, MIB_PHY__REG_DOMAIN, NR(0x30)); | |
646 | if (err) { | 646 | if (err) { | |
647 | DPRINTF(("%s: error setting mac-addr\n", | 647 | DPRINTF(("%s: error setting mac-addr\n", | |
648 | device_xname(sc->atu_dev))); | 648 | device_xname(sc->atu_dev))); | |
649 | return err; | 649 | return err; | |
650 | } | 650 | } | |
651 | */ | 651 | */ | |
652 | 652 | |||
653 | memset(&cmd, 0, sizeof(cmd)); | 653 | memset(&cmd, 0, sizeof(cmd)); | |
654 | cmd.Cmd = CMD_STARTUP; | 654 | cmd.Cmd = CMD_STARTUP; | |
655 | cmd.Reserved = 0; | 655 | cmd.Reserved = 0; | |
656 | USETW(cmd.Size, sizeof(cmd) - 4); | 656 | USETW(cmd.Size, sizeof(cmd) - 4); | |
657 | 657 | |||
658 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | 658 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | |
659 | cmd.Channel = (uint8_t)sc->atu_desired_channel; | 659 | cmd.Channel = (uint8_t)sc->atu_desired_channel; | |
660 | else | 660 | else | |
661 | cmd.Channel = sc->atu_channel; | 661 | cmd.Channel = sc->atu_channel; | |
662 | cmd.AutoRateFallback = 1; | 662 | cmd.AutoRateFallback = 1; | |
663 | memcpy(cmd.BasicRateSet, rates, 4); | 663 | memcpy(cmd.BasicRateSet, rates, 4); | |
664 | 664 | |||
665 | /* ShortRetryLimit should be 7 according to 802.11 spec */ | 665 | /* ShortRetryLimit should be 7 according to 802.11 spec */ | |
666 | cmd.ShortRetryLimit = 7; | 666 | cmd.ShortRetryLimit = 7; | |
667 | USETW(cmd.RTS_Threshold, 2347); | 667 | USETW(cmd.RTS_Threshold, 2347); | |
668 | USETW(cmd.FragThreshold, 2346); | 668 | USETW(cmd.FragThreshold, 2346); | |
669 | 669 | |||
670 | /* Doesn't seem to work, but we'll set it to 1 anyway */ | 670 | /* Doesn't seem to work, but we'll set it to 1 anyway */ | |
671 | cmd.PromiscuousMode = 1; | 671 | cmd.PromiscuousMode = 1; | |
672 | 672 | |||
673 | /* this goes into the beacon we transmit */ | 673 | /* this goes into the beacon we transmit */ | |
674 | if (ic->ic_flags & IEEE80211_F_PRIVACY) | 674 | if (ic->ic_flags & IEEE80211_F_PRIVACY) | |
675 | cmd.PrivacyInvoked = 1; | 675 | cmd.PrivacyInvoked = 1; | |
676 | else | 676 | else | |
677 | cmd.PrivacyInvoked = 0; | 677 | cmd.PrivacyInvoked = 0; | |
678 | 678 | |||
679 | cmd.ExcludeUnencrypted = 0; | 679 | cmd.ExcludeUnencrypted = 0; | |
680 | 680 | |||
681 | if (ic->ic_flags & IEEE80211_F_PRIVACY) { | 681 | if (ic->ic_flags & IEEE80211_F_PRIVACY) { | |
682 | switch (ic->ic_nw_keys[ic->ic_def_txkey].wk_keylen) { | 682 | switch (ic->ic_nw_keys[ic->ic_def_txkey].wk_keylen) { | |
683 | case 5: | 683 | case 5: | |
684 | cmd.EncryptionType = ATU_WEP_40BITS; | 684 | cmd.EncryptionType = ATU_WEP_40BITS; | |
685 | break; | 685 | break; | |
686 | case 13: | 686 | case 13: | |
687 | cmd.EncryptionType = ATU_WEP_104BITS; | 687 | cmd.EncryptionType = ATU_WEP_104BITS; | |
688 | break; | 688 | break; | |
689 | default: | 689 | default: | |
690 | cmd.EncryptionType = ATU_WEP_OFF; | 690 | cmd.EncryptionType = ATU_WEP_OFF; | |
691 | break; | 691 | break; | |
692 | } | 692 | } | |
693 | 693 | |||
694 | 694 | |||
695 | cmd.WEP_DefaultKeyID = ic->ic_def_txkey; | 695 | cmd.WEP_DefaultKeyID = ic->ic_def_txkey; | |
696 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { | 696 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { | |
697 | memcpy(cmd.WEP_DefaultKey[i], ic->ic_nw_keys[i].wk_key, | 697 | memcpy(cmd.WEP_DefaultKey[i], ic->ic_nw_keys[i].wk_key, | |
698 | ic->ic_nw_keys[i].wk_keylen); | 698 | ic->ic_nw_keys[i].wk_keylen); | |
699 | } | 699 | } | |
700 | } | 700 | } | |
701 | 701 | |||
702 | /* Setting the SSID here doesn't seem to do anything */ | 702 | /* Setting the SSID here doesn't seem to do anything */ | |
703 | memset(cmd.SSID, 0x00, sizeof(cmd.SSID)); | 703 | memset(cmd.SSID, 0x00, sizeof(cmd.SSID)); | |
704 | memcpy(cmd.SSID, ic->ic_des_essid, ic->ic_des_esslen); | 704 | memcpy(cmd.SSID, ic->ic_des_essid, ic->ic_des_esslen); | |
705 | cmd.SSID_Len = ic->ic_des_esslen; | 705 | cmd.SSID_Len = ic->ic_des_esslen; | |
706 | 706 | |||
707 | cmd.ShortPreamble = 0; | 707 | cmd.ShortPreamble = 0; | |
708 | USETW(cmd.BeaconPeriod, 100); | 708 | USETW(cmd.BeaconPeriod, 100); | |
709 | /* cmd.BeaconPeriod = 65535; */ | 709 | /* cmd.BeaconPeriod = 65535; */ | |
710 | 710 | |||
711 | /* | 711 | /* | |
712 | * TODO: | 712 | * TODO: | |
713 | * read reg domain MIB_PHY @ 0x17 (1 byte), (reply = 0x30) | 713 | * read reg domain MIB_PHY @ 0x17 (1 byte), (reply = 0x30) | |
714 | * we should do something useful with this info. right now it's just | 714 | * we should do something useful with this info. right now it's just | |
715 | * ignored | 715 | * ignored | |
716 | */ | 716 | */ | |
717 | err = atu_get_mib(sc, MIB_PHY__REG_DOMAIN, ®_domain); | 717 | err = atu_get_mib(sc, MIB_PHY__REG_DOMAIN, ®_domain); | |
718 | if (err) { | 718 | if (err) { | |
719 | DPRINTF(("%s: could not get regdomain!\n", | 719 | DPRINTF(("%s: could not get regdomain!\n", | |
720 | device_xname(sc->atu_dev))); | 720 | device_xname(sc->atu_dev))); | |
721 | } else { | 721 | } else { | |
722 | DPRINTF(("%s: in reg domain %#x according to the " | 722 | DPRINTF(("%s: in reg domain %#x according to the " | |
723 | "adapter\n", device_xname(sc->atu_dev), reg_domain)); | 723 | "adapter\n", device_xname(sc->atu_dev), reg_domain)); | |
724 | } | 724 | } | |
725 | 725 | |||
726 | #ifdef ATU_DEBUG | 726 | #ifdef ATU_DEBUG | |
727 | if (atudebug) { | 727 | if (atudebug) { | |
728 | DPRINTFN(20, ("%s: configlen=%02zx\n", | 728 | DPRINTFN(20, ("%s: configlen=%02zx\n", | |
729 | device_xname(sc->atu_dev), sizeof(cmd))); | 729 | device_xname(sc->atu_dev), sizeof(cmd))); | |
730 | } | 730 | } | |
731 | #endif /* ATU_DEBUG */ | 731 | #endif /* ATU_DEBUG */ | |
732 | 732 | |||
733 | /* Windoze : driver says exclude-unencrypted=1 & encr-type=1 */ | 733 | /* Windoze : driver says exclude-unencrypted=1 & encr-type=1 */ | |
734 | 734 | |||
735 | err = atu_send_command(sc, (uint8_t *)&cmd, sizeof(cmd)); | 735 | err = atu_send_command(sc, (uint8_t *)&cmd, sizeof(cmd)); | |
736 | if (err) | 736 | if (err) | |
737 | return err; | 737 | return err; | |
738 | err = atu_wait_completion(sc, CMD_STARTUP, NULL); | 738 | err = atu_wait_completion(sc, CMD_STARTUP, NULL); | |
739 | if (err) | 739 | if (err) | |
740 | return err; | 740 | return err; | |
741 | 741 | |||
742 | /* Turn on radio now */ | 742 | /* Turn on radio now */ | |
743 | err = atu_switch_radio(sc, 1); | 743 | err = atu_switch_radio(sc, 1); | |
744 | if (err) | 744 | if (err) | |
745 | return err; | 745 | return err; | |
746 | 746 | |||
747 | /* preamble type = short */ | 747 | /* preamble type = short */ | |
748 | err = atu_send_mib(sc, MIB_LOCAL__PREAMBLE, NR(PREAMBLE_SHORT)); | 748 | err = atu_send_mib(sc, MIB_LOCAL__PREAMBLE, NR(PREAMBLE_SHORT)); | |
749 | if (err) | 749 | if (err) | |
750 | return err; | 750 | return err; | |
751 | 751 | |||
752 | /* frag = 1536 */ | 752 | /* frag = 1536 */ | |
753 | err = atu_send_mib(sc, MIB_MAC__FRAG, NR(2346)); | 753 | err = atu_send_mib(sc, MIB_MAC__FRAG, NR(2346)); | |
754 | if (err) | 754 | if (err) | |
755 | return err; | 755 | return err; | |
756 | 756 | |||
757 | /* rts = 1536 */ | 757 | /* rts = 1536 */ | |
758 | err = atu_send_mib(sc, MIB_MAC__RTS, NR(2347)); | 758 | err = atu_send_mib(sc, MIB_MAC__RTS, NR(2347)); | |
759 | if (err) | 759 | if (err) | |
760 | return err; | 760 | return err; | |
761 | 761 | |||
762 | /* auto rate fallback = 1 */ | 762 | /* auto rate fallback = 1 */ | |
763 | err = atu_send_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, NR(1)); | 763 | err = atu_send_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, NR(1)); | |
764 | if (err) | 764 | if (err) | |
765 | return err; | 765 | return err; | |
766 | 766 | |||
767 | /* power mode = full on, no power saving */ | 767 | /* power mode = full on, no power saving */ | |
768 | err = atu_send_mib(sc, MIB_MAC_MGMT__POWER_MODE, | 768 | err = atu_send_mib(sc, MIB_MAC_MGMT__POWER_MODE, | |
769 | NR(POWER_MODE_ACTIVE)); | 769 | NR(POWER_MODE_ACTIVE)); | |
770 | if (err) | 770 | if (err) | |
771 | return err; | 771 | return err; | |
772 | 772 | |||
773 | DPRINTFN(10, ("%s: completed initial config\n", | 773 | DPRINTFN(10, ("%s: completed initial config\n", | |
774 | device_xname(sc->atu_dev))); | 774 | device_xname(sc->atu_dev))); | |
775 | return 0; | 775 | return 0; | |
776 | } | 776 | } | |
777 | 777 | |||
778 | static int | 778 | static int | |
779 | atu_join(struct atu_softc *sc, struct ieee80211_node *node) | 779 | atu_join(struct atu_softc *sc, struct ieee80211_node *node) | |
780 | { | 780 | { | |
781 | struct atu_cmd_join join; | 781 | struct atu_cmd_join join; | |
782 | uint8_t status = 0; /* XXX: GCC */ | 782 | uint8_t status = 0; /* XXX: GCC */ | |
783 | usbd_status err; | 783 | usbd_status err; | |
784 | 784 | |||
785 | memset(&join, 0, sizeof(join)); | 785 | memset(&join, 0, sizeof(join)); | |
786 | 786 | |||
787 | join.Cmd = CMD_JOIN; | 787 | join.Cmd = CMD_JOIN; | |
788 | join.Reserved = 0x00; | 788 | join.Reserved = 0x00; | |
789 | USETW(join.Size, sizeof(join) - 4); | 789 | USETW(join.Size, sizeof(join) - 4); | |
790 | 790 | |||
791 | DPRINTFN(15, ("%s: pre-join sc->atu_bssid=%s\n", | 791 | DPRINTFN(15, ("%s: pre-join sc->atu_bssid=%s\n", | |
792 | device_xname(sc->atu_dev), ether_sprintf(sc->atu_bssid))); | 792 | device_xname(sc->atu_dev), ether_sprintf(sc->atu_bssid))); | |
793 | DPRINTFN(15, ("%s: mode=%d\n", device_xname(sc->atu_dev), | 793 | DPRINTFN(15, ("%s: mode=%d\n", device_xname(sc->atu_dev), | |
794 | sc->atu_mode)); | 794 | sc->atu_mode)); | |
795 | memcpy(join.bssid, node->ni_bssid, IEEE80211_ADDR_LEN); | 795 | memcpy(join.bssid, node->ni_bssid, IEEE80211_ADDR_LEN); | |
796 | memset(join.essid, 0x00, 32); | 796 | memset(join.essid, 0x00, 32); | |
797 | memcpy(join.essid, node->ni_essid, node->ni_esslen); | 797 | memcpy(join.essid, node->ni_essid, node->ni_esslen); | |
798 | join.essid_size = node->ni_esslen; | 798 | join.essid_size = node->ni_esslen; | |
799 | if (node->ni_capinfo & IEEE80211_CAPINFO_IBSS) | 799 | if (node->ni_capinfo & IEEE80211_CAPINFO_IBSS) | |
800 | join.bss_type = AD_HOC_MODE; | 800 | join.bss_type = AD_HOC_MODE; | |
801 | else | 801 | else | |
802 | join.bss_type = INFRASTRUCTURE_MODE; | 802 | join.bss_type = INFRASTRUCTURE_MODE; | |
803 | join.channel = ieee80211_chan2ieee(&sc->sc_ic, node->ni_chan); | 803 | join.channel = ieee80211_chan2ieee(&sc->sc_ic, node->ni_chan); | |
804 | 804 | |||
805 | USETW(join.timeout, ATU_JOIN_TIMEOUT); | 805 | USETW(join.timeout, ATU_JOIN_TIMEOUT); | |
806 | join.reserved = 0x00; | 806 | join.reserved = 0x00; | |
807 | 807 | |||
808 | DPRINTFN(10, ("%s: trying to join BSSID=%s\n", | 808 | DPRINTFN(10, ("%s: trying to join BSSID=%s\n", | |
809 | device_xname(sc->atu_dev), ether_sprintf(join.bssid))); | 809 | device_xname(sc->atu_dev), ether_sprintf(join.bssid))); | |
810 | err = atu_send_command(sc, (uint8_t *)&join, sizeof(join)); | 810 | err = atu_send_command(sc, (uint8_t *)&join, sizeof(join)); | |
811 | if (err) { | 811 | if (err) { | |
812 | DPRINTF(("%s: ERROR trying to join IBSS\n", | 812 | DPRINTF(("%s: ERROR trying to join IBSS\n", | |
813 | device_xname(sc->atu_dev))); | 813 | device_xname(sc->atu_dev))); | |
814 | return err; | 814 | return err; | |
815 | } | 815 | } | |
816 | err = atu_wait_completion(sc, CMD_JOIN, &status); | 816 | err = atu_wait_completion(sc, CMD_JOIN, &status); | |
817 | if (err) { | 817 | if (err) { | |
818 | DPRINTF(("%s: error joining BSS!\n", | 818 | DPRINTF(("%s: error joining BSS!\n", | |
819 | device_xname(sc->atu_dev))); | 819 | device_xname(sc->atu_dev))); | |
820 | return err; | 820 | return err; | |
821 | } | 821 | } | |
822 | if (status != STATUS_COMPLETE) { | 822 | if (status != STATUS_COMPLETE) { | |
823 | DPRINTF(("%s: error joining... [status=%02x]\n", | 823 | DPRINTF(("%s: error joining... [status=%02x]\n", | |
824 | device_xname(sc->atu_dev), status)); | 824 | device_xname(sc->atu_dev), status)); | |
825 | return status; | 825 | return status; | |
826 | } else { | 826 | } else { | |
827 | DPRINTFN(10, ("%s: joined BSS\n", device_xname(sc->atu_dev))); | 827 | DPRINTFN(10, ("%s: joined BSS\n", device_xname(sc->atu_dev))); | |
828 | } | 828 | } | |
829 | return err; | 829 | return err; | |
830 | } | 830 | } | |
831 | 831 | |||
832 | /* | 832 | /* | |
833 | * Get the state of the DFU unit | 833 | * Get the state of the DFU unit | |
834 | */ | 834 | */ | |
835 | static int8_t | 835 | static int8_t | |
836 | atu_get_dfu_state(struct atu_softc *sc) | 836 | atu_get_dfu_state(struct atu_softc *sc) | |
837 | { | 837 | { | |
838 | uint8_t state; | 838 | uint8_t state; | |
839 | 839 | |||
840 | if (atu_usb_request(sc, DFU_GETSTATE, 0, 0, 1, &state)) | 840 | if (atu_usb_request(sc, DFU_GETSTATE, 0, 0, 1, &state)) | |
841 | return -1; | 841 | return -1; | |
842 | return state; | 842 | return state; | |
843 | } | 843 | } | |
844 | 844 | |||
845 | /* | 845 | /* | |
846 | * Get MAC opmode | 846 | * Get MAC opmode | |
847 | */ | 847 | */ | |
848 | static uint8_t | 848 | static uint8_t | |
849 | atu_get_opmode(struct atu_softc *sc, uint8_t *mode) | 849 | atu_get_opmode(struct atu_softc *sc, uint8_t *mode) | |
850 | { | 850 | { | |
851 | 851 | |||
852 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33, 0x0001, | 852 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33, 0x0001, | |
853 | 0x0000, 1, mode); | 853 | 0x0000, 1, mode); | |
854 | } | 854 | } | |
855 | 855 | |||
856 | /* | 856 | /* | |
857 | * Upload the internal firmware into the device | 857 | * Upload the internal firmware into the device | |
858 | */ | 858 | */ | |
859 | static void | 859 | static void | |
860 | atu_internal_firmware(device_t arg) | 860 | atu_internal_firmware(device_t arg) | |
861 | { | 861 | { | |
862 | struct atu_softc *sc = device_private(arg); | 862 | struct atu_softc *sc = device_private(arg); | |
863 | u_char state, *ptr = NULL, *firm = NULL, status[6]; | 863 | u_char state, *ptr = NULL, *firm = NULL, status[6]; | |
864 | int block_size, block = 0, err, i; | 864 | int block_size, block = 0, err, i; | |
865 | size_t bytes_left = 0; | 865 | size_t bytes_left = 0; | |
866 | 866 | |||
867 | /* | 867 | /* | |
868 | * Uploading firmware is done with the DFU (Device Firmware Upgrade) | 868 | * Uploading firmware is done with the DFU (Device Firmware Upgrade) | |
869 | * interface. See "Universal Serial Bus - Device Class Specification | 869 | * interface. See "Universal Serial Bus - Device Class Specification | |
870 | * for Device Firmware Upgrade" pdf for details of the protocol. | 870 | * for Device Firmware Upgrade" pdf for details of the protocol. | |
871 | * Maybe this could be moved to a separate 'firmware driver' once more | 871 | * Maybe this could be moved to a separate 'firmware driver' once more | |
872 | * device drivers need it... For now we'll just do it here. | 872 | * device drivers need it... For now we'll just do it here. | |
873 | * | 873 | * | |
874 | * Just for your information, the Atmel's DFU descriptor looks like | 874 | * Just for your information, the Atmel's DFU descriptor looks like | |
875 | * this: | 875 | * this: | |
876 | * | 876 | * | |
877 | * 07 size | 877 | * 07 size | |
878 | * 21 type | 878 | * 21 type | |
879 | * 01 capabilities : only firmware download, need reset | 879 | * 01 capabilities : only firmware download, need reset | |
880 | * after download | 880 | * after download | |
881 | * 13 05 detach timeout : max 1299ms between DFU_DETACH and | 881 | * 13 05 detach timeout : max 1299ms between DFU_DETACH and | |
882 | * reset | 882 | * reset | |
883 | * 00 04 max bytes of firmware per transaction : 1024 | 883 | * 00 04 max bytes of firmware per transaction : 1024 | |
884 | */ | 884 | */ | |
885 | 885 | |||
886 | /* Choose the right firmware for the device */ | 886 | /* Choose the right firmware for the device */ | |
887 | for (i = 0; i < __arraycount(atu_radfirm); i++) | 887 | for (i = 0; i < __arraycount(atu_radfirm); i++) | |
888 | if (sc->atu_radio == atu_radfirm[i].atur_type) { | 888 | if (sc->atu_radio == atu_radfirm[i].atur_type) { | |
889 | firm = atu_radfirm[i].atur_internal; | 889 | firm = atu_radfirm[i].atur_internal; | |
890 | bytes_left = atu_radfirm[i].atur_internal_sz; | 890 | bytes_left = atu_radfirm[i].atur_internal_sz; | |
891 | } | 891 | } | |
892 | 892 | |||
893 | if (firm == NULL) { | 893 | if (firm == NULL) { | |
894 | aprint_error_dev(arg, "no firmware found\n"); | 894 | aprint_error_dev(arg, "no firmware found\n"); | |
895 | return; | 895 | return; | |
896 | } | 896 | } | |
897 | 897 | |||
898 | ptr = firm; | 898 | ptr = firm; | |
899 | state = atu_get_dfu_state(sc); | 899 | state = atu_get_dfu_state(sc); | |
900 | 900 | |||
901 | while (block >= 0 && state > 0) { | 901 | while (block >= 0 && state > 0) { | |
902 | switch (state) { | 902 | switch (state) { | |
903 | case DFUState_DnLoadSync: | 903 | case DFUState_DnLoadSync: | |
904 | /* get DFU status */ | 904 | /* get DFU status */ | |
905 | err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0 , 6, | 905 | err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0 , 6, | |
906 | status); | 906 | status); | |
907 | if (err) { | 907 | if (err) { | |
908 | DPRINTF(("%s: dfu_getstatus failed!\n", | 908 | DPRINTF(("%s: dfu_getstatus failed!\n", | |
909 | device_xname(sc->atu_dev))); | 909 | device_xname(sc->atu_dev))); | |
910 | return; | 910 | return; | |
911 | } | 911 | } | |
912 | /* success means state => DnLoadIdle */ | 912 | /* success means state => DnLoadIdle */ | |
913 | state = DFUState_DnLoadIdle; | 913 | state = DFUState_DnLoadIdle; | |
914 | continue; | 914 | continue; | |
915 | break; | 915 | break; | |
916 | 916 | |||
917 | case DFUState_DFUIdle: | 917 | case DFUState_DFUIdle: | |
918 | case DFUState_DnLoadIdle: | 918 | case DFUState_DnLoadIdle: | |
919 | if (bytes_left>=DFU_MaxBlockSize) | 919 | if (bytes_left>=DFU_MaxBlockSize) | |
920 | block_size = DFU_MaxBlockSize; | 920 | block_size = DFU_MaxBlockSize; | |
921 | else | 921 | else | |
922 | block_size = bytes_left; | 922 | block_size = bytes_left; | |
923 | DPRINTFN(15, ("%s: firmware block %d\n", | 923 | DPRINTFN(15, ("%s: firmware block %d\n", | |
924 | device_xname(sc->atu_dev), block)); | 924 | device_xname(sc->atu_dev), block)); | |
925 | 925 | |||
926 | err = atu_usb_request(sc, DFU_DNLOAD, block++, 0, | 926 | err = atu_usb_request(sc, DFU_DNLOAD, block++, 0, | |
927 | block_size, ptr); | 927 | block_size, ptr); | |
928 | if (err) { | 928 | if (err) { | |
929 | DPRINTF(("%s: dfu_dnload failed\n", | 929 | DPRINTF(("%s: dfu_dnload failed\n", | |
930 | device_xname(sc->atu_dev))); | 930 | device_xname(sc->atu_dev))); | |
931 | return; | 931 | return; | |
932 | } | 932 | } | |
933 | 933 | |||
934 | ptr += block_size; | 934 | ptr += block_size; | |
935 | bytes_left -= block_size; | 935 | bytes_left -= block_size; | |
936 | if (block_size == 0) | 936 | if (block_size == 0) | |
937 | block = -1; | 937 | block = -1; | |
938 | break; | 938 | break; | |
939 | 939 | |||
940 | default: | 940 | default: | |
941 | usbd_delay_ms(sc->atu_udev, 100); | 941 | usbd_delay_ms(sc->atu_udev, 100); | |
942 | DPRINTFN(20, ("%s: sleeping for a while\n", | 942 | DPRINTFN(20, ("%s: sleeping for a while\n", | |
943 | device_xname(sc->atu_dev))); | 943 | device_xname(sc->atu_dev))); | |
944 | break; | 944 | break; | |
945 | } | 945 | } | |
946 | 946 | |||
947 | state = atu_get_dfu_state(sc); | 947 | state = atu_get_dfu_state(sc); | |
948 | } | 948 | } | |
949 | 949 | |||
950 | if (state != DFUState_ManifestSync) { | 950 | if (state != DFUState_ManifestSync) { | |
951 | DPRINTF(("%s: state != manifestsync... eek!\n", | 951 | DPRINTF(("%s: state != manifestsync... eek!\n", | |
952 | device_xname(sc->atu_dev))); | 952 | device_xname(sc->atu_dev))); | |
953 | } | 953 | } | |
954 | 954 | |||
955 | err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0, 6, status); | 955 | err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0, 6, status); | |
956 | if (err) { | 956 | if (err) { | |
957 | DPRINTF(("%s: dfu_getstatus failed!\n", | 957 | DPRINTF(("%s: dfu_getstatus failed!\n", | |
958 | device_xname(sc->atu_dev))); | 958 | device_xname(sc->atu_dev))); | |
959 | return; | 959 | return; | |
960 | } | 960 | } | |
961 | 961 | |||
962 | DPRINTFN(15, ("%s: sending remap\n", device_xname(sc->atu_dev))); | 962 | DPRINTFN(15, ("%s: sending remap\n", device_xname(sc->atu_dev))); | |
963 | err = atu_usb_request(sc, DFU_REMAP, 0, 0, 0, NULL); | 963 | err = atu_usb_request(sc, DFU_REMAP, 0, 0, 0, NULL); | |
964 | if ((err) && !(sc->atu_quirk & ATU_QUIRK_NO_REMAP)) { | 964 | if ((err) && !(sc->atu_quirk & ATU_QUIRK_NO_REMAP)) { | |
965 | DPRINTF(("%s: remap failed!\n", device_xname(sc->atu_dev))); | 965 | DPRINTF(("%s: remap failed!\n", device_xname(sc->atu_dev))); | |
966 | return; | 966 | return; | |
967 | } | 967 | } | |
968 | 968 | |||
969 | /* after a lot of trying and measuring I found out the device needs | 969 | /* after a lot of trying and measuring I found out the device needs | |
970 | * about 56 miliseconds after sending the remap command before | 970 | * about 56 miliseconds after sending the remap command before | |
971 | * it's ready to communicate again. So we'll wait just a little bit | 971 | * it's ready to communicate again. So we'll wait just a little bit | |
972 | * longer than that to be sure... | 972 | * longer than that to be sure... | |
973 | */ | 973 | */ | |
974 | usbd_delay_ms(sc->atu_udev, 56+100); | 974 | usbd_delay_ms(sc->atu_udev, 56+100); | |
975 | 975 | |||
976 | aprint_error_dev(arg, "reattaching after firmware upload\n"); | 976 | aprint_error_dev(arg, "reattaching after firmware upload\n"); | |
977 | usb_needs_reattach(sc->atu_udev); | 977 | usb_needs_reattach(sc->atu_udev); | |
978 | } | 978 | } | |
979 | 979 | |||
980 | static void | 980 | static void | |
981 | atu_external_firmware(device_t arg) | 981 | atu_external_firmware(device_t arg) | |
982 | { | 982 | { | |
983 | struct atu_softc *sc = device_private(arg); | 983 | struct atu_softc *sc = device_private(arg); | |
984 | u_char *ptr = NULL, *firm = NULL; | 984 | u_char *ptr = NULL, *firm = NULL; | |
985 | int block_size, block = 0, err, i; | 985 | int block_size, block = 0, err, i; | |
986 | size_t bytes_left = 0; | 986 | size_t bytes_left = 0; | |
987 | 987 | |||
988 | for (i = 0; i < __arraycount(atu_radfirm); i++) | 988 | for (i = 0; i < __arraycount(atu_radfirm); i++) | |
989 | if (sc->atu_radio == atu_radfirm[i].atur_type) { | 989 | if (sc->atu_radio == atu_radfirm[i].atur_type) { | |
990 | firm = atu_radfirm[i].atur_external; | 990 | firm = atu_radfirm[i].atur_external; | |
991 | bytes_left = atu_radfirm[i].atur_external_sz; | 991 | bytes_left = atu_radfirm[i].atur_external_sz; | |
992 | } | 992 | } | |
993 | 993 | |||
994 | if (firm == NULL) { | 994 | if (firm == NULL) { | |
995 | aprint_error_dev(arg, "no firmware found\n"); | 995 | aprint_error_dev(arg, "no firmware found\n"); | |
996 | return; | 996 | return; | |
997 | } | 997 | } | |
998 | ptr = firm; | 998 | ptr = firm; | |
999 | 999 | |||
1000 | while (bytes_left) { | 1000 | while (bytes_left) { | |
1001 | if (bytes_left > 1024) | 1001 | if (bytes_left > 1024) | |
1002 | block_size = 1024; | 1002 | block_size = 1024; | |
1003 | else | 1003 | else | |
1004 | block_size = bytes_left; | 1004 | block_size = bytes_left; | |
1005 | 1005 | |||
1006 | DPRINTFN(15, ("%s: block:%d size:%d\n", | 1006 | DPRINTFN(15, ("%s: block:%d size:%d\n", | |
1007 | device_xname(sc->atu_dev), block, block_size)); | 1007 | device_xname(sc->atu_dev), block, block_size)); | |
1008 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, | 1008 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, | |
1009 | 0x0802, block, block_size, ptr); | 1009 | 0x0802, block, block_size, ptr); | |
1010 | if (err) { | 1010 | if (err) { | |
1011 | DPRINTF(("%s: could not load external firmware " | 1011 | DPRINTF(("%s: could not load external firmware " | |
1012 | "block\n", device_xname(sc->atu_dev))); | 1012 | "block\n", device_xname(sc->atu_dev))); | |
1013 | return; | 1013 | return; | |
1014 | } | 1014 | } | |
1015 | 1015 | |||
1016 | ptr += block_size; | 1016 | ptr += block_size; | |
1017 | block++; | 1017 | block++; | |
1018 | bytes_left -= block_size; | 1018 | bytes_left -= block_size; | |
1019 | } | 1019 | } | |
1020 | 1020 | |||
1021 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0802, | 1021 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0802, | |
1022 | block, 0, NULL); | 1022 | block, 0, NULL); | |
1023 | if (err) { | 1023 | if (err) { | |
1024 | DPRINTF(("%s: could not load last zero-length firmware " | 1024 | DPRINTF(("%s: could not load last zero-length firmware " | |
1025 | "block\n", device_xname(sc->atu_dev))); | 1025 | "block\n", device_xname(sc->atu_dev))); | |
1026 | return; | 1026 | return; | |
1027 | } | 1027 | } | |
1028 | 1028 | |||
1029 | /* | 1029 | /* | |
1030 | * The SMC2662w V.4 seems to require some time to do its thing with | 1030 | * The SMC2662w V.4 seems to require some time to do its thing with | |
1031 | * the external firmware... 20 ms isn't enough, but 21 ms works 100 | 1031 | * the external firmware... 20 ms isn't enough, but 21 ms works 100 | |
1032 | * times out of 100 tries. We'll wait a bit longer just to be sure | 1032 | * times out of 100 tries. We'll wait a bit longer just to be sure | |
1033 | */ | 1033 | */ | |
1034 | if (sc->atu_quirk & ATU_QUIRK_FW_DELAY) | 1034 | if (sc->atu_quirk & ATU_QUIRK_FW_DELAY) | |
1035 | usbd_delay_ms(sc->atu_udev, 21 + 100); | 1035 | usbd_delay_ms(sc->atu_udev, 21 + 100); | |
1036 | 1036 | |||
1037 | DPRINTFN(10, ("%s: external firmware upload done\n", | 1037 | DPRINTFN(10, ("%s: external firmware upload done\n", | |
1038 | device_xname(sc->atu_dev))); | 1038 | device_xname(sc->atu_dev))); | |
1039 | /* complete configuration after the firmwares have been uploaded */ | 1039 | /* complete configuration after the firmwares have been uploaded */ | |
1040 | atu_complete_attach(sc); | 1040 | atu_complete_attach(sc); | |
1041 | } | 1041 | } | |
1042 | 1042 | |||
1043 | static int | 1043 | static int | |
1044 | atu_get_card_config(struct atu_softc *sc) | 1044 | atu_get_card_config(struct atu_softc *sc) | |
1045 | { | 1045 | { | |
1046 | struct ieee80211com *ic = &sc->sc_ic; | 1046 | struct ieee80211com *ic = &sc->sc_ic; | |
1047 | struct atu_rfmd_conf rfmd_conf; | 1047 | struct atu_rfmd_conf rfmd_conf; | |
1048 | struct atu_intersil_conf intersil_conf; | 1048 | struct atu_intersil_conf intersil_conf; | |
1049 | int err; | 1049 | int err; | |
1050 | 1050 | |||
@@ -1239,1043 +1239,1035 @@ atu_attach(device_t parent, device_t sel | @@ -1239,1043 +1239,1035 @@ atu_attach(device_t parent, device_t sel | |||
1239 | usbd_status err; | 1239 | usbd_status err; | |
1240 | struct usbd_device *dev = uaa->uaa_device; | 1240 | struct usbd_device *dev = uaa->uaa_device; | |
1241 | uint8_t mode, channel; | 1241 | uint8_t mode, channel; | |
1242 | int i; | 1242 | int i; | |
1243 | 1243 | |||
1244 | sc->atu_dev = self; | 1244 | sc->atu_dev = self; | |
1245 | sc->sc_state = ATU_S_UNCONFIG; | 1245 | sc->sc_state = ATU_S_UNCONFIG; | |
1246 | 1246 | |||
1247 | aprint_naive("\n"); | 1247 | aprint_naive("\n"); | |
1248 | aprint_normal("\n"); | 1248 | aprint_normal("\n"); | |
1249 | 1249 | |||
1250 | devinfop = usbd_devinfo_alloc(dev, 0); | 1250 | devinfop = usbd_devinfo_alloc(dev, 0); | |
1251 | aprint_normal_dev(self, "%s\n", devinfop); | 1251 | aprint_normal_dev(self, "%s\n", devinfop); | |
1252 | usbd_devinfo_free(devinfop); | 1252 | usbd_devinfo_free(devinfop); | |
1253 | 1253 | |||
1254 | err = usbd_set_config_no(dev, ATU_CONFIG_NO, 1); | 1254 | err = usbd_set_config_no(dev, ATU_CONFIG_NO, 1); | |
1255 | if (err) { | 1255 | if (err) { | |
1256 | aprint_error_dev(self, "failed to set configuration" | 1256 | aprint_error_dev(self, "failed to set configuration" | |
1257 | ", err=%s\n", usbd_errstr(err)); | 1257 | ", err=%s\n", usbd_errstr(err)); | |
1258 | return; | 1258 | return; | |
1259 | } | 1259 | } | |
1260 | 1260 | |||
1261 | err = usbd_device2interface_handle(dev, ATU_IFACE_IDX, &sc->atu_iface); | 1261 | err = usbd_device2interface_handle(dev, ATU_IFACE_IDX, &sc->atu_iface); | |
1262 | if (err) { | 1262 | if (err) { | |
1263 | aprint_error_dev(self, "getting interface handle failed\n"); | 1263 | aprint_error_dev(self, "getting interface handle failed\n"); | |
1264 | return; | 1264 | return; | |
1265 | } | 1265 | } | |
1266 | 1266 | |||
1267 | sc->atu_unit = device_unit(self); | 1267 | sc->atu_unit = device_unit(self); | |
1268 | sc->atu_udev = dev; | 1268 | sc->atu_udev = dev; | |
1269 | 1269 | |||
1270 | /* | 1270 | /* | |
1271 | * look up the radio_type for the device | 1271 | * look up the radio_type for the device | |
1272 | * basically does the same as atu_match | 1272 | * basically does the same as atu_match | |
1273 | */ | 1273 | */ | |
1274 | for (i = 0; i < __arraycount(atu_devs); i++) { | 1274 | for (i = 0; i < __arraycount(atu_devs); i++) { | |
1275 | const struct atu_type *t = &atu_devs[i]; | 1275 | const struct atu_type *t = &atu_devs[i]; | |
1276 | 1276 | |||
1277 | if (uaa->uaa_vendor == t->atu_vid && | 1277 | if (uaa->uaa_vendor == t->atu_vid && | |
1278 | uaa->uaa_product == t->atu_pid) { | 1278 | uaa->uaa_product == t->atu_pid) { | |
1279 | sc->atu_radio = t->atu_radio; | 1279 | sc->atu_radio = t->atu_radio; | |
1280 | sc->atu_quirk = t->atu_quirk; | 1280 | sc->atu_quirk = t->atu_quirk; | |
1281 | } | 1281 | } | |
1282 | } | 1282 | } | |
1283 | 1283 | |||
1284 | /* | 1284 | /* | |
1285 | * Check in the interface descriptor if we're in DFU mode | 1285 | * Check in the interface descriptor if we're in DFU mode | |
1286 | * If we're in DFU mode, we upload the external firmware | 1286 | * If we're in DFU mode, we upload the external firmware | |
1287 | * If we're not, the PC must have rebooted without power-cycling | 1287 | * If we're not, the PC must have rebooted without power-cycling | |
1288 | * the device.. I've tried this out, a reboot only requeres the | 1288 | * the device.. I've tried this out, a reboot only requeres the | |
1289 | * external firmware to be reloaded :) | 1289 | * external firmware to be reloaded :) | |
1290 | * | 1290 | * | |
1291 | * Hmm. The at76c505a doesn't report a DFU descriptor when it's | 1291 | * Hmm. The at76c505a doesn't report a DFU descriptor when it's | |
1292 | * in DFU mode... Let's just try to get the opmode | 1292 | * in DFU mode... Let's just try to get the opmode | |
1293 | */ | 1293 | */ | |
1294 | err = atu_get_opmode(sc, &mode); | 1294 | err = atu_get_opmode(sc, &mode); | |
1295 | DPRINTFN(20, ("%s: opmode: %d\n", device_xname(sc->atu_dev), mode)); | 1295 | DPRINTFN(20, ("%s: opmode: %d\n", device_xname(sc->atu_dev), mode)); | |
1296 | if (err || (mode != MODE_NETCARD && mode != MODE_NOFLASHNETCARD)) { | 1296 | if (err || (mode != MODE_NETCARD && mode != MODE_NOFLASHNETCARD)) { | |
1297 | DPRINTF(("%s: starting internal firmware download\n", | 1297 | DPRINTF(("%s: starting internal firmware download\n", | |
1298 | device_xname(sc->atu_dev))); | 1298 | device_xname(sc->atu_dev))); | |
1299 | 1299 | |||
1300 | atu_internal_firmware(sc->atu_dev); | 1300 | atu_internal_firmware(sc->atu_dev); | |
1301 | /* | 1301 | /* | |
1302 | * atu_internal_firmware will cause a reset of the device | 1302 | * atu_internal_firmware will cause a reset of the device | |
1303 | * so we don't want to do any more configuration after this | 1303 | * so we don't want to do any more configuration after this | |
1304 | * point. | 1304 | * point. | |
1305 | */ | 1305 | */ | |
1306 | return; | 1306 | return; | |
1307 | } | 1307 | } | |
1308 | 1308 | |||
1309 | if (mode != MODE_NETCARD) { | 1309 | if (mode != MODE_NETCARD) { | |
1310 | DPRINTFN(15, ("%s: device needs external firmware\n", | 1310 | DPRINTFN(15, ("%s: device needs external firmware\n", | |
1311 | device_xname(sc->atu_dev))); | 1311 | device_xname(sc->atu_dev))); | |
1312 | 1312 | |||
1313 | if (mode != MODE_NOFLASHNETCARD) { | 1313 | if (mode != MODE_NOFLASHNETCARD) { | |
1314 | DPRINTF(("%s: unexpected opmode=%d\n", | 1314 | DPRINTF(("%s: unexpected opmode=%d\n", | |
1315 | device_xname(sc->atu_dev), mode)); | 1315 | device_xname(sc->atu_dev), mode)); | |
1316 | } | 1316 | } | |
1317 | 1317 | |||
1318 | /* | 1318 | /* | |
1319 | * There is no difference in opmode before and after external | 1319 | * There is no difference in opmode before and after external | |
1320 | * firmware upload with the SMC2662 V.4 . So instead we'll try | 1320 | * firmware upload with the SMC2662 V.4 . So instead we'll try | |
1321 | * to read the channel number. If we succeed, external | 1321 | * to read the channel number. If we succeed, external | |
1322 | * firmwaremust have been already uploaded... | 1322 | * firmwaremust have been already uploaded... | |
1323 | */ | 1323 | */ | |
1324 | if (sc->atu_radio != RadioIntersil) { | 1324 | if (sc->atu_radio != RadioIntersil) { | |
1325 | err = atu_get_mib(sc, MIB_PHY__CHANNEL, &channel); | 1325 | err = atu_get_mib(sc, MIB_PHY__CHANNEL, &channel); | |
1326 | if (!err) { | 1326 | if (!err) { | |
1327 | DPRINTF(("%s: external firmware has already" | 1327 | DPRINTF(("%s: external firmware has already" | |
1328 | " been downloaded\n", | 1328 | " been downloaded\n", | |
1329 | device_xname(sc->atu_dev))); | 1329 | device_xname(sc->atu_dev))); | |
1330 | atu_complete_attach(sc); | 1330 | atu_complete_attach(sc); | |
1331 | return; | 1331 | return; | |
1332 | } | 1332 | } | |
1333 | } | 1333 | } | |
1334 | 1334 | |||
1335 | atu_external_firmware(sc->atu_dev); | 1335 | atu_external_firmware(sc->atu_dev); | |
1336 | 1336 | |||
1337 | /* | 1337 | /* | |
1338 | * atu_external_firmware will call atu_complete_attach after | 1338 | * atu_external_firmware will call atu_complete_attach after | |
1339 | * it's finished so we can just return. | 1339 | * it's finished so we can just return. | |
1340 | */ | 1340 | */ | |
1341 | } else { | 1341 | } else { | |
1342 | /* all the firmwares are in place, so complete the attach */ | 1342 | /* all the firmwares are in place, so complete the attach */ | |
1343 | atu_complete_attach(sc); | 1343 | atu_complete_attach(sc); | |
1344 | } | 1344 | } | |
1345 | 1345 | |||
1346 | return; | 1346 | return; | |
1347 | } | 1347 | } | |
1348 | 1348 | |||
1349 | static void | 1349 | static void | |
1350 | atu_complete_attach(struct atu_softc *sc) | 1350 | atu_complete_attach(struct atu_softc *sc) | |
1351 | { | 1351 | { | |
1352 | struct ieee80211com *ic = &sc->sc_ic; | 1352 | struct ieee80211com *ic = &sc->sc_ic; | |
1353 | struct ifnet *ifp = &sc->sc_if; | 1353 | struct ifnet *ifp = &sc->sc_if; | |
1354 | usb_interface_descriptor_t *id; | 1354 | usb_interface_descriptor_t *id; | |
1355 | usb_endpoint_descriptor_t *ed; | 1355 | usb_endpoint_descriptor_t *ed; | |
1356 | usbd_status err; | 1356 | usbd_status err; | |
1357 | int i; | 1357 | int i; | |
1358 | #ifdef ATU_DEBUG | 1358 | #ifdef ATU_DEBUG | |
1359 | struct atu_fw fw; | 1359 | struct atu_fw fw; | |
1360 | #endif | 1360 | #endif | |
1361 | 1361 | |||
1362 | id = usbd_get_interface_descriptor(sc->atu_iface); | 1362 | id = usbd_get_interface_descriptor(sc->atu_iface); | |
1363 | 1363 | |||
1364 | /* Find endpoints. */ | 1364 | /* Find endpoints. */ | |
1365 | for (i = 0; i < id->bNumEndpoints; i++) { | 1365 | for (i = 0; i < id->bNumEndpoints; i++) { | |
1366 | ed = usbd_interface2endpoint_descriptor(sc->atu_iface, i); | 1366 | ed = usbd_interface2endpoint_descriptor(sc->atu_iface, i); | |
1367 | if (!ed) { | 1367 | if (!ed) { | |
1368 | DPRINTF(("%s: num_endp:%d\n", device_xname(sc->atu_dev), | 1368 | DPRINTF(("%s: num_endp:%d\n", device_xname(sc->atu_dev), | |
1369 | sc->atu_iface->ui_idesc->bNumEndpoints)); | 1369 | sc->atu_iface->ui_idesc->bNumEndpoints)); | |
1370 | DPRINTF(("%s: couldn't get ep %d\n", | 1370 | DPRINTF(("%s: couldn't get ep %d\n", | |
1371 | device_xname(sc->atu_dev), i)); | 1371 | device_xname(sc->atu_dev), i)); | |
1372 | return; | 1372 | return; | |
1373 | } | 1373 | } | |
1374 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 1374 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
1375 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 1375 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
1376 | sc->atu_ed[ATU_ENDPT_RX] = ed->bEndpointAddress; | 1376 | sc->atu_ed[ATU_ENDPT_RX] = ed->bEndpointAddress; | |
1377 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 1377 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
1378 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 1378 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
1379 | sc->atu_ed[ATU_ENDPT_TX] = ed->bEndpointAddress; | 1379 | sc->atu_ed[ATU_ENDPT_TX] = ed->bEndpointAddress; | |
1380 | } | 1380 | } | |
1381 | } | 1381 | } | |
1382 | 1382 | |||
1383 | /* read device config & get MAC address */ | 1383 | /* read device config & get MAC address */ | |
1384 | err = atu_get_card_config(sc); | 1384 | err = atu_get_card_config(sc); | |
1385 | if (err) { | 1385 | if (err) { | |
1386 | aprint_error("\n%s: could not get card cfg!\n", | 1386 | aprint_error("\n%s: could not get card cfg!\n", | |
1387 | device_xname(sc->atu_dev)); | 1387 | device_xname(sc->atu_dev)); | |
1388 | return; | 1388 | return; | |
1389 | } | 1389 | } | |
1390 | 1390 | |||
1391 | #ifdef ATU_DEBUG | 1391 | #ifdef ATU_DEBUG | |
1392 | /* DEBUG : try to get firmware version */ | 1392 | /* DEBUG : try to get firmware version */ | |
1393 | err = atu_get_mib(sc, MIB_FW_VERSION, sizeof(fw), 0, (uint8_t *)&fw); | 1393 | err = atu_get_mib(sc, MIB_FW_VERSION, sizeof(fw), 0, (uint8_t *)&fw); | |
1394 | if (!err) { | 1394 | if (!err) { | |
1395 | DPRINTFN(15, ("%s: firmware: maj:%d min:%d patch:%d " | 1395 | DPRINTFN(15, ("%s: firmware: maj:%d min:%d patch:%d " | |
1396 | "build:%d\n", device_xname(sc->atu_dev), fw.major, | 1396 | "build:%d\n", device_xname(sc->atu_dev), fw.major, | |
1397 | fw.minor, fw.patch, fw.build)); | 1397 | fw.minor, fw.patch, fw.build)); | |
1398 | } else { | 1398 | } else { | |
1399 | DPRINTF(("%s: get firmware version failed\n", | 1399 | DPRINTF(("%s: get firmware version failed\n", | |
1400 | device_xname(sc->atu_dev))); | 1400 | device_xname(sc->atu_dev))); | |
1401 | } | 1401 | } | |
1402 | #endif /* ATU_DEBUG */ | 1402 | #endif /* ATU_DEBUG */ | |
1403 | 1403 | |||
1404 | /* Show the world our MAC address */ | 1404 | /* Show the world our MAC address */ | |
1405 | aprint_normal_dev(sc->atu_dev, "MAC address %s\n", | 1405 | aprint_normal_dev(sc->atu_dev, "MAC address %s\n", | |
1406 | ether_sprintf(ic->ic_myaddr)); | 1406 | ether_sprintf(ic->ic_myaddr)); | |
1407 | 1407 | |||
1408 | sc->atu_cdata.atu_tx_inuse = 0; | 1408 | sc->atu_cdata.atu_tx_inuse = 0; | |
1409 | sc->atu_encrypt = ATU_WEP_OFF; | 1409 | sc->atu_encrypt = ATU_WEP_OFF; | |
1410 | sc->atu_wepkeylen = ATU_WEP_104BITS; | 1410 | sc->atu_wepkeylen = ATU_WEP_104BITS; | |
1411 | sc->atu_wepkey = 0; | 1411 | sc->atu_wepkey = 0; | |
1412 | 1412 | |||
1413 | memset(sc->atu_bssid, 0, ETHER_ADDR_LEN); | 1413 | memset(sc->atu_bssid, 0, ETHER_ADDR_LEN); | |
1414 | sc->atu_channel = ATU_DEFAULT_CHANNEL; | 1414 | sc->atu_channel = ATU_DEFAULT_CHANNEL; | |
1415 | sc->atu_desired_channel = IEEE80211_CHAN_ANY; | 1415 | sc->atu_desired_channel = IEEE80211_CHAN_ANY; | |
1416 | sc->atu_mode = INFRASTRUCTURE_MODE; | 1416 | sc->atu_mode = INFRASTRUCTURE_MODE; | |
1417 | 1417 | |||
1418 | ic->ic_ifp = ifp; | 1418 | ic->ic_ifp = ifp; | |
1419 | ic->ic_phytype = IEEE80211_T_DS; | 1419 | ic->ic_phytype = IEEE80211_T_DS; | |
1420 | ic->ic_opmode = IEEE80211_M_STA; | 1420 | ic->ic_opmode = IEEE80211_M_STA; | |
1421 | ic->ic_state = IEEE80211_S_INIT; | 1421 | ic->ic_state = IEEE80211_S_INIT; | |
1422 | #ifdef FIXME | 1422 | #ifdef FIXME | |
1423 | ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_WEP | IEEE80211_C_SCANALL; | 1423 | ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_WEP | IEEE80211_C_SCANALL; | |
1424 | #else | 1424 | #else | |
1425 | ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_WEP; | 1425 | ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_WEP; | |
1426 | #endif | 1426 | #endif | |
1427 | 1427 | |||
1428 | i = 0; | 1428 | i = 0; | |
1429 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; | 1429 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; | |
1430 | 1430 | |||
1431 | for (i = 1; i <= 14; i++) { | 1431 | for (i = 1; i <= 14; i++) { | |
1432 | ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B | | 1432 | ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B | | |
1433 | IEEE80211_CHAN_PASSIVE; | 1433 | IEEE80211_CHAN_PASSIVE; | |
1434 | ic->ic_channels[i].ic_freq = ieee80211_ieee2mhz(i, | 1434 | ic->ic_channels[i].ic_freq = ieee80211_ieee2mhz(i, | |
1435 | ic->ic_channels[i].ic_flags); | 1435 | ic->ic_channels[i].ic_flags); | |
1436 | } | 1436 | } | |
1437 | 1437 | |||
1438 | ic->ic_ibss_chan = &ic->ic_channels[0]; | 1438 | ic->ic_ibss_chan = &ic->ic_channels[0]; | |
1439 | 1439 | |||
1440 | ifp->if_softc = sc; | 1440 | ifp->if_softc = sc; | |
1441 | memcpy(ifp->if_xname, device_xname(sc->atu_dev), IFNAMSIZ); | 1441 | memcpy(ifp->if_xname, device_xname(sc->atu_dev), IFNAMSIZ); | |
1442 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | 1442 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |
1443 | ifp->if_init = atu_init; | 1443 | ifp->if_init = atu_init; | |
1444 | ifp->if_stop = atu_stop; | 1444 | ifp->if_stop = atu_stop; | |
1445 | ifp->if_start = atu_start; | 1445 | ifp->if_start = atu_start; | |
1446 | ifp->if_ioctl = atu_ioctl; | 1446 | ifp->if_ioctl = atu_ioctl; | |
1447 | ifp->if_watchdog = atu_watchdog; | 1447 | ifp->if_watchdog = atu_watchdog; | |
1448 | ifp->if_mtu = ATU_DEFAULT_MTU; | 1448 | ifp->if_mtu = ATU_DEFAULT_MTU; | |
1449 | IFQ_SET_READY(&ifp->if_snd); | 1449 | IFQ_SET_READY(&ifp->if_snd); | |
1450 | 1450 | |||
1451 | /* Call MI attach routine. */ | 1451 | /* Call MI attach routine. */ | |
1452 | if_attach(ifp); | 1452 | if_attach(ifp); | |
1453 | ieee80211_ifattach(ic); | 1453 | ieee80211_ifattach(ic); | |
1454 | 1454 | |||
1455 | sc->sc_newstate = ic->ic_newstate; | 1455 | sc->sc_newstate = ic->ic_newstate; | |
1456 | ic->ic_newstate = atu_newstate; | 1456 | ic->ic_newstate = atu_newstate; | |
1457 | 1457 | |||
1458 | /* setup ifmedia interface */ | 1458 | /* setup ifmedia interface */ | |
1459 | /* XXX media locking needs revisiting */ | 1459 | /* XXX media locking needs revisiting */ | |
1460 | mutex_init(&sc->sc_media_mtx, MUTEX_DEFAULT, IPL_SOFTUSB); | 1460 | mutex_init(&sc->sc_media_mtx, MUTEX_DEFAULT, IPL_SOFTUSB); | |
1461 | ieee80211_media_init_with_lock(ic, | 1461 | ieee80211_media_init_with_lock(ic, | |
1462 | atu_media_change, atu_media_status, &sc->sc_media_mtx); | 1462 | atu_media_change, atu_media_status, &sc->sc_media_mtx); | |
1463 | 1463 | |||
1464 | usb_init_task(&sc->sc_task, atu_task, sc, 0); | 1464 | usb_init_task(&sc->sc_task, atu_task, sc, 0); | |
1465 | 1465 | |||
1466 | sc->sc_state = ATU_S_OK; | 1466 | sc->sc_state = ATU_S_OK; | |
1467 | } | 1467 | } | |
1468 | 1468 | |||
1469 | static int | 1469 | static int | |
1470 | atu_detach(device_t self, int flags) | 1470 | atu_detach(device_t self, int flags) | |
1471 | { | 1471 | { | |
1472 | struct atu_softc *sc = device_private(self); | 1472 | struct atu_softc *sc = device_private(self); | |
1473 | struct ifnet *ifp = &sc->sc_if; | 1473 | struct ifnet *ifp = &sc->sc_if; | |
1474 | 1474 | |||
1475 | DPRINTFN(10, ("%s: atu_detach state=%d\n", device_xname(sc->atu_dev), | 1475 | DPRINTFN(10, ("%s: atu_detach state=%d\n", device_xname(sc->atu_dev), | |
1476 | sc->sc_state)); | 1476 | sc->sc_state)); | |
1477 | 1477 | |||
1478 | if (sc->sc_state != ATU_S_UNCONFIG) { | 1478 | if (sc->sc_state != ATU_S_UNCONFIG) { | |
1479 | atu_stop(ifp, 1); | 1479 | atu_stop(ifp, 1); | |
1480 | 1480 | |||
1481 | ieee80211_ifdetach(&sc->sc_ic); | 1481 | ieee80211_ifdetach(&sc->sc_ic); | |
1482 | if_detach(ifp); | 1482 | if_detach(ifp); | |
1483 | } | 1483 | } | |
1484 | 1484 | |||
1485 | return 0; | 1485 | return 0; | |
1486 | } | 1486 | } | |
1487 | 1487 | |||
1488 | static int | 1488 | static int | |
1489 | atu_activate(device_t self, enum devact act) | 1489 | atu_activate(device_t self, enum devact act) | |
1490 | { | 1490 | { | |
1491 | struct atu_softc *sc = device_private(self); | 1491 | struct atu_softc *sc = device_private(self); | |
1492 | 1492 | |||
1493 | switch (act) { | 1493 | switch (act) { | |
1494 | case DVACT_DEACTIVATE: | 1494 | case DVACT_DEACTIVATE: | |
1495 | if (sc->sc_state != ATU_S_UNCONFIG) { | 1495 | if (sc->sc_state != ATU_S_UNCONFIG) { | |
1496 | if_deactivate(&sc->atu_ec.ec_if); | 1496 | if_deactivate(&sc->atu_ec.ec_if); | |
1497 | sc->sc_state = ATU_S_DEAD; | 1497 | sc->sc_state = ATU_S_DEAD; | |
1498 | } | 1498 | } | |
1499 | return 0; | 1499 | return 0; | |
1500 | default: | 1500 | default: | |
1501 | return EOPNOTSUPP; | 1501 | return EOPNOTSUPP; | |
1502 | } | 1502 | } | |
1503 | } | 1503 | } | |
1504 | 1504 | |||
1505 | /* | 1505 | /* | |
1506 | * Initialize an RX descriptor and attach an MBUF cluster. | 1506 | * Initialize an RX descriptor and attach an MBUF cluster. | |
1507 | */ | 1507 | */ | |
1508 | static int | 1508 | static int | |
1509 | atu_newbuf(struct atu_softc *sc, struct atu_chain *c, struct mbuf *m) | 1509 | atu_newbuf(struct atu_softc *sc, struct atu_chain *c, struct mbuf *m) | |
1510 | { | 1510 | { | |
1511 | struct mbuf *m_new = NULL; | 1511 | struct mbuf *m_new = NULL; | |
1512 | 1512 | |||
1513 | if (m == NULL) { | 1513 | if (m == NULL) { | |
1514 | MGETHDR(m_new, M_DONTWAIT, MT_DATA); | 1514 | MGETHDR(m_new, M_DONTWAIT, MT_DATA); | |
1515 | if (m_new == NULL) { | 1515 | if (m_new == NULL) { | |
1516 | DPRINTF(("%s: no memory for rx list\n", | 1516 | DPRINTF(("%s: no memory for rx list\n", | |
1517 | device_xname(sc->atu_dev))); | 1517 | device_xname(sc->atu_dev))); | |
1518 | return ENOBUFS; | 1518 | return ENOBUFS; | |
1519 | } | 1519 | } | |
1520 | 1520 | |||
1521 | MCLGET(m_new, M_DONTWAIT); | 1521 | MCLGET(m_new, M_DONTWAIT); | |
1522 | if (!(m_new->m_flags & M_EXT)) { | 1522 | if (!(m_new->m_flags & M_EXT)) { | |
1523 | DPRINTF(("%s: no memory for rx list\n", | 1523 | DPRINTF(("%s: no memory for rx list\n", | |
1524 | device_xname(sc->atu_dev))); | 1524 | device_xname(sc->atu_dev))); | |
1525 | m_freem(m_new); | 1525 | m_freem(m_new); | |
1526 | return ENOBUFS; | 1526 | return ENOBUFS; | |
1527 | } | 1527 | } | |
1528 | m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; | 1528 | m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; | |
1529 | } else { | 1529 | } else { | |
1530 | m_new = m; | 1530 | m_new = m; | |
1531 | m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; | 1531 | m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; | |
1532 | m_new->m_data = m_new->m_ext.ext_buf; | 1532 | m_new->m_data = m_new->m_ext.ext_buf; | |
1533 | } | 1533 | } | |
1534 | c->atu_mbuf = m_new; | 1534 | c->atu_mbuf = m_new; | |
1535 | return 0; | 1535 | return 0; | |
1536 | } | 1536 | } | |
1537 | 1537 | |||
1538 | static int | 1538 | static int | |
1539 | atu_rx_list_init(struct atu_softc *sc) | 1539 | atu_rx_list_init(struct atu_softc *sc) | |
1540 | { | 1540 | { | |
1541 | struct atu_cdata *cd = &sc->atu_cdata; | 1541 | struct atu_cdata *cd = &sc->atu_cdata; | |
1542 | struct atu_chain *c; | 1542 | struct atu_chain *c; | |
1543 | int i; | 1543 | int i; | |
1544 | 1544 | |||
1545 | DPRINTFN(15, ("%s: atu_rx_list_init: enter\n", | 1545 | DPRINTFN(15, ("%s: atu_rx_list_init: enter\n", | |
1546 | device_xname(sc->atu_dev))); | 1546 | device_xname(sc->atu_dev))); | |
1547 | 1547 | |||
1548 | for (i = 0; i < ATU_RX_LIST_CNT; i++) { | 1548 | for (i = 0; i < ATU_RX_LIST_CNT; i++) { | |
1549 | c = &cd->atu_rx_chain[i]; | 1549 | c = &cd->atu_rx_chain[i]; | |
1550 | c->atu_sc = sc; | 1550 | c->atu_sc = sc; | |
1551 | c->atu_idx = i; | 1551 | c->atu_idx = i; | |
1552 | if (c->atu_xfer == NULL) { | 1552 | if (c->atu_xfer == NULL) { | |
1553 | int err = usbd_create_xfer(sc->atu_ep[ATU_ENDPT_RX], | 1553 | int err = usbd_create_xfer(sc->atu_ep[ATU_ENDPT_RX], | |
1554 | ATU_RX_BUFSZ, 0, 0, &c->atu_xfer); | 1554 | ATU_RX_BUFSZ, 0, 0, &c->atu_xfer); | |
1555 | if (err) | 1555 | if (err) | |
1556 | return err; | 1556 | return err; | |
1557 | c->atu_buf = usbd_get_buffer(c->atu_xfer); | 1557 | c->atu_buf = usbd_get_buffer(c->atu_xfer); | |
1558 | if (atu_newbuf(sc, c, NULL) == ENOBUFS) /* XXX free? */ | 1558 | if (atu_newbuf(sc, c, NULL) == ENOBUFS) /* XXX free? */ | |
1559 | return ENOBUFS; | 1559 | return ENOBUFS; | |
1560 | } | 1560 | } | |
1561 | } | 1561 | } | |
1562 | return 0; | 1562 | return 0; | |
1563 | } | 1563 | } | |
1564 | 1564 | |||
1565 | static int | 1565 | static int | |
1566 | atu_tx_list_init(struct atu_softc *sc) | 1566 | atu_tx_list_init(struct atu_softc *sc) | |
1567 | { | 1567 | { | |
1568 | struct atu_cdata *cd = &sc->atu_cdata; | 1568 | struct atu_cdata *cd = &sc->atu_cdata; | |
1569 | struct atu_chain *c; | 1569 | struct atu_chain *c; | |
1570 | int i; | 1570 | int i; | |
1571 | 1571 | |||
1572 | DPRINTFN(15, ("%s: atu_tx_list_init\n", | 1572 | DPRINTFN(15, ("%s: atu_tx_list_init\n", | |
1573 | device_xname(sc->atu_dev))); | 1573 | device_xname(sc->atu_dev))); | |
1574 | 1574 | |||
1575 | SLIST_INIT(&cd->atu_tx_free); | 1575 | SLIST_INIT(&cd->atu_tx_free); | |
1576 | sc->atu_cdata.atu_tx_inuse = 0; | 1576 | sc->atu_cdata.atu_tx_inuse = 0; | |
1577 | 1577 | |||
1578 | for (i = 0; i < ATU_TX_LIST_CNT; i++) { | 1578 | for (i = 0; i < ATU_TX_LIST_CNT; i++) { | |
1579 | c = &cd->atu_tx_chain[i]; | 1579 | c = &cd->atu_tx_chain[i]; | |
1580 | c->atu_sc = sc; | 1580 | c->atu_sc = sc; | |
1581 | c->atu_idx = i; | 1581 | c->atu_idx = i; | |
1582 | if (c->atu_xfer == NULL) { | 1582 | if (c->atu_xfer == NULL) { | |
1583 | int err = usbd_create_xfer(sc->atu_ep[ATU_ENDPT_TX], | 1583 | int err = usbd_create_xfer(sc->atu_ep[ATU_ENDPT_TX], | |
1584 | ATU_TX_BUFSZ, 0, 0, &c->atu_xfer); | 1584 | ATU_TX_BUFSZ, 0, 0, &c->atu_xfer); | |
1585 | if (err) { | 1585 | if (err) { | |
1586 | return err; | 1586 | return err; | |
1587 | } | 1587 | } | |
1588 | c->atu_buf = usbd_get_buffer(c->atu_xfer); | 1588 | c->atu_buf = usbd_get_buffer(c->atu_xfer); | |
1589 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, atu_list); | 1589 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, atu_list); | |
1590 | } | 1590 | } | |
1591 | } | 1591 | } | |
1592 | return 0; | 1592 | return 0; | |
1593 | } | 1593 | } | |
1594 | 1594 | |||
1595 | static void | 1595 | static void | |
1596 | atu_xfer_list_free(struct atu_softc *sc, struct atu_chain *ch, int listlen) | 1596 | atu_xfer_list_free(struct atu_softc *sc, struct atu_chain *ch, int listlen) | |
1597 | { | 1597 | { | |
1598 | int i; | 1598 | int i; | |
1599 | 1599 | |||
1600 | /* Free resources. */ | 1600 | /* Free resources. */ | |
1601 | for (i = 0; i < listlen; i++) { | 1601 | for (i = 0; i < listlen; i++) { | |
1602 | if (ch[i].atu_buf != NULL) | 1602 | if (ch[i].atu_buf != NULL) | |
1603 | ch[i].atu_buf = NULL; | 1603 | ch[i].atu_buf = NULL; | |
1604 | if (ch[i].atu_mbuf != NULL) { | 1604 | if (ch[i].atu_mbuf != NULL) { | |
1605 | m_freem(ch[i].atu_mbuf); | 1605 | m_freem(ch[i].atu_mbuf); | |
1606 | ch[i].atu_mbuf = NULL; | 1606 | ch[i].atu_mbuf = NULL; | |
1607 | } | 1607 | } | |
1608 | if (ch[i].atu_xfer != NULL) { | 1608 | if (ch[i].atu_xfer != NULL) { | |
1609 | usbd_destroy_xfer(ch[i].atu_xfer); | 1609 | usbd_destroy_xfer(ch[i].atu_xfer); | |
1610 | ch[i].atu_xfer = NULL; | 1610 | ch[i].atu_xfer = NULL; | |
1611 | } | 1611 | } | |
1612 | } | 1612 | } | |
1613 | } | 1613 | } | |
1614 | 1614 | |||
1615 | /* | 1615 | /* | |
1616 | * A frame has been uploaded: pass the resulting mbuf chain up to | 1616 | * A frame has been uploaded: pass the resulting mbuf chain up to | |
1617 | * the higher level protocols. | 1617 | * the higher level protocols. | |
1618 | */ | 1618 | */ | |
1619 | static void | 1619 | static void | |
1620 | atu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | 1620 | atu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | |
1621 | { | 1621 | { | |
1622 | struct atu_chain *c = (struct atu_chain *)priv; | 1622 | struct atu_chain *c = (struct atu_chain *)priv; | |
1623 | struct atu_softc *sc = c->atu_sc; | 1623 | struct atu_softc *sc = c->atu_sc; | |
1624 | struct ieee80211com *ic = &sc->sc_ic; | 1624 | struct ieee80211com *ic = &sc->sc_ic; | |
1625 | struct ifnet *ifp = &sc->sc_if; | 1625 | struct ifnet *ifp = &sc->sc_if; | |
1626 | struct atu_rx_hdr *h; | 1626 | struct atu_rx_hdr *h; | |
1627 | struct ieee80211_frame_min *wh; | 1627 | struct ieee80211_frame_min *wh; | |
1628 | struct ieee80211_node *ni; | 1628 | struct ieee80211_node *ni; | |
1629 | struct mbuf *m; | 1629 | struct mbuf *m; | |
1630 | uint32_t len; | 1630 | uint32_t len; | |
1631 | int s; | 1631 | int s; | |
1632 | 1632 | |||
1633 | DPRINTFN(25, ("%s: atu_rxeof\n", device_xname(sc->atu_dev))); | 1633 | DPRINTFN(25, ("%s: atu_rxeof\n", device_xname(sc->atu_dev))); | |
1634 | 1634 | |||
1635 | if (sc->sc_state != ATU_S_OK) | 1635 | if (sc->sc_state != ATU_S_OK) | |
1636 | return; | 1636 | return; | |
1637 | 1637 | |||
1638 | if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) | 1638 | if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) | |
1639 | goto done; | 1639 | goto done; | |
1640 | 1640 | |||
1641 | if (status != USBD_NORMAL_COMPLETION) { | 1641 | if (status != USBD_NORMAL_COMPLETION) { | |
1642 | DPRINTF(("%s: status != USBD_NORMAL_COMPLETION\n", | 1642 | DPRINTF(("%s: status != USBD_NORMAL_COMPLETION\n", | |
1643 | device_xname(sc->atu_dev))); | 1643 | device_xname(sc->atu_dev))); | |
1644 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { | 1644 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { | |
1645 | return; | 1645 | return; | |
1646 | } | 1646 | } | |
1647 | #if 0 | 1647 | #if 0 | |
1648 | if (status == USBD_IOERROR) { | 1648 | if (status == USBD_IOERROR) { | |
1649 | DPRINTF(("%s: rx: EEK! lost device?\n", | 1649 | DPRINTF(("%s: rx: EEK! lost device?\n", | |
1650 | device_xname(sc->atu_dev))); | 1650 | device_xname(sc->atu_dev))); | |
1651 | 1651 | |||
1652 | /* | 1652 | /* | |
1653 | * My experience with USBD_IOERROR is that trying to | 1653 | * My experience with USBD_IOERROR is that trying to | |
1654 | * restart the transfer will always fail and we'll | 1654 | * restart the transfer will always fail and we'll | |
1655 | * keep on looping restarting transfers untill someone | 1655 | * keep on looping restarting transfers untill someone | |
1656 | * pulls the plug of the device. | 1656 | * pulls the plug of the device. | |
1657 | * So we don't restart the transfer, but just let it | 1657 | * So we don't restart the transfer, but just let it | |
1658 | * die... If someone knows of a situation where we can | 1658 | * die... If someone knows of a situation where we can | |
1659 | * recover from USBD_IOERROR, let me know. | 1659 | * recover from USBD_IOERROR, let me know. | |
1660 | */ | 1660 | */ | |
1661 | splx(s); | 1661 | splx(s); | |
1662 | return; | 1662 | return; | |
1663 | } | 1663 | } | |
1664 | #endif /* 0 */ | 1664 | #endif /* 0 */ | |
1665 | 1665 | |||
1666 | if (usbd_ratecheck(&sc->atu_rx_notice)) { | 1666 | if (usbd_ratecheck(&sc->atu_rx_notice)) { | |
1667 | DPRINTF(("%s: usb error on rx: %s\n", | 1667 | DPRINTF(("%s: usb error on rx: %s\n", | |
1668 | device_xname(sc->atu_dev), usbd_errstr(status))); | 1668 | device_xname(sc->atu_dev), usbd_errstr(status))); | |
1669 | } | 1669 | } | |
1670 | if (status == USBD_STALLED) | 1670 | if (status == USBD_STALLED) | |
1671 | usbd_clear_endpoint_stall_async( | 1671 | usbd_clear_endpoint_stall_async( | |
1672 | sc->atu_ep[ATU_ENDPT_RX]); | 1672 | sc->atu_ep[ATU_ENDPT_RX]); | |
1673 | goto done; | 1673 | goto done; | |
1674 | } | 1674 | } | |
1675 | 1675 | |||
1676 | usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); | 1676 | usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); | |
1677 | 1677 | |||
1678 | if (len <= 1) { | 1678 | if (len <= 1) { | |
1679 | DPRINTF(("%s: atu_rxeof: too short\n", | 1679 | DPRINTF(("%s: atu_rxeof: too short\n", | |
1680 | device_xname(sc->atu_dev))); | 1680 | device_xname(sc->atu_dev))); | |
1681 | goto done; | 1681 | goto done; | |
1682 | } else if (len > MCLBYTES) { | 1682 | } else if (len > MCLBYTES) { | |
1683 | DPRINTF(("%s: atu_rxeof: too long\n", | 1683 | DPRINTF(("%s: atu_rxeof: too long\n", | |
1684 | device_xname(sc->atu_dev))); | 1684 | device_xname(sc->atu_dev))); | |
1685 | goto done; | 1685 | goto done; | |
1686 | } | 1686 | } | |
1687 | 1687 | |||
1688 | h = (struct atu_rx_hdr *)c->atu_buf; | 1688 | h = (struct atu_rx_hdr *)c->atu_buf; | |
1689 | len = UGETW(h->length) - 4; /* XXX magic number */ | 1689 | len = UGETW(h->length) - 4; /* XXX magic number */ | |
1690 | 1690 | |||
1691 | m = c->atu_mbuf; | 1691 | m = c->atu_mbuf; | |
1692 | memcpy(mtod(m, char *), c->atu_buf + ATU_RX_HDRLEN, len); | 1692 | memcpy(mtod(m, char *), c->atu_buf + ATU_RX_HDRLEN, len); | |
1693 | m_set_rcvif(m, ifp); | 1693 | m_set_rcvif(m, ifp); | |
1694 | m->m_pkthdr.len = m->m_len = len; | 1694 | m->m_pkthdr.len = m->m_len = len; | |
1695 | 1695 | |||
1696 | wh = mtod(m, struct ieee80211_frame_min *); | 1696 | wh = mtod(m, struct ieee80211_frame_min *); | |
1697 | ni = ieee80211_find_rxnode(ic, wh); | 1697 | ni = ieee80211_find_rxnode(ic, wh); | |
1698 | 1698 | |||
1699 | if_statinc(ifp, if_ipackets); | 1699 | if_statinc(ifp, if_ipackets); | |
1700 | 1700 | |||
1701 | s = splnet(); | 1701 | s = splnet(); | |
1702 | 1702 | |||
1703 | if (atu_newbuf(sc, c, NULL) == ENOBUFS) { | 1703 | if (atu_newbuf(sc, c, NULL) == ENOBUFS) { | |
1704 | if_statinc(ifp, if_ierrors); | 1704 | if_statinc(ifp, if_ierrors); | |
1705 | goto done1; /* XXX if we can't allocate, why restart it? */ | 1705 | goto done1; /* XXX if we can't allocate, why restart it? */ | |
1706 | } | 1706 | } | |
1707 | 1707 | |||
1708 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { | 1708 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { | |
1709 | /* | 1709 | /* | |
1710 | * WEP is decrypted by hardware. Clear WEP bit | 1710 | * WEP is decrypted by hardware. Clear WEP bit | |
1711 | * header for ieee80211_input(). | 1711 | * header for ieee80211_input(). | |
1712 | */ | 1712 | */ | |
1713 | wh->i_fc[1] &= ~IEEE80211_FC1_WEP; | 1713 | wh->i_fc[1] &= ~IEEE80211_FC1_WEP; | |
1714 | } | 1714 | } | |
1715 | 1715 | |||
1716 | ieee80211_input(ic, m, ni, h->rssi, UGETDW(h->rx_time)); | 1716 | ieee80211_input(ic, m, ni, h->rssi, UGETDW(h->rx_time)); | |
1717 | 1717 | |||
1718 | ieee80211_free_node(ni); | 1718 | ieee80211_free_node(ni); | |
1719 | done1: | 1719 | done1: | |
1720 | splx(s); | 1720 | splx(s); | |
1721 | done: | 1721 | done: | |
1722 | /* Setup new transfer. */ | 1722 | /* Setup new transfer. */ | |
1723 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, ATU_RX_BUFSZ, | 1723 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, ATU_RX_BUFSZ, | |
1724 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atu_rxeof); | 1724 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atu_rxeof); | |
1725 | usbd_transfer(c->atu_xfer); | 1725 | usbd_transfer(c->atu_xfer); | |
1726 | } | 1726 | } | |
1727 | 1727 | |||
1728 | /* | 1728 | /* | |
1729 | * A frame was downloaded to the chip. It's safe for us to clean up | 1729 | * A frame was downloaded to the chip. It's safe for us to clean up | |
1730 | * the list buffers. | 1730 | * the list buffers. | |
1731 | */ | 1731 | */ | |
1732 | static void | 1732 | static void | |
1733 | atu_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | 1733 | atu_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | |
1734 | { | 1734 | { | |
1735 | struct atu_chain *c = (struct atu_chain *)priv; | 1735 | struct atu_chain *c = (struct atu_chain *)priv; | |
1736 | struct atu_softc *sc = c->atu_sc; | 1736 | struct atu_softc *sc = c->atu_sc; | |
1737 | struct ifnet *ifp = &sc->sc_if; | 1737 | struct ifnet *ifp = &sc->sc_if; | |
1738 | usbd_status err; | 1738 | usbd_status err; | |
1739 | int s; | 1739 | int s; | |
1740 | 1740 | |||
1741 | DPRINTFN(25, ("%s: atu_txeof status=%d\n", device_xname(sc->atu_dev), | 1741 | DPRINTFN(25, ("%s: atu_txeof status=%d\n", device_xname(sc->atu_dev), | |
1742 | status)); | 1742 | status)); | |
1743 | 1743 | |||
1744 | if (c->atu_mbuf) { | 1744 | if (c->atu_mbuf) { | |
1745 | m_freem(c->atu_mbuf); | 1745 | m_freem(c->atu_mbuf); | |
1746 | c->atu_mbuf = NULL; | 1746 | c->atu_mbuf = NULL; | |
1747 | } | 1747 | } | |
1748 | 1748 | |||
1749 | if (status != USBD_NORMAL_COMPLETION) { | 1749 | if (status != USBD_NORMAL_COMPLETION) { | |
1750 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) | 1750 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) | |
1751 | return; | 1751 | return; | |
1752 | 1752 | |||
1753 | DPRINTF(("%s: usb error on tx: %s\n", | 1753 | DPRINTF(("%s: usb error on tx: %s\n", | |
1754 | device_xname(sc->atu_dev), usbd_errstr(status))); | 1754 | device_xname(sc->atu_dev), usbd_errstr(status))); | |
1755 | if (status == USBD_STALLED) | 1755 | if (status == USBD_STALLED) | |
1756 | usbd_clear_endpoint_stall_async( | 1756 | usbd_clear_endpoint_stall_async( | |
1757 | sc->atu_ep[ATU_ENDPT_TX]); | 1757 | sc->atu_ep[ATU_ENDPT_TX]); | |
1758 | return; | 1758 | return; | |
1759 | } | 1759 | } | |
1760 | 1760 | |||
1761 | usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, &err); | 1761 | usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, &err); | |
1762 | 1762 | |||
1763 | if (err) | 1763 | if (err) | |
1764 | if_statinc(ifp, if_oerrors); | 1764 | if_statinc(ifp, if_oerrors); | |
1765 | else | 1765 | else | |
1766 | if_statinc(ifp, if_opackets); | 1766 | if_statinc(ifp, if_opackets); | |
1767 | 1767 | |||
1768 | s = splnet(); | 1768 | s = splnet(); | |
1769 | SLIST_INSERT_HEAD(&sc->atu_cdata.atu_tx_free, c, atu_list); | 1769 | SLIST_INSERT_HEAD(&sc->atu_cdata.atu_tx_free, c, atu_list); | |
1770 | sc->atu_cdata.atu_tx_inuse--; | 1770 | sc->atu_cdata.atu_tx_inuse--; | |
1771 | if (sc->atu_cdata.atu_tx_inuse == 0) | 1771 | if (sc->atu_cdata.atu_tx_inuse == 0) | |
1772 | ifp->if_timer = 0; | 1772 | ifp->if_timer = 0; | |
1773 | ifp->if_flags &= ~IFF_OACTIVE; | 1773 | ifp->if_flags &= ~IFF_OACTIVE; | |
1774 | splx(s); | 1774 | splx(s); | |
1775 | 1775 | |||
1776 | atu_start(ifp); | 1776 | atu_start(ifp); | |
1777 | } | 1777 | } | |
1778 | 1778 | |||
1779 | static uint8_t | 1779 | static uint8_t | |
1780 | atu_calculate_padding(int size) | 1780 | atu_calculate_padding(int size) | |
1781 | { | 1781 | { | |
1782 | size %= 64; | 1782 | size %= 64; | |
1783 | 1783 | |||
1784 | if (size < 50) | 1784 | if (size < 50) | |
1785 | return 50 - size; | 1785 | return 50 - size; | |
1786 | if (size >=61) | 1786 | if (size >=61) | |
1787 | return 64 + 50 - size; | 1787 | return 64 + 50 - size; | |
1788 | return 0; | 1788 | return 0; | |
1789 | } | 1789 | } | |
1790 | 1790 | |||
1791 | static int | 1791 | static int | |
1792 | atu_tx_start(struct atu_softc *sc, struct ieee80211_node *ni, | 1792 | atu_tx_start(struct atu_softc *sc, struct ieee80211_node *ni, | |
1793 | struct atu_chain *c, struct mbuf *m) | 1793 | struct atu_chain *c, struct mbuf *m) | |
1794 | { | 1794 | { | |
1795 | int len; | 1795 | int len; | |
1796 | struct atu_tx_hdr *h; | 1796 | struct atu_tx_hdr *h; | |
1797 | usbd_status err; | 1797 | usbd_status err; | |
1798 | uint8_t pad; | 1798 | uint8_t pad; | |
1799 | 1799 | |||
1800 | DPRINTFN(25, ("%s: atu_tx_start\n", device_xname(sc->atu_dev))); | 1800 | DPRINTFN(25, ("%s: atu_tx_start\n", device_xname(sc->atu_dev))); | |
1801 | 1801 | |||
1802 | /* Don't try to send when we're shutting down the driver */ | 1802 | /* Don't try to send when we're shutting down the driver */ | |
1803 | if (sc->sc_state != ATU_S_OK) { | 1803 | if (sc->sc_state != ATU_S_OK) { | |
1804 | m_freem(m); | 1804 | m_freem(m); | |
1805 | return EIO; | 1805 | return EIO; | |
1806 | } | 1806 | } | |
1807 | 1807 | |||
1808 | /* | 1808 | /* | |
1809 | * Copy the mbuf data into a contiguous buffer, leaving | 1809 | * Copy the mbuf data into a contiguous buffer, leaving | |
1810 | * enough room for the atmel headers | 1810 | * enough room for the atmel headers | |
1811 | */ | 1811 | */ | |
1812 | len = m->m_pkthdr.len; | 1812 | len = m->m_pkthdr.len; | |
1813 | 1813 | |||
1814 | m_copydata(m, 0, m->m_pkthdr.len, c->atu_buf + ATU_TX_HDRLEN); | 1814 | m_copydata(m, 0, m->m_pkthdr.len, c->atu_buf + ATU_TX_HDRLEN); | |
1815 | 1815 | |||
1816 | h = (struct atu_tx_hdr *)c->atu_buf; | 1816 | h = (struct atu_tx_hdr *)c->atu_buf; | |
1817 | memset(h, 0, ATU_TX_HDRLEN); | 1817 | memset(h, 0, ATU_TX_HDRLEN); | |
1818 | USETW(h->length, len); | 1818 | USETW(h->length, len); | |
1819 | h->tx_rate = 4; /* XXX rate = auto */ | 1819 | h->tx_rate = 4; /* XXX rate = auto */ | |
1820 | len += ATU_TX_HDRLEN; | 1820 | len += ATU_TX_HDRLEN; | |
1821 | 1821 | |||
1822 | pad = atu_calculate_padding(len); | 1822 | pad = atu_calculate_padding(len); | |
1823 | len += pad; | 1823 | len += pad; | |
1824 | h->padding = pad; | 1824 | h->padding = pad; | |
1825 | 1825 | |||
1826 | c->atu_length = len; | 1826 | c->atu_length = len; | |
1827 | c->atu_mbuf = m; | 1827 | c->atu_mbuf = m; | |
1828 | 1828 | |||
1829 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, c->atu_length, 0, | 1829 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, c->atu_length, 0, | |
1830 | ATU_TX_TIMEOUT, atu_txeof); | 1830 | ATU_TX_TIMEOUT, atu_txeof); | |
1831 | 1831 | |||
1832 | /* Let's get this thing into the air! */ | 1832 | /* Let's get this thing into the air! */ | |
1833 | c->atu_in_xfer = 1; | 1833 | c->atu_in_xfer = 1; | |
1834 | err = usbd_transfer(c->atu_xfer); | 1834 | err = usbd_transfer(c->atu_xfer); | |
1835 | if (err != USBD_IN_PROGRESS) { | 1835 | if (err != USBD_IN_PROGRESS) { | |
1836 | DPRINTFN(25, ("%s: atu_tx_start, err=%d", | 1836 | DPRINTFN(25, ("%s: atu_tx_start, err=%d", | |
1837 | device_xname(sc->atu_dev), err)); | 1837 | device_xname(sc->atu_dev), err)); | |
1838 | c->atu_mbuf = NULL; | 1838 | c->atu_mbuf = NULL; | |
1839 | m_freem(m); | 1839 | m_freem(m); | |
1840 | return EIO; | 1840 | return EIO; | |
1841 | } | 1841 | } | |
1842 | 1842 | |||
1843 | return 0; | 1843 | return 0; | |
1844 | } | 1844 | } | |
1845 | 1845 | |||
1846 | static void | 1846 | static void | |
1847 | atu_start(struct ifnet *ifp) | 1847 | atu_start(struct ifnet *ifp) | |
1848 | { | 1848 | { | |
1849 | struct atu_softc *sc = ifp->if_softc; | 1849 | struct atu_softc *sc = ifp->if_softc; | |
1850 | struct ieee80211com *ic = &sc->sc_ic; | 1850 | struct ieee80211com *ic = &sc->sc_ic; | |
1851 | struct atu_cdata *cd = &sc->atu_cdata; | 1851 | struct atu_cdata *cd = &sc->atu_cdata; | |
1852 | struct ieee80211_node *ni; | 1852 | struct ieee80211_node *ni; | |
1853 | struct atu_chain *c; | 1853 | struct atu_chain *c; | |
1854 | struct mbuf *m = NULL; | 1854 | struct mbuf *m = NULL; | |
1855 | int s; | 1855 | int s; | |
1856 | 1856 | |||
1857 | DPRINTFN(25, ("%s: atu_start: enter\n", device_xname(sc->atu_dev))); | 1857 | DPRINTFN(25, ("%s: atu_start: enter\n", device_xname(sc->atu_dev))); | |
1858 | 1858 | |||
1859 | if ((ifp->if_flags & IFF_RUNNING) == 0) { | 1859 | if ((ifp->if_flags & IFF_RUNNING) == 0) { | |
1860 | return; | 1860 | return; | |
1861 | } | 1861 | } | |
1862 | if (ifp->if_flags & IFF_OACTIVE) { | 1862 | if (ifp->if_flags & IFF_OACTIVE) { | |
1863 | DPRINTFN(30, ("%s: atu_start: IFF_OACTIVE\n", | 1863 | DPRINTFN(30, ("%s: atu_start: IFF_OACTIVE\n", | |
1864 | device_xname(sc->atu_dev))); | 1864 | device_xname(sc->atu_dev))); | |
1865 | return; | 1865 | return; | |
1866 | } | 1866 | } | |
1867 | 1867 | |||
1868 | for (;;) { | 1868 | for (;;) { | |
1869 | /* grab a TX buffer */ | 1869 | /* grab a TX buffer */ | |
1870 | s = splnet(); | 1870 | s = splnet(); | |
1871 | c = SLIST_FIRST(&cd->atu_tx_free); | 1871 | c = SLIST_FIRST(&cd->atu_tx_free); | |
1872 | if (c != NULL) { | 1872 | if (c != NULL) { | |
1873 | SLIST_REMOVE_HEAD(&cd->atu_tx_free, atu_list); | 1873 | SLIST_REMOVE_HEAD(&cd->atu_tx_free, atu_list); | |
1874 | cd->atu_tx_inuse++; | 1874 | cd->atu_tx_inuse++; | |
1875 | if (cd->atu_tx_inuse == ATU_TX_LIST_CNT) | 1875 | if (cd->atu_tx_inuse == ATU_TX_LIST_CNT) | |
1876 | ifp->if_flags |= IFF_OACTIVE; | 1876 | ifp->if_flags |= IFF_OACTIVE; | |
1877 | } | 1877 | } | |
1878 | splx(s); | 1878 | splx(s); | |
1879 | if (c == NULL) { | 1879 | if (c == NULL) { | |
1880 | DPRINTFN(10, ("%s: out of tx xfers\n", | 1880 | DPRINTFN(10, ("%s: out of tx xfers\n", | |
1881 | device_xname(sc->atu_dev))); | 1881 | device_xname(sc->atu_dev))); | |
1882 | ifp->if_flags |= IFF_OACTIVE; | 1882 | ifp->if_flags |= IFF_OACTIVE; | |
1883 | break; | 1883 | break; | |
1884 | } | 1884 | } | |
1885 | 1885 | |||
1886 | /* | 1886 | /* | |
1887 | * Poll the management queue for frames, it has priority over | 1887 | * Poll the management queue for frames, it has priority over | |
1888 | * normal data frames. | 1888 | * normal data frames. | |
1889 | */ | 1889 | */ | |
1890 | IF_DEQUEUE(&ic->ic_mgtq, m); | 1890 | IF_DEQUEUE(&ic->ic_mgtq, m); | |
1891 | if (m == NULL) { | 1891 | if (m == NULL) { | |
1892 | DPRINTFN(10, ("%s: atu_start: data packet\n", | 1892 | DPRINTFN(10, ("%s: atu_start: data packet\n", | |
1893 | device_xname(sc->atu_dev))); | 1893 | device_xname(sc->atu_dev))); | |
1894 | if (ic->ic_state != IEEE80211_S_RUN) { | 1894 | if (ic->ic_state != IEEE80211_S_RUN) { | |
1895 | DPRINTFN(25, ("%s: no data till running\n", | 1895 | DPRINTFN(25, ("%s: no data till running\n", | |
1896 | device_xname(sc->atu_dev))); | 1896 | device_xname(sc->atu_dev))); | |
1897 | /* put the xfer back on the list */ | 1897 | /* put the xfer back on the list */ | |
1898 | s = splnet(); | 1898 | s = splnet(); | |
1899 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | 1899 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | |
1900 | atu_list); | 1900 | atu_list); | |
1901 | cd->atu_tx_inuse--; | 1901 | cd->atu_tx_inuse--; | |
1902 | splx(s); | 1902 | splx(s); | |
1903 | break; | 1903 | break; | |
1904 | } | 1904 | } | |
1905 | 1905 | |||
1906 | IFQ_DEQUEUE(&ifp->if_snd, m); | 1906 | IFQ_DEQUEUE(&ifp->if_snd, m); | |
1907 | if (m == NULL) { | 1907 | if (m == NULL) { | |
1908 | DPRINTFN(25, ("%s: nothing to send\n", | 1908 | DPRINTFN(25, ("%s: nothing to send\n", | |
1909 | device_xname(sc->atu_dev))); | 1909 | device_xname(sc->atu_dev))); | |
1910 | s = splnet(); | 1910 | s = splnet(); | |
1911 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | 1911 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | |
1912 | atu_list); | 1912 | atu_list); | |
1913 | cd->atu_tx_inuse--; | 1913 | cd->atu_tx_inuse--; | |
1914 | splx(s); | 1914 | splx(s); | |
1915 | break; | 1915 | break; | |
1916 | } | 1916 | } | |
1917 | bpf_mtap(ifp, m, BPF_D_OUT); | 1917 | bpf_mtap(ifp, m, BPF_D_OUT); | |
1918 | ni = ieee80211_find_txnode(ic, | 1918 | ni = ieee80211_find_txnode(ic, | |
1919 | mtod(m, struct ether_header *)->ether_dhost); | 1919 | mtod(m, struct ether_header *)->ether_dhost); | |
1920 | if (ni == NULL) { | 1920 | if (ni == NULL) { | |
1921 | m_freem(m); | 1921 | m_freem(m); | |
1922 | goto bad; | 1922 | goto bad; | |
1923 | } | 1923 | } | |
1924 | m = ieee80211_encap(ic, m, ni); | 1924 | m = ieee80211_encap(ic, m, ni); | |
1925 | if (m == NULL) | 1925 | if (m == NULL) | |
1926 | goto bad; | 1926 | goto bad; | |
1927 | } else { | 1927 | } else { | |
1928 | DPRINTFN(25, ("%s: atu_start: mgmt packet\n", | 1928 | DPRINTFN(25, ("%s: atu_start: mgmt packet\n", | |
1929 | device_xname(sc->atu_dev))); | 1929 | device_xname(sc->atu_dev))); | |
1930 | 1930 | |||
1931 | /* | 1931 | /* | |
1932 | * Hack! The referenced node pointer is in the | 1932 | * Hack! The referenced node pointer is in the | |
1933 | * rcvif field of the packet header. This is | 1933 | * rcvif field of the packet header. This is | |
1934 | * placed there by ieee80211_mgmt_output because | 1934 | * placed there by ieee80211_mgmt_output because | |
1935 | * we need to hold the reference with the frame | 1935 | * we need to hold the reference with the frame | |
1936 | * and there's no other way (other than packet | 1936 | * and there's no other way (other than packet | |
1937 | * tags which we consider too expensive to use) | 1937 | * tags which we consider too expensive to use) | |
1938 | * to pass it along. | 1938 | * to pass it along. | |
1939 | */ | 1939 | */ | |
1940 | ni = M_GETCTX(m, struct ieee80211_node *); | 1940 | ni = M_GETCTX(m, struct ieee80211_node *); | |
1941 | M_CLEARCTX(m); | 1941 | M_CLEARCTX(m); | |
1942 | 1942 | |||
1943 | /* sc->sc_stats.ast_tx_mgmt++; */ | 1943 | /* sc->sc_stats.ast_tx_mgmt++; */ | |
1944 | } | 1944 | } | |
1945 | 1945 | |||
1946 | bpf_mtap3(ic->ic_rawbpf, m, BPF_D_OUT); | 1946 | bpf_mtap3(ic->ic_rawbpf, m, BPF_D_OUT); | |
1947 | 1947 | |||
1948 | if (atu_tx_start(sc, ni, c, m)) { | 1948 | if (atu_tx_start(sc, ni, c, m)) { | |
1949 | bad: | 1949 | bad: | |
1950 | s = splnet(); | 1950 | s = splnet(); | |
1951 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | 1951 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | |
1952 | atu_list); | 1952 | atu_list); | |
1953 | cd->atu_tx_inuse--; | 1953 | cd->atu_tx_inuse--; | |
1954 | splx(s); | 1954 | splx(s); | |
1955 | /* if_statinc(ifp, if_oerrors); */ | 1955 | /* if_statinc(ifp, if_oerrors); */ | |
1956 | if (ni != NULL) | 1956 | if (ni != NULL) | |
1957 | ieee80211_free_node(ni); | 1957 | ieee80211_free_node(ni); | |
1958 | continue; | 1958 | continue; | |
1959 | } | 1959 | } | |
1960 | ifp->if_timer = 5; | 1960 | ifp->if_timer = 5; | |
1961 | } | 1961 | } | |
1962 | } | 1962 | } | |
1963 | 1963 | |||
1964 | static int | 1964 | static int | |
1965 | atu_init(struct ifnet *ifp) | 1965 | atu_init(struct ifnet *ifp) | |
1966 | { | 1966 | { | |
1967 | struct atu_softc *sc = ifp->if_softc; | 1967 | struct atu_softc *sc = ifp->if_softc; | |
1968 | struct ieee80211com *ic = &sc->sc_ic; | 1968 | struct ieee80211com *ic = &sc->sc_ic; | |
1969 | struct atu_chain *c; | 1969 | struct atu_chain *c; | |
1970 | usbd_status err; | 1970 | usbd_status err; | |
1971 | int i, s; | 1971 | int i, s; | |
1972 | 1972 | |||
1973 | s = splnet(); | 1973 | s = splnet(); | |
1974 | 1974 | |||
1975 | DPRINTFN(10, ("%s: atu_init\n", device_xname(sc->atu_dev))); | 1975 | DPRINTFN(10, ("%s: atu_init\n", device_xname(sc->atu_dev))); | |
1976 | 1976 | |||
1977 | if (ifp->if_flags & IFF_RUNNING) { | 1977 | if (ifp->if_flags & IFF_RUNNING) { | |
1978 | splx(s); | 1978 | splx(s); | |
1979 | return 0; | 1979 | return 0; | |
1980 | } | 1980 | } | |
1981 | 1981 | |||
1982 | /* Load the multicast filter. */ | 1982 | /* Load the multicast filter. */ | |
1983 | /*atu_setmulti(sc); */ | 1983 | /*atu_setmulti(sc); */ | |
1984 | 1984 | |||
1985 | /* Open RX and TX pipes. */ | 1985 | /* Open RX and TX pipes. */ | |
1986 | err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_RX], | 1986 | err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_RX], | |
1987 | USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_RX]); | 1987 | USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_RX]); | |
1988 | if (err) { | 1988 | if (err) { | |
1989 | DPRINTF(("%s: open rx pipe failed: %s\n", | 1989 | DPRINTF(("%s: open rx pipe failed: %s\n", | |
1990 | device_xname(sc->atu_dev), usbd_errstr(err))); | 1990 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
1991 | splx(s); | 1991 | splx(s); | |
1992 | return EIO; | 1992 | return EIO; | |
1993 | } | 1993 | } | |
1994 | 1994 | |||
1995 | err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_TX], | 1995 | err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_TX], | |
1996 | USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_TX]); | 1996 | USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_TX]); | |
1997 | if (err) { | 1997 | if (err) { | |
1998 | DPRINTF(("%s: open tx pipe failed: %s\n", | 1998 | DPRINTF(("%s: open tx pipe failed: %s\n", | |
1999 | device_xname(sc->atu_dev), usbd_errstr(err))); | 1999 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
2000 | splx(s); | 2000 | splx(s); | |
2001 | return EIO; | 2001 | return EIO; | |
2002 | } | 2002 | } | |
2003 | 2003 | |||
2004 | /* Init TX ring */ | 2004 | /* Init TX ring */ | |
2005 | if (atu_tx_list_init(sc)) | 2005 | if (atu_tx_list_init(sc)) | |
2006 | printf("%s: tx list init failed\n", device_xname(sc->atu_dev)); | 2006 | printf("%s: tx list init failed\n", device_xname(sc->atu_dev)); | |
2007 | 2007 | |||
2008 | /* Init RX ring */ | 2008 | /* Init RX ring */ | |
2009 | if (atu_rx_list_init(sc)) | 2009 | if (atu_rx_list_init(sc)) | |
2010 | printf("%s: rx list init failed\n", device_xname(sc->atu_dev)); | 2010 | printf("%s: rx list init failed\n", device_xname(sc->atu_dev)); | |
2011 | 2011 | |||
2012 | /* Start up the receive pipe. */ | 2012 | /* Start up the receive pipe. */ | |
2013 | for (i = 0; i < ATU_RX_LIST_CNT; i++) { | 2013 | for (i = 0; i < ATU_RX_LIST_CNT; i++) { | |
2014 | c = &sc->atu_cdata.atu_rx_chain[i]; | 2014 | c = &sc->atu_cdata.atu_rx_chain[i]; | |
2015 | 2015 | |||
2016 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, ATU_RX_BUFSZ, | 2016 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, ATU_RX_BUFSZ, | |
2017 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atu_rxeof); | 2017 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atu_rxeof); | |
2018 | usbd_transfer(c->atu_xfer); | 2018 | usbd_transfer(c->atu_xfer); | |
2019 | } | 2019 | } | |
2020 | 2020 | |||
2021 | DPRINTFN(10, ("%s: starting up using MAC=%s\n", | 2021 | DPRINTFN(10, ("%s: starting up using MAC=%s\n", | |
2022 | device_xname(sc->atu_dev), ether_sprintf(ic->ic_myaddr))); | 2022 | device_xname(sc->atu_dev), ether_sprintf(ic->ic_myaddr))); | |
2023 | 2023 | |||
2024 | /* Do initial setup */ | 2024 | /* Do initial setup */ | |
2025 | err = atu_initial_config(sc); | 2025 | err = atu_initial_config(sc); | |
2026 | if (err) { | 2026 | if (err) { | |
2027 | DPRINTF(("%s: initial config failed!\n", | 2027 | DPRINTF(("%s: initial config failed!\n", | |
2028 | device_xname(sc->atu_dev))); | 2028 | device_xname(sc->atu_dev))); | |
2029 | splx(s); | 2029 | splx(s); | |
2030 | return EIO; | 2030 | return EIO; | |
2031 | } | 2031 | } | |
2032 | DPRINTFN(10, ("%s: initialised transceiver\n", | 2032 | DPRINTFN(10, ("%s: initialised transceiver\n", | |
2033 | device_xname(sc->atu_dev))); | 2033 | device_xname(sc->atu_dev))); | |
2034 | 2034 | |||
2035 | /* sc->atu_rxfilt = ATU_RXFILT_UNICAST|ATU_RXFILT_BROADCAST; */ | 2035 | /* sc->atu_rxfilt = ATU_RXFILT_UNICAST|ATU_RXFILT_BROADCAST; */ | |
2036 | 2036 | |||
2037 | /* If we want promiscuous mode, set the allframes bit. */ | 2037 | /* If we want promiscuous mode, set the allframes bit. */ | |
2038 | /* | 2038 | /* | |
2039 | if (ifp->if_flags & IFF_PROMISC) | 2039 | if (ifp->if_flags & IFF_PROMISC) | |
2040 | sc->atu_rxfilt |= ATU_RXFILT_PROMISC; | 2040 | sc->atu_rxfilt |= ATU_RXFILT_PROMISC; | |
2041 | */ | 2041 | */ | |
2042 | 2042 | |||
2043 | ifp->if_flags |= IFF_RUNNING; | 2043 | ifp->if_flags |= IFF_RUNNING; | |
2044 | ifp->if_flags &= ~IFF_OACTIVE; | 2044 | ifp->if_flags &= ~IFF_OACTIVE; | |
2045 | splx(s); | 2045 | splx(s); | |
2046 | 2046 | |||
2047 | /* XXX the following HAS to be replaced */ | 2047 | /* XXX the following HAS to be replaced */ | |
2048 | s = splnet(); | 2048 | s = splnet(); | |
2049 | err = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | 2049 | err = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | |
2050 | if (err) { | 2050 | if (err) { | |
2051 | DPRINTFN(1, ("%s: atu_init: error calling " | 2051 | DPRINTFN(1, ("%s: atu_init: error calling " | |
2052 | "ieee80211_net_state", device_xname(sc->atu_dev))); | 2052 | "ieee80211_net_state", device_xname(sc->atu_dev))); | |
2053 | } | 2053 | } | |
2054 | splx(s); | 2054 | splx(s); | |
2055 | 2055 | |||
2056 | return 0; | 2056 | return 0; | |
2057 | } | 2057 | } | |
2058 | 2058 | |||
2059 | #if 0 && defined(ATU_DEBUG) /* XXX XXX XXX UNUSED */ | 2059 | #if 0 && defined(ATU_DEBUG) /* XXX XXX XXX UNUSED */ | |
2060 | static void atu_debug_print(struct atu_softc *); | 2060 | static void atu_debug_print(struct atu_softc *); | |
2061 | static void | 2061 | static void | |
2062 | atu_debug_print(struct atu_softc *sc) | 2062 | atu_debug_print(struct atu_softc *sc) | |
2063 | { | 2063 | { | |
2064 | usbd_status err; | 2064 | usbd_status err; | |
2065 | uint8_t tmp[32]; | 2065 | uint8_t tmp[32]; | |
2066 | 2066 | |||
2067 | /* DEBUG */ | 2067 | /* DEBUG */ | |
2068 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_BSSID, tmp))) | 2068 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_BSSID, tmp))) | |
2069 | return; | 2069 | return; | |
2070 | DPRINTF(("%s: DEBUG: current BSSID=%s\n", device_xname(sc->atu_dev), | 2070 | DPRINTF(("%s: DEBUG: current BSSID=%s\n", device_xname(sc->atu_dev), | |
2071 | ether_sprintf(tmp))); | 2071 | ether_sprintf(tmp))); | |
2072 | 2072 | |||
2073 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__BEACON_PERIOD, tmp))) | 2073 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__BEACON_PERIOD, tmp))) | |
2074 | return; | 2074 | return; | |
2075 | DPRINTF(("%s: DEBUG: beacon period=%d\n", device_xname(sc->atu_dev), | 2075 | DPRINTF(("%s: DEBUG: beacon period=%d\n", device_xname(sc->atu_dev), | |
2076 | tmp[0])); | 2076 | tmp[0])); | |
2077 | 2077 | |||
2078 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__PRIVACY_INVOKED, tmp))) | 2078 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__PRIVACY_INVOKED, tmp))) | |
2079 | return; | 2079 | return; | |
2080 | DPRINTF(("%s: DEBUG: privacy invoked=%d\n", device_xname(sc->atu_dev), | 2080 | DPRINTF(("%s: DEBUG: privacy invoked=%d\n", device_xname(sc->atu_dev), | |
2081 | tmp[0])); | 2081 | tmp[0])); | |
2082 | 2082 | |||
2083 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__ENCR_LEVEL, tmp))) | 2083 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__ENCR_LEVEL, tmp))) | |
2084 | return; | 2084 | return; | |
2085 | DPRINTF(("%s: DEBUG: encr_level=%d\n", device_xname(sc->atu_dev), | 2085 | DPRINTF(("%s: DEBUG: encr_level=%d\n", device_xname(sc->atu_dev), | |
2086 | tmp[0])); | 2086 | tmp[0])); | |
2087 | 2087 | |||
2088 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__ICV_ERROR_COUNT, tmp))) | 2088 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__ICV_ERROR_COUNT, tmp))) | |
2089 | return; | 2089 | return; | |
2090 | DPRINTF(("%s: DEBUG: icv error count=%d\n", device_xname(sc->atu_dev), | 2090 | DPRINTF(("%s: DEBUG: icv error count=%d\n", device_xname(sc->atu_dev), | |
2091 | *(short *)tmp)); | 2091 | *(short *)tmp)); | |
2092 | 2092 | |||
2093 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__EXCLUDED_COUNT, tmp))) | 2093 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__EXCLUDED_COUNT, tmp))) | |
2094 | return; | 2094 | return; | |
2095 | DPRINTF(("%s: DEBUG: wep excluded count=%d\n", | 2095 | DPRINTF(("%s: DEBUG: wep excluded count=%d\n", | |
2096 | device_xname(sc->atu_dev), *(short *)tmp)); | 2096 | device_xname(sc->atu_dev), *(short *)tmp)); | |
2097 | 2097 | |||
2098 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__POWER_MODE, tmp))) | 2098 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__POWER_MODE, tmp))) | |
2099 | return; | 2099 | return; | |
2100 | DPRINTF(("%s: DEBUG: power mode=%d\n", device_xname(sc->atu_dev), | 2100 | DPRINTF(("%s: DEBUG: power mode=%d\n", device_xname(sc->atu_dev), | |
2101 | tmp[0])); | 2101 | tmp[0])); | |
2102 | 2102 | |||
2103 | if ((err = atu_get_mib(sc, MIB_PHY__CHANNEL, tmp))) | 2103 | if ((err = atu_get_mib(sc, MIB_PHY__CHANNEL, tmp))) | |
2104 | return; | 2104 | return; | |
2105 | DPRINTF(("%s: DEBUG: channel=%d\n", device_xname(sc->atu_dev), tmp[0])); | 2105 | DPRINTF(("%s: DEBUG: channel=%d\n", device_xname(sc->atu_dev), tmp[0])); | |
2106 | 2106 | |||
2107 | if ((err = atu_get_mib(sc, MIB_PHY__REG_DOMAIN, tmp))) | 2107 | if ((err = atu_get_mib(sc, MIB_PHY__REG_DOMAIN, tmp))) | |
2108 | return; | 2108 | return; | |
2109 | DPRINTF(("%s: DEBUG: reg domain=%d\n", device_xname(sc->atu_dev), | 2109 | DPRINTF(("%s: DEBUG: reg domain=%d\n", device_xname(sc->atu_dev), | |
2110 | tmp[0])); | 2110 | tmp[0])); | |
2111 | 2111 | |||
2112 | if ((err = atu_get_mib(sc, MIB_LOCAL__SSID_SIZE, tmp))) | 2112 | if ((err = atu_get_mib(sc, MIB_LOCAL__SSID_SIZE, tmp))) | |
2113 | return; | 2113 | return; | |
2114 | DPRINTF(("%s: DEBUG: ssid size=%d\n", device_xname(sc->atu_dev), | 2114 | DPRINTF(("%s: DEBUG: ssid size=%d\n", device_xname(sc->atu_dev), | |
2115 | tmp[0])); | 2115 | tmp[0])); | |
2116 | 2116 | |||
2117 | if ((err = atu_get_mib(sc, MIB_LOCAL__BEACON_ENABLE, tmp))) | 2117 | if ((err = atu_get_mib(sc, MIB_LOCAL__BEACON_ENABLE, tmp))) | |
2118 | return; | 2118 | return; | |
2119 | DPRINTF(("%s: DEBUG: beacon enable=%d\n", device_xname(sc->atu_dev), | 2119 | DPRINTF(("%s: DEBUG: beacon enable=%d\n", device_xname(sc->atu_dev), | |
2120 | tmp[0])); | 2120 | tmp[0])); | |
2121 | 2121 | |||
2122 | if ((err = atu_get_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, tmp))) | 2122 | if ((err = atu_get_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, tmp))) | |
2123 | return; | 2123 | return; | |
2124 | DPRINTF(("%s: DEBUG: auto rate fallback=%d\n", | 2124 | DPRINTF(("%s: DEBUG: auto rate fallback=%d\n", | |
2125 | device_xname(sc->atu_dev), tmp[0])); | 2125 | device_xname(sc->atu_dev), tmp[0])); | |
2126 | 2126 | |||
2127 | if ((err = atu_get_mib(sc, MIB_MAC_ADDR__ADDR, tmp))) | 2127 | if ((err = atu_get_mib(sc, MIB_MAC_ADDR__ADDR, tmp))) | |
2128 | return; | 2128 | return; | |
2129 | DPRINTF(("%s: DEBUG: mac addr=%s\n", device_xname(sc->atu_dev), | 2129 | DPRINTF(("%s: DEBUG: mac addr=%s\n", device_xname(sc->atu_dev), | |
2130 | ether_sprintf(tmp))); | 2130 | ether_sprintf(tmp))); | |
2131 | 2131 | |||
2132 | if ((err = atu_get_mib(sc, MIB_MAC__DESIRED_SSID, tmp))) | 2132 | if ((err = atu_get_mib(sc, MIB_MAC__DESIRED_SSID, tmp))) | |
2133 | return; | 2133 | return; | |
2134 | DPRINTF(("%s: DEBUG: desired ssid=%s\n", device_xname(sc->atu_dev), | 2134 | DPRINTF(("%s: DEBUG: desired ssid=%s\n", device_xname(sc->atu_dev), | |
2135 | tmp)); | 2135 | tmp)); | |
2136 | 2136 | |||
2137 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_ESSID, tmp))) | 2137 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_ESSID, tmp))) | |
2138 | return; | 2138 | return; | |
2139 | DPRINTF(("%s: DEBUG: current ESSID=%s\n", device_xname(sc->atu_dev), | 2139 | DPRINTF(("%s: DEBUG: current ESSID=%s\n", device_xname(sc->atu_dev), | |
2140 | tmp)); | 2140 | tmp)); | |
2141 | } | 2141 | } | |
2142 | #endif /* ATU_DEBUG */ | 2142 | #endif /* ATU_DEBUG */ | |
2143 | 2143 | |||
2144 | static int | 2144 | static int | |
2145 | atu_ioctl(struct ifnet *ifp, u_long command, void *data) | 2145 | atu_ioctl(struct ifnet *ifp, u_long command, void *data) | |
2146 | { | 2146 | { | |
2147 | struct atu_softc *sc = ifp->if_softc; | 2147 | struct atu_softc *sc = ifp->if_softc; | |
2148 | struct ieee80211com *ic = &sc->sc_ic; | 2148 | struct ieee80211com *ic = &sc->sc_ic; | |
2149 | int err = 0, s; | 2149 | int err = 0, s; | |
2150 | 2150 | |||
2151 | s = splnet(); | 2151 | s = splnet(); | |
2152 | switch (command) { | 2152 | switch (command) { | |
2153 | default: | 2153 | default: | |
2154 | DPRINTFN(15, ("%s: ieee80211_ioctl (%lu)\n", | 2154 | DPRINTFN(15, ("%s: ieee80211_ioctl (%lu)\n", | |
2155 | device_xname(sc->atu_dev), command)); | 2155 | device_xname(sc->atu_dev), command)); | |
2156 | err = ieee80211_ioctl(ic, command, data); | 2156 | err = ieee80211_ioctl(ic, command, data); | |
2157 | break; | 2157 | break; | |
2158 | } | 2158 | } | |
2159 | 2159 | |||
2160 | if (err == ENETRESET) { | 2160 | if (err == ENETRESET) { | |
2161 | if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) == | 2161 | if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) == | |
2162 | (IFF_RUNNING|IFF_UP)) { | 2162 | (IFF_RUNNING|IFF_UP)) { | |
2163 | DPRINTF(("%s: atu_ioctl(): netreset %lu\n", | 2163 | DPRINTF(("%s: atu_ioctl(): netreset %lu\n", | |
2164 | device_xname(sc->atu_dev), command)); | 2164 | device_xname(sc->atu_dev), command)); | |
2165 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | 2165 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | |
2166 | atu_initial_config(sc); | 2166 | atu_initial_config(sc); | |
2167 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | 2167 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | |
2168 | } | 2168 | } | |
2169 | err = 0; | 2169 | err = 0; | |
2170 | } | 2170 | } | |
2171 | 2171 | |||
2172 | splx(s); | 2172 | splx(s); | |
2173 | return err; | 2173 | return err; | |
2174 | } | 2174 | } | |
2175 | 2175 | |||
2176 | static void | 2176 | static void | |
2177 | atu_watchdog(struct ifnet *ifp) | 2177 | atu_watchdog(struct ifnet *ifp) | |
2178 | { | 2178 | { | |
2179 | struct atu_softc *sc = ifp->if_softc; | 2179 | struct atu_softc *sc = ifp->if_softc; | |
2180 | struct atu_chain *c; | 2180 | struct atu_chain *c; | |
2181 | usbd_status stat; | 2181 | usbd_status stat; | |
2182 | int cnt, s; | 2182 | int cnt, s; | |
2183 | 2183 | |||
2184 | DPRINTF(("%s: atu_watchdog\n", device_xname(sc->atu_dev))); | 2184 | DPRINTF(("%s: atu_watchdog\n", device_xname(sc->atu_dev))); | |
2185 | 2185 | |||
2186 | ifp->if_timer = 0; | 2186 | ifp->if_timer = 0; | |
2187 | 2187 | |||
2188 | if (sc->sc_state != ATU_S_OK || (ifp->if_flags & IFF_RUNNING) == 0) | 2188 | if (sc->sc_state != ATU_S_OK || (ifp->if_flags & IFF_RUNNING) == 0) | |
2189 | return; | 2189 | return; | |
2190 | 2190 | |||
2191 | sc = ifp->if_softc; | 2191 | sc = ifp->if_softc; | |
2192 | s = splnet(); | 2192 | s = splnet(); | |
2193 | if_statinc(ifp, if_oerrors); | 2193 | if_statinc(ifp, if_oerrors); | |
2194 | DPRINTF(("%s: watchdog timeout\n", device_xname(sc->atu_dev))); | 2194 | DPRINTF(("%s: watchdog timeout\n", device_xname(sc->atu_dev))); | |
2195 | 2195 | |||
2196 | /* | 2196 | /* | |
2197 | * TODO: | 2197 | * TODO: | |
2198 | * we should change this since we have multiple TX tranfers... | 2198 | * we should change this since we have multiple TX tranfers... | |
2199 | */ | 2199 | */ | |
2200 | for (cnt = 0; cnt < ATU_TX_LIST_CNT; cnt++) { | 2200 | for (cnt = 0; cnt < ATU_TX_LIST_CNT; cnt++) { | |
2201 | c = &sc->atu_cdata.atu_tx_chain[cnt]; | 2201 | c = &sc->atu_cdata.atu_tx_chain[cnt]; | |
2202 | if (c->atu_in_xfer) { | 2202 | if (c->atu_in_xfer) { | |
2203 | usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, | 2203 | usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, | |
2204 | &stat); | 2204 | &stat); | |
2205 | atu_txeof(c->atu_xfer, c, stat); | 2205 | atu_txeof(c->atu_xfer, c, stat); | |
2206 | } | 2206 | } | |
2207 | } | 2207 | } | |
2208 | 2208 | |||
2209 | if (!IFQ_IS_EMPTY(&ifp->if_snd)) | 2209 | if (!IFQ_IS_EMPTY(&ifp->if_snd)) | |
2210 | atu_start(ifp); | 2210 | atu_start(ifp); | |
2211 | splx(s); | 2211 | splx(s); | |
2212 | 2212 | |||
2213 | ieee80211_watchdog(&sc->sc_ic); | 2213 | ieee80211_watchdog(&sc->sc_ic); | |
2214 | } | 2214 | } | |
2215 | 2215 | |||
2216 | /* | 2216 | /* | |
2217 | * Stop the adapter and free any mbufs allocated to the | 2217 | * Stop the adapter and free any mbufs allocated to the | |
2218 | * RX and TX lists. | 2218 | * RX and TX lists. | |
2219 | */ | 2219 | */ | |
2220 | static void | 2220 | static void | |
2221 | atu_stop(struct ifnet *ifp, int disable) | 2221 | atu_stop(struct ifnet *ifp, int disable) | |
2222 | { | 2222 | { | |
2223 | struct atu_softc *sc = ifp->if_softc; | 2223 | struct atu_softc *sc = ifp->if_softc; | |
2224 | struct ieee80211com *ic = &sc->sc_ic; | 2224 | struct ieee80211com *ic = &sc->sc_ic; | |
2225 | struct atu_cdata *cd; | 2225 | struct atu_cdata *cd; | |
2226 | usbd_status err; | 2226 | usbd_status err; | |
2227 | int s; | 2227 | int s; | |
2228 | 2228 | |||
2229 | s = splnet(); | 2229 | s = splnet(); | |
2230 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | 2230 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | |
2231 | ifp->if_timer = 0; | 2231 | ifp->if_timer = 0; | |
2232 | 2232 | |||
2233 | usb_rem_task_wait(sc->atu_udev, &sc->sc_task, USB_TASKQ_DRIVER, NULL); | 2233 | usb_rem_task_wait(sc->atu_udev, &sc->sc_task, USB_TASKQ_DRIVER, NULL); | |
2234 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | 2234 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | |
2235 | 2235 | |||
2236 | /* Stop transfers. */ | 2236 | /* Stop transfers. */ | |
2237 | if (sc->atu_ep[ATU_ENDPT_RX] != NULL) { | 2237 | if (sc->atu_ep[ATU_ENDPT_RX] != NULL) { | |
2238 | err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]); | 2238 | usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]); | |
2239 | if (err) { | |||
2240 | DPRINTF(("%s: abort rx pipe failed: %s\n", | |||
2241 | device_xname(sc->atu_dev), usbd_errstr(err))); | |||
2242 | } | |||
2243 | } | 2239 | } | |
2244 | 2240 | |||
2245 | if (sc->atu_ep[ATU_ENDPT_TX] != NULL) { | 2241 | if (sc->atu_ep[ATU_ENDPT_TX] != NULL) { | |
2246 | err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]); | 2242 | usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]); | |
2247 | if (err) { | |||
2248 | DPRINTF(("%s: abort tx pipe failed: %s\n", | |||
2249 | device_xname(sc->atu_dev), usbd_errstr(err))); | |||
2250 | } | |||
2251 | } | 2243 | } | |
2252 | 2244 | |||
2253 | /* Free RX/TX/MGMT list resources. */ | 2245 | /* Free RX/TX/MGMT list resources. */ | |
2254 | cd = &sc->atu_cdata; | 2246 | cd = &sc->atu_cdata; | |
2255 | atu_xfer_list_free(sc, cd->atu_rx_chain, ATU_RX_LIST_CNT); | 2247 | atu_xfer_list_free(sc, cd->atu_rx_chain, ATU_RX_LIST_CNT); | |
2256 | atu_xfer_list_free(sc, cd->atu_tx_chain, ATU_TX_LIST_CNT); | 2248 | atu_xfer_list_free(sc, cd->atu_tx_chain, ATU_TX_LIST_CNT); | |
2257 | 2249 | |||
2258 | /* Close pipes */ | 2250 | /* Close pipes */ | |
2259 | if (sc->atu_ep[ATU_ENDPT_RX] != NULL) { | 2251 | if (sc->atu_ep[ATU_ENDPT_RX] != NULL) { | |
2260 | err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_RX]); | 2252 | err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_RX]); | |
2261 | if (err) { | 2253 | if (err) { | |
2262 | DPRINTF(("%s: close rx pipe failed: %s\n", | 2254 | DPRINTF(("%s: close rx pipe failed: %s\n", | |
2263 | device_xname(sc->atu_dev), usbd_errstr(err))); | 2255 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
2264 | } | 2256 | } | |
2265 | sc->atu_ep[ATU_ENDPT_RX] = NULL; | 2257 | sc->atu_ep[ATU_ENDPT_RX] = NULL; | |
2266 | } | 2258 | } | |
2267 | 2259 | |||
2268 | if (sc->atu_ep[ATU_ENDPT_TX] != NULL) { | 2260 | if (sc->atu_ep[ATU_ENDPT_TX] != NULL) { | |
2269 | err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_TX]); | 2261 | err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_TX]); | |
2270 | if (err) { | 2262 | if (err) { | |
2271 | DPRINTF(("%s: close tx pipe failed: %s\n", | 2263 | DPRINTF(("%s: close tx pipe failed: %s\n", | |
2272 | device_xname(sc->atu_dev), usbd_errstr(err))); | 2264 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
2273 | } | 2265 | } | |
2274 | sc->atu_ep[ATU_ENDPT_TX] = NULL; | 2266 | sc->atu_ep[ATU_ENDPT_TX] = NULL; | |
2275 | } | 2267 | } | |
2276 | 2268 | |||
2277 | /* Let's be nice and turn off the radio before we leave */ | 2269 | /* Let's be nice and turn off the radio before we leave */ | |
2278 | atu_switch_radio(sc, 0); | 2270 | atu_switch_radio(sc, 0); | |
2279 | 2271 | |||
2280 | splx(s); | 2272 | splx(s); | |
2281 | } | 2273 | } |
--- src/sys/dev/usb/ualea.c 2021/05/29 08:45:19 1.13
+++ src/sys/dev/usb/ualea.c 2022/03/03 06:05:38 1.14
@@ -1,289 +1,289 @@ | @@ -1,289 +1,289 @@ | |||
1 | /* $NetBSD: ualea.c,v 1.13 2021/05/29 08:45:19 riastradh Exp $ */ | 1 | /* $NetBSD: ualea.c,v 1.14 2022/03/03 06:05:38 riastradh Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2017 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2017 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Taylor R. Campbell. | 8 | * by Taylor R. Campbell. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | __KERNEL_RCSID(0, "$NetBSD: ualea.c,v 1.13 2021/05/29 08:45:19 riastradh Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: ualea.c,v 1.14 2022/03/03 06:05:38 riastradh Exp $"); | |
34 | 34 | |||
35 | #include <sys/types.h> | 35 | #include <sys/types.h> | |
36 | #include <sys/atomic.h> | 36 | #include <sys/atomic.h> | |
37 | #include <sys/device_if.h> | 37 | #include <sys/device_if.h> | |
38 | #include <sys/kmem.h> | 38 | #include <sys/kmem.h> | |
39 | #include <sys/module.h> | 39 | #include <sys/module.h> | |
40 | #include <sys/rndsource.h> | 40 | #include <sys/rndsource.h> | |
41 | 41 | |||
42 | #include <dev/usb/usb.h> | 42 | #include <dev/usb/usb.h> | |
43 | #include <dev/usb/usbdevs.h> | 43 | #include <dev/usb/usbdevs.h> | |
44 | #include <dev/usb/usbdi.h> | 44 | #include <dev/usb/usbdi.h> | |
45 | #include <dev/usb/usbdi_util.h> | 45 | #include <dev/usb/usbdi_util.h> | |
46 | 46 | |||
47 | struct ualea_softc { | 47 | struct ualea_softc { | |
48 | device_t sc_dev; | 48 | device_t sc_dev; | |
49 | kmutex_t sc_lock; | 49 | kmutex_t sc_lock; | |
50 | krndsource_t sc_rnd; | 50 | krndsource_t sc_rnd; | |
51 | uint16_t sc_maxpktsize; | 51 | uint16_t sc_maxpktsize; | |
52 | struct usbd_pipe *sc_pipe; | 52 | struct usbd_pipe *sc_pipe; | |
53 | /* | 53 | /* | |
54 | * Lock covers: | 54 | * Lock covers: | |
55 | * - sc_needed | 55 | * - sc_needed | |
56 | * - sc_inflight | 56 | * - sc_inflight | |
57 | * - usbd_transfer(sc_xfer) | 57 | * - usbd_transfer(sc_xfer) | |
58 | */ | 58 | */ | |
59 | struct usbd_xfer *sc_xfer; | 59 | struct usbd_xfer *sc_xfer; | |
60 | size_t sc_needed; | 60 | size_t sc_needed; | |
61 | bool sc_attached:1; | 61 | bool sc_attached:1; | |
62 | bool sc_inflight:1; | 62 | bool sc_inflight:1; | |
63 | }; | 63 | }; | |
64 | 64 | |||
65 | static int ualea_match(device_t, cfdata_t, void *); | 65 | static int ualea_match(device_t, cfdata_t, void *); | |
66 | static void ualea_attach(device_t, device_t, void *); | 66 | static void ualea_attach(device_t, device_t, void *); | |
67 | static int ualea_detach(device_t, int); | 67 | static int ualea_detach(device_t, int); | |
68 | static void ualea_get(size_t, void *); | 68 | static void ualea_get(size_t, void *); | |
69 | static void ualea_xfer_done(struct usbd_xfer *, void *, usbd_status); | 69 | static void ualea_xfer_done(struct usbd_xfer *, void *, usbd_status); | |
70 | 70 | |||
71 | CFATTACH_DECL_NEW(ualea, sizeof(struct ualea_softc), | 71 | CFATTACH_DECL_NEW(ualea, sizeof(struct ualea_softc), | |
72 | ualea_match, ualea_attach, ualea_detach, NULL); | 72 | ualea_match, ualea_attach, ualea_detach, NULL); | |
73 | 73 | |||
74 | static const struct usb_devno ualea_devs[] = { | 74 | static const struct usb_devno ualea_devs[] = { | |
75 | { USB_VENDOR_ARANEUS, USB_PRODUCT_ARANEUS_ALEA }, | 75 | { USB_VENDOR_ARANEUS, USB_PRODUCT_ARANEUS_ALEA }, | |
76 | }; | 76 | }; | |
77 | 77 | |||
78 | static int | 78 | static int | |
79 | ualea_match(device_t parent, cfdata_t match, void *aux) | 79 | ualea_match(device_t parent, cfdata_t match, void *aux) | |
80 | { | 80 | { | |
81 | struct usbif_attach_arg *uiaa = aux; | 81 | struct usbif_attach_arg *uiaa = aux; | |
82 | 82 | |||
83 | if (usb_lookup(ualea_devs, uiaa->uiaa_vendor, uiaa->uiaa_product)) | 83 | if (usb_lookup(ualea_devs, uiaa->uiaa_vendor, uiaa->uiaa_product)) | |
84 | return UMATCH_VENDOR_PRODUCT; | 84 | return UMATCH_VENDOR_PRODUCT; | |
85 | 85 | |||
86 | return UMATCH_NONE; | 86 | return UMATCH_NONE; | |
87 | } | 87 | } | |
88 | 88 | |||
89 | static void | 89 | static void | |
90 | ualea_attach(device_t parent, device_t self, void *aux) | 90 | ualea_attach(device_t parent, device_t self, void *aux) | |
91 | { | 91 | { | |
92 | struct usbif_attach_arg *uiaa = aux; | 92 | struct usbif_attach_arg *uiaa = aux; | |
93 | struct ualea_softc *sc = device_private(self); | 93 | struct ualea_softc *sc = device_private(self); | |
94 | const usb_endpoint_descriptor_t *ed; | 94 | const usb_endpoint_descriptor_t *ed; | |
95 | char *devinfop; | 95 | char *devinfop; | |
96 | usbd_status status; | 96 | usbd_status status; | |
97 | 97 | |||
98 | /* Print the device info. */ | 98 | /* Print the device info. */ | |
99 | aprint_naive("\n"); | 99 | aprint_naive("\n"); | |
100 | aprint_normal("\n"); | 100 | aprint_normal("\n"); | |
101 | devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0); | 101 | devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0); | |
102 | aprint_normal_dev(self, "%s\n", devinfop); | 102 | aprint_normal_dev(self, "%s\n", devinfop); | |
103 | usbd_devinfo_free(devinfop); | 103 | usbd_devinfo_free(devinfop); | |
104 | 104 | |||
105 | /* Initialize the softc. */ | 105 | /* Initialize the softc. */ | |
106 | sc->sc_dev = self; | 106 | sc->sc_dev = self; | |
107 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | 107 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | |
108 | 108 | |||
109 | /* Get endpoint descriptor 0. Make sure it's bulk-in. */ | 109 | /* Get endpoint descriptor 0. Make sure it's bulk-in. */ | |
110 | ed = usbd_interface2endpoint_descriptor(uiaa->uiaa_iface, 0); | 110 | ed = usbd_interface2endpoint_descriptor(uiaa->uiaa_iface, 0); | |
111 | if (ed == NULL) { | 111 | if (ed == NULL) { | |
112 | aprint_error_dev(sc->sc_dev, "failed to read endpoint 0\n"); | 112 | aprint_error_dev(sc->sc_dev, "failed to read endpoint 0\n"); | |
113 | return; | 113 | return; | |
114 | } | 114 | } | |
115 | if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || | 115 | if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || | |
116 | UE_GET_XFERTYPE(ed->bmAttributes) != UE_BULK) { | 116 | UE_GET_XFERTYPE(ed->bmAttributes) != UE_BULK) { | |
117 | aprint_error_dev(sc->sc_dev, "invalid endpoint\n"); | 117 | aprint_error_dev(sc->sc_dev, "invalid endpoint\n"); | |
118 | return; | 118 | return; | |
119 | } | 119 | } | |
120 | 120 | |||
121 | /* Remember the maximum packet size. */ | 121 | /* Remember the maximum packet size. */ | |
122 | sc->sc_maxpktsize = UGETW(ed->wMaxPacketSize); | 122 | sc->sc_maxpktsize = UGETW(ed->wMaxPacketSize); | |
123 | 123 | |||
124 | /* Open an exclusive MP-safe pipe for endpoint 0. */ | 124 | /* Open an exclusive MP-safe pipe for endpoint 0. */ | |
125 | status = usbd_open_pipe(uiaa->uiaa_iface, ed->bEndpointAddress, | 125 | status = usbd_open_pipe(uiaa->uiaa_iface, ed->bEndpointAddress, | |
126 | USBD_EXCLUSIVE_USE|USBD_MPSAFE, &sc->sc_pipe); | 126 | USBD_EXCLUSIVE_USE|USBD_MPSAFE, &sc->sc_pipe); | |
127 | if (status) { | 127 | if (status) { | |
128 | aprint_error_dev(sc->sc_dev, "failed to open pipe: %d\n", | 128 | aprint_error_dev(sc->sc_dev, "failed to open pipe: %d\n", | |
129 | status); | 129 | status); | |
130 | return; | 130 | return; | |
131 | } | 131 | } | |
132 | 132 | |||
133 | /* Create an xfer of maximum packet size on the pipe. */ | 133 | /* Create an xfer of maximum packet size on the pipe. */ | |
134 | status = usbd_create_xfer(sc->sc_pipe, sc->sc_maxpktsize, | 134 | status = usbd_create_xfer(sc->sc_pipe, sc->sc_maxpktsize, | |
135 | 0, 0, &sc->sc_xfer); | 135 | 0, 0, &sc->sc_xfer); | |
136 | if (status) { | 136 | if (status) { | |
137 | aprint_error_dev(sc->sc_dev, "failed to create xfer: %d\n", | 137 | aprint_error_dev(sc->sc_dev, "failed to create xfer: %d\n", | |
138 | status); | 138 | status); | |
139 | return; | 139 | return; | |
140 | } | 140 | } | |
141 | 141 | |||
142 | if (!pmf_device_register(self, NULL, NULL)) | 142 | if (!pmf_device_register(self, NULL, NULL)) | |
143 | aprint_error_dev(sc->sc_dev, "failed to register power handler" | 143 | aprint_error_dev(sc->sc_dev, "failed to register power handler" | |
144 | "\n"); | 144 | "\n"); | |
145 | 145 | |||
146 | /* Success! We are ready to run. */ | 146 | /* Success! We are ready to run. */ | |
147 | sc->sc_attached = true; | 147 | sc->sc_attached = true; | |
148 | rndsource_setcb(&sc->sc_rnd, ualea_get, sc); | 148 | rndsource_setcb(&sc->sc_rnd, ualea_get, sc); | |
149 | rnd_attach_source(&sc->sc_rnd, device_xname(self), RND_TYPE_RNG, | 149 | rnd_attach_source(&sc->sc_rnd, device_xname(self), RND_TYPE_RNG, | |
150 | RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB); | 150 | RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB); | |
151 | } | 151 | } | |
152 | 152 | |||
153 | static int | 153 | static int | |
154 | ualea_detach(device_t self, int flags) | 154 | ualea_detach(device_t self, int flags) | |
155 | { | 155 | { | |
156 | struct ualea_softc *sc = device_private(self); | 156 | struct ualea_softc *sc = device_private(self); | |
157 | 157 | |||
158 | /* Prevent new use of xfer. */ | 158 | /* Prevent new use of xfer. */ | |
159 | if (sc->sc_attached) | 159 | if (sc->sc_attached) | |
160 | rnd_detach_source(&sc->sc_rnd); | 160 | rnd_detach_source(&sc->sc_rnd); | |
161 | 161 | |||
162 | /* Cancel pending xfer. */ | 162 | /* Cancel pending xfer. */ | |
163 | if (sc->sc_pipe) | 163 | if (sc->sc_pipe) | |
164 | (void)usbd_abort_pipe(sc->sc_pipe); | 164 | usbd_abort_pipe(sc->sc_pipe); | |
165 | KASSERT(!sc->sc_inflight); | 165 | KASSERT(!sc->sc_inflight); | |
166 | 166 | |||
167 | /* All users have drained. Tear it all down. */ | 167 | /* All users have drained. Tear it all down. */ | |
168 | if (sc->sc_xfer) | 168 | if (sc->sc_xfer) | |
169 | usbd_destroy_xfer(sc->sc_xfer); | 169 | usbd_destroy_xfer(sc->sc_xfer); | |
170 | if (sc->sc_pipe) | 170 | if (sc->sc_pipe) | |
171 | (void)usbd_close_pipe(sc->sc_pipe); | 171 | (void)usbd_close_pipe(sc->sc_pipe); | |
172 | mutex_destroy(&sc->sc_lock); | 172 | mutex_destroy(&sc->sc_lock); | |
173 | 173 | |||
174 | return 0; | 174 | return 0; | |
175 | } | 175 | } | |
176 | 176 | |||
177 | static void | 177 | static void | |
178 | ualea_xfer(struct ualea_softc *sc) | 178 | ualea_xfer(struct ualea_softc *sc) | |
179 | { | 179 | { | |
180 | usbd_status status; | 180 | usbd_status status; | |
181 | 181 | |||
182 | KASSERT(mutex_owned(&sc->sc_lock)); | 182 | KASSERT(mutex_owned(&sc->sc_lock)); | |
183 | KASSERT(sc->sc_attached); | 183 | KASSERT(sc->sc_attached); | |
184 | KASSERT(!sc->sc_inflight); | 184 | KASSERT(!sc->sc_inflight); | |
185 | 185 | |||
186 | /* Do nothing if we need nothing. */ | 186 | /* Do nothing if we need nothing. */ | |
187 | if (sc->sc_needed == 0) | 187 | if (sc->sc_needed == 0) | |
188 | return; | 188 | return; | |
189 | 189 | |||
190 | /* Setup the xfer to call ualea_xfer_done with sc. */ | 190 | /* Setup the xfer to call ualea_xfer_done with sc. */ | |
191 | usbd_setup_xfer(sc->sc_xfer, sc, usbd_get_buffer(sc->sc_xfer), | 191 | usbd_setup_xfer(sc->sc_xfer, sc, usbd_get_buffer(sc->sc_xfer), | |
192 | sc->sc_maxpktsize, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, | 192 | sc->sc_maxpktsize, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, | |
193 | ualea_xfer_done); | 193 | ualea_xfer_done); | |
194 | 194 | |||
195 | /* Issue xfer or complain if we can't. */ | 195 | /* Issue xfer or complain if we can't. */ | |
196 | status = usbd_transfer(sc->sc_xfer); | 196 | status = usbd_transfer(sc->sc_xfer); | |
197 | KASSERT(status != USBD_NORMAL_COMPLETION); /* asynchronous xfer */ | 197 | KASSERT(status != USBD_NORMAL_COMPLETION); /* asynchronous xfer */ | |
198 | if (status != USBD_IN_PROGRESS) { | 198 | if (status != USBD_IN_PROGRESS) { | |
199 | aprint_error_dev(sc->sc_dev, "failed to issue xfer: %d\n", | 199 | aprint_error_dev(sc->sc_dev, "failed to issue xfer: %d\n", | |
200 | status); | 200 | status); | |
201 | /* We failed -- let someone else have a go. */ | 201 | /* We failed -- let someone else have a go. */ | |
202 | return; | 202 | return; | |
203 | } | 203 | } | |
204 | 204 | |||
205 | /* Mark xfer in-flight. */ | 205 | /* Mark xfer in-flight. */ | |
206 | sc->sc_inflight = true; | 206 | sc->sc_inflight = true; | |
207 | } | 207 | } | |
208 | 208 | |||
209 | static void | 209 | static void | |
210 | ualea_get(size_t nbytes, void *cookie) | 210 | ualea_get(size_t nbytes, void *cookie) | |
211 | { | 211 | { | |
212 | struct ualea_softc *sc = cookie; | 212 | struct ualea_softc *sc = cookie; | |
213 | 213 | |||
214 | mutex_enter(&sc->sc_lock); | 214 | mutex_enter(&sc->sc_lock); | |
215 | sc->sc_needed = MAX(sc->sc_needed, nbytes); | 215 | sc->sc_needed = MAX(sc->sc_needed, nbytes); | |
216 | if (!sc->sc_inflight) | 216 | if (!sc->sc_inflight) | |
217 | ualea_xfer(sc); | 217 | ualea_xfer(sc); | |
218 | mutex_exit(&sc->sc_lock); | 218 | mutex_exit(&sc->sc_lock); | |
219 | } | 219 | } | |
220 | 220 | |||
221 | static void | 221 | static void | |
222 | ualea_xfer_done(struct usbd_xfer *xfer, void *cookie, usbd_status status) | 222 | ualea_xfer_done(struct usbd_xfer *xfer, void *cookie, usbd_status status) | |
223 | { | 223 | { | |
224 | struct ualea_softc *sc = cookie; | 224 | struct ualea_softc *sc = cookie; | |
225 | void *pkt; | 225 | void *pkt; | |
226 | uint32_t pktsize; | 226 | uint32_t pktsize; | |
227 | 227 | |||
228 | /* Check the transfer status. */ | 228 | /* Check the transfer status. */ | |
229 | if (status) { | 229 | if (status) { | |
230 | aprint_error_dev(sc->sc_dev, "xfer failed: %d\n", status); | 230 | aprint_error_dev(sc->sc_dev, "xfer failed: %d\n", status); | |
231 | return; | 231 | return; | |
232 | } | 232 | } | |
233 | 233 | |||
234 | /* Get and sanity-check the transferred size. */ | 234 | /* Get and sanity-check the transferred size. */ | |
235 | usbd_get_xfer_status(xfer, NULL, &pkt, &pktsize, NULL); | 235 | usbd_get_xfer_status(xfer, NULL, &pkt, &pktsize, NULL); | |
236 | if (pktsize > sc->sc_maxpktsize) { | 236 | if (pktsize > sc->sc_maxpktsize) { | |
237 | aprint_error_dev(sc->sc_dev, | 237 | aprint_error_dev(sc->sc_dev, | |
238 | "bogus packet size: %"PRIu32" > %"PRIu16" (max), ignoring" | 238 | "bogus packet size: %"PRIu32" > %"PRIu16" (max), ignoring" | |
239 | "\n", | 239 | "\n", | |
240 | pktsize, sc->sc_maxpktsize); | 240 | pktsize, sc->sc_maxpktsize); | |
241 | goto out; | 241 | goto out; | |
242 | } | 242 | } | |
243 | 243 | |||
244 | /* Add the data to the pool. */ | 244 | /* Add the data to the pool. */ | |
245 | rnd_add_data(&sc->sc_rnd, pkt, pktsize, NBBY*pktsize); | 245 | rnd_add_data(&sc->sc_rnd, pkt, pktsize, NBBY*pktsize); | |
246 | 246 | |||
247 | out: | 247 | out: | |
248 | mutex_enter(&sc->sc_lock); | 248 | mutex_enter(&sc->sc_lock); | |
249 | 249 | |||
250 | /* Debit what we contributed from what we need. */ | 250 | /* Debit what we contributed from what we need. */ | |
251 | sc->sc_needed -= MIN(sc->sc_needed, pktsize); | 251 | sc->sc_needed -= MIN(sc->sc_needed, pktsize); | |
252 | 252 | |||
253 | /* Mark xfer done. */ | 253 | /* Mark xfer done. */ | |
254 | sc->sc_inflight = false; | 254 | sc->sc_inflight = false; | |
255 | 255 | |||
256 | /* Reissue xfer if we still need more. */ | 256 | /* Reissue xfer if we still need more. */ | |
257 | ualea_xfer(sc); | 257 | ualea_xfer(sc); | |
258 | 258 | |||
259 | mutex_exit(&sc->sc_lock); | 259 | mutex_exit(&sc->sc_lock); | |
260 | } | 260 | } | |
261 | 261 | |||
262 | MODULE(MODULE_CLASS_DRIVER, ualea, NULL); | 262 | MODULE(MODULE_CLASS_DRIVER, ualea, NULL); | |
263 | 263 | |||
264 | #ifdef _MODULE | 264 | #ifdef _MODULE | |
265 | #include "ioconf.c" | 265 | #include "ioconf.c" | |
266 | #endif | 266 | #endif | |
267 | 267 | |||
268 | static int | 268 | static int | |
269 | ualea_modcmd(modcmd_t cmd, void *aux) | 269 | ualea_modcmd(modcmd_t cmd, void *aux) | |
270 | { | 270 | { | |
271 | int error = 0; | 271 | int error = 0; | |
272 | 272 | |||
273 | switch (cmd) { | 273 | switch (cmd) { | |
274 | case MODULE_CMD_INIT: | 274 | case MODULE_CMD_INIT: | |
275 | #ifdef _MODULE | 275 | #ifdef _MODULE | |
276 | error = config_init_component(cfdriver_ioconf_ualea, | 276 | error = config_init_component(cfdriver_ioconf_ualea, | |
277 | cfattach_ioconf_ualea, cfdata_ioconf_ualea); | 277 | cfattach_ioconf_ualea, cfdata_ioconf_ualea); | |
278 | #endif | 278 | #endif | |
279 | return error; | 279 | return error; | |
280 | case MODULE_CMD_FINI: | 280 | case MODULE_CMD_FINI: | |
281 | #ifdef _MODULE | 281 | #ifdef _MODULE | |
282 | error = config_fini_component(cfdriver_ioconf_ualea, | 282 | error = config_fini_component(cfdriver_ioconf_ualea, | |
283 | cfattach_ioconf_ualea, cfdata_ioconf_ualea); | 283 | cfattach_ioconf_ualea, cfdata_ioconf_ualea); | |
284 | #endif | 284 | #endif | |
285 | return error; | 285 | return error; | |
286 | default: | 286 | default: | |
287 | return ENOTTY; | 287 | return ENOTTY; | |
288 | } | 288 | } | |
289 | } | 289 | } |
--- src/sys/dev/usb/usbdi.c 2022/03/03 06:04:31 1.223
+++ src/sys/dev/usb/usbdi.c 2022/03/03 06:05:38 1.224
@@ -1,1842 +1,1839 @@ | @@ -1,1842 +1,1839 @@ | |||
1 | /* $NetBSD: usbdi.c,v 1.223 2022/03/03 06:04:31 riastradh Exp $ */ | 1 | /* $NetBSD: usbdi.c,v 1.224 2022/03/03 06:05:38 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology, Matthew R. Green (mrg@eterna.com.au), | 9 | * Carlstedt Research & Technology, Matthew R. Green (mrg@eterna.com.au), | |
10 | * and Nick Hudson. | 10 | * and Nick Hudson. | |
11 | * | 11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | 14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | 15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | 16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | 17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | 18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | 19 | * documentation and/or other materials provided with the distribution. | |
20 | * | 20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | * POSSIBILITY OF SUCH DAMAGE. | 31 | * POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | 32 | */ | |
33 | 33 | |||
34 | #include <sys/cdefs.h> | 34 | #include <sys/cdefs.h> | |
35 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.223 2022/03/03 06:04:31 riastradh Exp $"); | 35 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.224 2022/03/03 06:05:38 riastradh Exp $"); | |
36 | 36 | |||
37 | #ifdef _KERNEL_OPT | 37 | #ifdef _KERNEL_OPT | |
38 | #include "opt_usb.h" | 38 | #include "opt_usb.h" | |
39 | #include "opt_compat_netbsd.h" | 39 | #include "opt_compat_netbsd.h" | |
40 | #include "usb_dma.h" | 40 | #include "usb_dma.h" | |
41 | #endif | 41 | #endif | |
42 | 42 | |||
43 | #include <sys/param.h> | 43 | #include <sys/param.h> | |
44 | #include <sys/systm.h> | 44 | #include <sys/systm.h> | |
45 | #include <sys/kernel.h> | 45 | #include <sys/kernel.h> | |
46 | #include <sys/device.h> | 46 | #include <sys/device.h> | |
47 | #include <sys/kmem.h> | 47 | #include <sys/kmem.h> | |
48 | #include <sys/proc.h> | 48 | #include <sys/proc.h> | |
49 | #include <sys/bus.h> | 49 | #include <sys/bus.h> | |
50 | #include <sys/cpu.h> | 50 | #include <sys/cpu.h> | |
51 | 51 | |||
52 | #include <dev/usb/usb.h> | 52 | #include <dev/usb/usb.h> | |
53 | #include <dev/usb/usbdi.h> | 53 | #include <dev/usb/usbdi.h> | |
54 | #include <dev/usb/usbdi_util.h> | 54 | #include <dev/usb/usbdi_util.h> | |
55 | #include <dev/usb/usbdivar.h> | 55 | #include <dev/usb/usbdivar.h> | |
56 | #include <dev/usb/usb_mem.h> | 56 | #include <dev/usb/usb_mem.h> | |
57 | #include <dev/usb/usb_quirks.h> | 57 | #include <dev/usb/usb_quirks.h> | |
58 | #include <dev/usb/usb_sdt.h> | 58 | #include <dev/usb/usb_sdt.h> | |
59 | #include <dev/usb/usbhist.h> | 59 | #include <dev/usb/usbhist.h> | |
60 | 60 | |||
61 | /* UTF-8 encoding stuff */ | 61 | /* UTF-8 encoding stuff */ | |
62 | #include <fs/unicode.h> | 62 | #include <fs/unicode.h> | |
63 | 63 | |||
64 | SDT_PROBE_DEFINE5(usb, device, pipe, open, | 64 | SDT_PROBE_DEFINE5(usb, device, pipe, open, | |
65 | "struct usbd_interface *"/*iface*/, | 65 | "struct usbd_interface *"/*iface*/, | |
66 | "uint8_t"/*address*/, | 66 | "uint8_t"/*address*/, | |
67 | "uint8_t"/*flags*/, | 67 | "uint8_t"/*flags*/, | |
68 | "int"/*ival*/, | 68 | "int"/*ival*/, | |
69 | "struct usbd_pipe *"/*pipe*/); | 69 | "struct usbd_pipe *"/*pipe*/); | |
70 | 70 | |||
71 | SDT_PROBE_DEFINE7(usb, device, pipe, open__intr, | 71 | SDT_PROBE_DEFINE7(usb, device, pipe, open__intr, | |
72 | "struct usbd_interface *"/*iface*/, | 72 | "struct usbd_interface *"/*iface*/, | |
73 | "uint8_t"/*address*/, | 73 | "uint8_t"/*address*/, | |
74 | "uint8_t"/*flags*/, | 74 | "uint8_t"/*flags*/, | |
75 | "int"/*ival*/, | 75 | "int"/*ival*/, | |
76 | "usbd_callback"/*cb*/, | 76 | "usbd_callback"/*cb*/, | |
77 | "void *"/*cookie*/, | 77 | "void *"/*cookie*/, | |
78 | "struct usbd_pipe *"/*pipe*/); | 78 | "struct usbd_pipe *"/*pipe*/); | |
79 | 79 | |||
80 | SDT_PROBE_DEFINE2(usb, device, pipe, transfer__start, | 80 | SDT_PROBE_DEFINE2(usb, device, pipe, transfer__start, | |
81 | "struct usbd_pipe *"/*pipe*/, | 81 | "struct usbd_pipe *"/*pipe*/, | |
82 | "struct usbd_xfer *"/*xfer*/); | 82 | "struct usbd_xfer *"/*xfer*/); | |
83 | SDT_PROBE_DEFINE3(usb, device, pipe, transfer__done, | 83 | SDT_PROBE_DEFINE3(usb, device, pipe, transfer__done, | |
84 | "struct usbd_pipe *"/*pipe*/, | 84 | "struct usbd_pipe *"/*pipe*/, | |
85 | "struct usbd_xfer *"/*xfer*/, | 85 | "struct usbd_xfer *"/*xfer*/, | |
86 | "usbd_status"/*err*/); | 86 | "usbd_status"/*err*/); | |
87 | SDT_PROBE_DEFINE2(usb, device, pipe, start, | 87 | SDT_PROBE_DEFINE2(usb, device, pipe, start, | |
88 | "struct usbd_pipe *"/*pipe*/, | 88 | "struct usbd_pipe *"/*pipe*/, | |
89 | "struct usbd_xfer *"/*xfer*/); | 89 | "struct usbd_xfer *"/*xfer*/); | |
90 | 90 | |||
91 | SDT_PROBE_DEFINE1(usb, device, pipe, close, "struct usbd_pipe *"/*pipe*/); | 91 | SDT_PROBE_DEFINE1(usb, device, pipe, close, "struct usbd_pipe *"/*pipe*/); | |
92 | SDT_PROBE_DEFINE1(usb, device, pipe, abort__start, | 92 | SDT_PROBE_DEFINE1(usb, device, pipe, abort__start, | |
93 | "struct usbd_pipe *"/*pipe*/); | 93 | "struct usbd_pipe *"/*pipe*/); | |
94 | SDT_PROBE_DEFINE1(usb, device, pipe, abort__done, | 94 | SDT_PROBE_DEFINE1(usb, device, pipe, abort__done, | |
95 | "struct usbd_pipe *"/*pipe*/); | 95 | "struct usbd_pipe *"/*pipe*/); | |
96 | SDT_PROBE_DEFINE1(usb, device, pipe, clear__endpoint__stall, | 96 | SDT_PROBE_DEFINE1(usb, device, pipe, clear__endpoint__stall, | |
97 | "struct usbd_pipe *"/*pipe*/); | 97 | "struct usbd_pipe *"/*pipe*/); | |
98 | SDT_PROBE_DEFINE1(usb, device, pipe, clear__endpoint__toggle, | 98 | SDT_PROBE_DEFINE1(usb, device, pipe, clear__endpoint__toggle, | |
99 | "struct usbd_pipe *"/*pipe*/); | 99 | "struct usbd_pipe *"/*pipe*/); | |
100 | 100 | |||
101 | SDT_PROBE_DEFINE5(usb, device, xfer, create, | 101 | SDT_PROBE_DEFINE5(usb, device, xfer, create, | |
102 | "struct usbd_xfer *"/*xfer*/, | 102 | "struct usbd_xfer *"/*xfer*/, | |
103 | "struct usbd_pipe *"/*pipe*/, | 103 | "struct usbd_pipe *"/*pipe*/, | |
104 | "size_t"/*len*/, | 104 | "size_t"/*len*/, | |
105 | "unsigned int"/*flags*/, | 105 | "unsigned int"/*flags*/, | |
106 | "unsigned int"/*nframes*/); | 106 | "unsigned int"/*nframes*/); | |
107 | SDT_PROBE_DEFINE1(usb, device, xfer, start, "struct usbd_xfer *"/*xfer*/); | 107 | SDT_PROBE_DEFINE1(usb, device, xfer, start, "struct usbd_xfer *"/*xfer*/); | |
108 | SDT_PROBE_DEFINE1(usb, device, xfer, preabort, "struct usbd_xfer *"/*xfer*/); | 108 | SDT_PROBE_DEFINE1(usb, device, xfer, preabort, "struct usbd_xfer *"/*xfer*/); | |
109 | SDT_PROBE_DEFINE1(usb, device, xfer, abort, "struct usbd_xfer *"/*xfer*/); | 109 | SDT_PROBE_DEFINE1(usb, device, xfer, abort, "struct usbd_xfer *"/*xfer*/); | |
110 | SDT_PROBE_DEFINE1(usb, device, xfer, timeout, "struct usbd_xfer *"/*xfer*/); | 110 | SDT_PROBE_DEFINE1(usb, device, xfer, timeout, "struct usbd_xfer *"/*xfer*/); | |
111 | SDT_PROBE_DEFINE2(usb, device, xfer, done, | 111 | SDT_PROBE_DEFINE2(usb, device, xfer, done, | |
112 | "struct usbd_xfer *"/*xfer*/, | 112 | "struct usbd_xfer *"/*xfer*/, | |
113 | "usbd_status"/*status*/); | 113 | "usbd_status"/*status*/); | |
114 | SDT_PROBE_DEFINE1(usb, device, xfer, destroy, "struct usbd_xfer *"/*xfer*/); | 114 | SDT_PROBE_DEFINE1(usb, device, xfer, destroy, "struct usbd_xfer *"/*xfer*/); | |
115 | 115 | |||
116 | Static usbd_status usbd_ar_pipe(struct usbd_pipe *); | 116 | Static void usbd_ar_pipe(struct usbd_pipe *); | |
117 | static usbd_status usb_insert_transfer(struct usbd_xfer *); | 117 | static usbd_status usb_insert_transfer(struct usbd_xfer *); | |
118 | Static void usbd_start_next(struct usbd_pipe *); | 118 | Static void usbd_start_next(struct usbd_pipe *); | |
119 | Static usbd_status usbd_open_pipe_ival | 119 | Static usbd_status usbd_open_pipe_ival | |
120 | (struct usbd_interface *, uint8_t, uint8_t, struct usbd_pipe **, int); | 120 | (struct usbd_interface *, uint8_t, uint8_t, struct usbd_pipe **, int); | |
121 | static void *usbd_alloc_buffer(struct usbd_xfer *, uint32_t); | 121 | static void *usbd_alloc_buffer(struct usbd_xfer *, uint32_t); | |
122 | static void usbd_free_buffer(struct usbd_xfer *); | 122 | static void usbd_free_buffer(struct usbd_xfer *); | |
123 | static struct usbd_xfer *usbd_alloc_xfer(struct usbd_device *, unsigned int); | 123 | static struct usbd_xfer *usbd_alloc_xfer(struct usbd_device *, unsigned int); | |
124 | static usbd_status usbd_free_xfer(struct usbd_xfer *); | 124 | static usbd_status usbd_free_xfer(struct usbd_xfer *); | |
125 | static void usbd_request_async_cb(struct usbd_xfer *, void *, usbd_status); | 125 | static void usbd_request_async_cb(struct usbd_xfer *, void *, usbd_status); | |
126 | static void usbd_xfer_timeout(void *); | 126 | static void usbd_xfer_timeout(void *); | |
127 | static void usbd_xfer_timeout_task(void *); | 127 | static void usbd_xfer_timeout_task(void *); | |
128 | static bool usbd_xfer_probe_timeout(struct usbd_xfer *); | 128 | static bool usbd_xfer_probe_timeout(struct usbd_xfer *); | |
129 | static void usbd_xfer_cancel_timeout_async(struct usbd_xfer *); | 129 | static void usbd_xfer_cancel_timeout_async(struct usbd_xfer *); | |
130 | 130 | |||
131 | #if defined(USB_DEBUG) | 131 | #if defined(USB_DEBUG) | |
132 | void | 132 | void | |
133 | usbd_dump_iface(struct usbd_interface *iface) | 133 | usbd_dump_iface(struct usbd_interface *iface) | |
134 | { | 134 | { | |
135 | USBHIST_FUNC(); | 135 | USBHIST_FUNC(); | |
136 | USBHIST_CALLARGS(usbdebug, "iface %#jx", (uintptr_t)iface, 0, 0, 0); | 136 | USBHIST_CALLARGS(usbdebug, "iface %#jx", (uintptr_t)iface, 0, 0, 0); | |
137 | 137 | |||
138 | if (iface == NULL) | 138 | if (iface == NULL) | |
139 | return; | 139 | return; | |
140 | USBHIST_LOG(usbdebug, " device = %#jx idesc = %#jx index = %jd", | 140 | USBHIST_LOG(usbdebug, " device = %#jx idesc = %#jx index = %jd", | |
141 | (uintptr_t)iface->ui_dev, (uintptr_t)iface->ui_idesc, | 141 | (uintptr_t)iface->ui_dev, (uintptr_t)iface->ui_idesc, | |
142 | iface->ui_index, 0); | 142 | iface->ui_index, 0); | |
143 | USBHIST_LOG(usbdebug, " altindex=%jd", | 143 | USBHIST_LOG(usbdebug, " altindex=%jd", | |
144 | iface->ui_altindex, 0, 0, 0); | 144 | iface->ui_altindex, 0, 0, 0); | |
145 | } | 145 | } | |
146 | 146 | |||
147 | void | 147 | void | |
148 | usbd_dump_device(struct usbd_device *dev) | 148 | usbd_dump_device(struct usbd_device *dev) | |
149 | { | 149 | { | |
150 | USBHIST_FUNC(); | 150 | USBHIST_FUNC(); | |
151 | USBHIST_CALLARGS(usbdebug, "dev = %#jx", (uintptr_t)dev, 0, 0, 0); | 151 | USBHIST_CALLARGS(usbdebug, "dev = %#jx", (uintptr_t)dev, 0, 0, 0); | |
152 | 152 | |||
153 | if (dev == NULL) | 153 | if (dev == NULL) | |
154 | return; | 154 | return; | |
155 | USBHIST_LOG(usbdebug, " bus = %#jx default_pipe = %#jx", | 155 | USBHIST_LOG(usbdebug, " bus = %#jx default_pipe = %#jx", | |
156 | (uintptr_t)dev->ud_bus, (uintptr_t)dev->ud_pipe0, 0, 0); | 156 | (uintptr_t)dev->ud_bus, (uintptr_t)dev->ud_pipe0, 0, 0); | |
157 | USBHIST_LOG(usbdebug, " address = %jd config = %jd depth = %jd ", | 157 | USBHIST_LOG(usbdebug, " address = %jd config = %jd depth = %jd ", | |
158 | dev->ud_addr, dev->ud_config, dev->ud_depth, 0); | 158 | dev->ud_addr, dev->ud_config, dev->ud_depth, 0); | |
159 | USBHIST_LOG(usbdebug, " speed = %jd self_powered = %jd " | 159 | USBHIST_LOG(usbdebug, " speed = %jd self_powered = %jd " | |
160 | "power = %jd langid = %jd", | 160 | "power = %jd langid = %jd", | |
161 | dev->ud_speed, dev->ud_selfpowered, dev->ud_power, dev->ud_langid); | 161 | dev->ud_speed, dev->ud_selfpowered, dev->ud_power, dev->ud_langid); | |
162 | } | 162 | } | |
163 | 163 | |||
164 | void | 164 | void | |
165 | usbd_dump_endpoint(struct usbd_endpoint *endp) | 165 | usbd_dump_endpoint(struct usbd_endpoint *endp) | |
166 | { | 166 | { | |
167 | USBHIST_FUNC(); | 167 | USBHIST_FUNC(); | |
168 | USBHIST_CALLARGS(usbdebug, "endp = %#jx", (uintptr_t)endp, 0, 0, 0); | 168 | USBHIST_CALLARGS(usbdebug, "endp = %#jx", (uintptr_t)endp, 0, 0, 0); | |
169 | 169 | |||
170 | if (endp == NULL) | 170 | if (endp == NULL) | |
171 | return; | 171 | return; | |
172 | USBHIST_LOG(usbdebug, " edesc = %#jx refcnt = %jd", | 172 | USBHIST_LOG(usbdebug, " edesc = %#jx refcnt = %jd", | |
173 | (uintptr_t)endp->ue_edesc, endp->ue_refcnt, 0, 0); | 173 | (uintptr_t)endp->ue_edesc, endp->ue_refcnt, 0, 0); | |
174 | if (endp->ue_edesc) | 174 | if (endp->ue_edesc) | |
175 | USBHIST_LOG(usbdebug, " bEndpointAddress=0x%02jx", | 175 | USBHIST_LOG(usbdebug, " bEndpointAddress=0x%02jx", | |
176 | endp->ue_edesc->bEndpointAddress, 0, 0, 0); | 176 | endp->ue_edesc->bEndpointAddress, 0, 0, 0); | |
177 | } | 177 | } | |
178 | 178 | |||
179 | void | 179 | void | |
180 | usbd_dump_queue(struct usbd_pipe *pipe) | 180 | usbd_dump_queue(struct usbd_pipe *pipe) | |
181 | { | 181 | { | |
182 | struct usbd_xfer *xfer; | 182 | struct usbd_xfer *xfer; | |
183 | 183 | |||
184 | USBHIST_FUNC(); | 184 | USBHIST_FUNC(); | |
185 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx", (uintptr_t)pipe, 0, 0, 0); | 185 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx", (uintptr_t)pipe, 0, 0, 0); | |
186 | 186 | |||
187 | SIMPLEQ_FOREACH(xfer, &pipe->up_queue, ux_next) { | 187 | SIMPLEQ_FOREACH(xfer, &pipe->up_queue, ux_next) { | |
188 | USBHIST_LOG(usbdebug, " xfer = %#jx", (uintptr_t)xfer, | 188 | USBHIST_LOG(usbdebug, " xfer = %#jx", (uintptr_t)xfer, | |
189 | 0, 0, 0); | 189 | 0, 0, 0); | |
190 | } | 190 | } | |
191 | } | 191 | } | |
192 | 192 | |||
193 | void | 193 | void | |
194 | usbd_dump_pipe(struct usbd_pipe *pipe) | 194 | usbd_dump_pipe(struct usbd_pipe *pipe) | |
195 | { | 195 | { | |
196 | USBHIST_FUNC(); | 196 | USBHIST_FUNC(); | |
197 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx", (uintptr_t)pipe, 0, 0, 0); | 197 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx", (uintptr_t)pipe, 0, 0, 0); | |
198 | 198 | |||
199 | if (pipe == NULL) | 199 | if (pipe == NULL) | |
200 | return; | 200 | return; | |
201 | usbd_dump_iface(pipe->up_iface); | 201 | usbd_dump_iface(pipe->up_iface); | |
202 | usbd_dump_device(pipe->up_dev); | 202 | usbd_dump_device(pipe->up_dev); | |
203 | usbd_dump_endpoint(pipe->up_endpoint); | 203 | usbd_dump_endpoint(pipe->up_endpoint); | |
204 | USBHIST_LOG(usbdebug, "(usbd_dump_pipe)", 0, 0, 0, 0); | 204 | USBHIST_LOG(usbdebug, "(usbd_dump_pipe)", 0, 0, 0, 0); | |
205 | USBHIST_LOG(usbdebug, " running = %jd aborting = %jd", | 205 | USBHIST_LOG(usbdebug, " running = %jd aborting = %jd", | |
206 | pipe->up_running, pipe->up_aborting, 0, 0); | 206 | pipe->up_running, pipe->up_aborting, 0, 0); | |
207 | USBHIST_LOG(usbdebug, " intrxfer = %#jx, repeat = %jd, " | 207 | USBHIST_LOG(usbdebug, " intrxfer = %#jx, repeat = %jd, " | |
208 | "interval = %jd", (uintptr_t)pipe->up_intrxfer, pipe->up_repeat, | 208 | "interval = %jd", (uintptr_t)pipe->up_intrxfer, pipe->up_repeat, | |
209 | pipe->up_interval, 0); | 209 | pipe->up_interval, 0); | |
210 | } | 210 | } | |
211 | #endif | 211 | #endif | |
212 | 212 | |||
213 | usbd_status | 213 | usbd_status | |
214 | usbd_open_pipe(struct usbd_interface *iface, uint8_t address, | 214 | usbd_open_pipe(struct usbd_interface *iface, uint8_t address, | |
215 | uint8_t flags, struct usbd_pipe **pipe) | 215 | uint8_t flags, struct usbd_pipe **pipe) | |
216 | { | 216 | { | |
217 | return (usbd_open_pipe_ival(iface, address, flags, pipe, | 217 | return (usbd_open_pipe_ival(iface, address, flags, pipe, | |
218 | USBD_DEFAULT_INTERVAL)); | 218 | USBD_DEFAULT_INTERVAL)); | |
219 | } | 219 | } | |
220 | 220 | |||
221 | usbd_status | 221 | usbd_status | |
222 | usbd_open_pipe_ival(struct usbd_interface *iface, uint8_t address, | 222 | usbd_open_pipe_ival(struct usbd_interface *iface, uint8_t address, | |
223 | uint8_t flags, struct usbd_pipe **pipe, int ival) | 223 | uint8_t flags, struct usbd_pipe **pipe, int ival) | |
224 | { | 224 | { | |
225 | struct usbd_pipe *p = NULL; | 225 | struct usbd_pipe *p = NULL; | |
226 | struct usbd_endpoint *ep = NULL /* XXXGCC */; | 226 | struct usbd_endpoint *ep = NULL /* XXXGCC */; | |
227 | bool piperef = false; | 227 | bool piperef = false; | |
228 | usbd_status err; | 228 | usbd_status err; | |
229 | int i; | 229 | int i; | |
230 | 230 | |||
231 | USBHIST_FUNC(); | 231 | USBHIST_FUNC(); | |
232 | USBHIST_CALLARGS(usbdebug, "iface = %#jx address = %#jx flags = %#jx", | 232 | USBHIST_CALLARGS(usbdebug, "iface = %#jx address = %#jx flags = %#jx", | |
233 | (uintptr_t)iface, address, flags, 0); | 233 | (uintptr_t)iface, address, flags, 0); | |
234 | 234 | |||
235 | /* | 235 | /* | |
236 | * Block usbd_set_interface so we have a snapshot of the | 236 | * Block usbd_set_interface so we have a snapshot of the | |
237 | * interface endpoints. They will remain stable until we drop | 237 | * interface endpoints. They will remain stable until we drop | |
238 | * the reference in usbd_close_pipe (or on failure here). | 238 | * the reference in usbd_close_pipe (or on failure here). | |
239 | */ | 239 | */ | |
240 | err = usbd_iface_piperef(iface); | 240 | err = usbd_iface_piperef(iface); | |
241 | if (err) | 241 | if (err) | |
242 | goto out; | 242 | goto out; | |
243 | piperef = true; | 243 | piperef = true; | |
244 | 244 | |||
245 | /* Find the endpoint at this address. */ | 245 | /* Find the endpoint at this address. */ | |
246 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { | 246 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { | |
247 | ep = &iface->ui_endpoints[i]; | 247 | ep = &iface->ui_endpoints[i]; | |
248 | if (ep->ue_edesc == NULL) { | 248 | if (ep->ue_edesc == NULL) { | |
249 | err = USBD_IOERROR; | 249 | err = USBD_IOERROR; | |
250 | goto out; | 250 | goto out; | |
251 | } | 251 | } | |
252 | if (ep->ue_edesc->bEndpointAddress == address) | 252 | if (ep->ue_edesc->bEndpointAddress == address) | |
253 | break; | 253 | break; | |
254 | } | 254 | } | |
255 | if (i == iface->ui_idesc->bNumEndpoints) { | 255 | if (i == iface->ui_idesc->bNumEndpoints) { | |
256 | err = USBD_BAD_ADDRESS; | 256 | err = USBD_BAD_ADDRESS; | |
257 | goto out; | 257 | goto out; | |
258 | } | 258 | } | |
259 | 259 | |||
260 | /* Set up the pipe with this endpoint. */ | 260 | /* Set up the pipe with this endpoint. */ | |
261 | err = usbd_setup_pipe_flags(iface->ui_dev, iface, ep, ival, &p, flags); | 261 | err = usbd_setup_pipe_flags(iface->ui_dev, iface, ep, ival, &p, flags); | |
262 | if (err) | 262 | if (err) | |
263 | goto out; | 263 | goto out; | |
264 | 264 | |||
265 | /* Success! */ | 265 | /* Success! */ | |
266 | *pipe = p; | 266 | *pipe = p; | |
267 | p = NULL; /* handed off to caller */ | 267 | p = NULL; /* handed off to caller */ | |
268 | piperef = false; /* handed off to pipe */ | 268 | piperef = false; /* handed off to pipe */ | |
269 | SDT_PROBE5(usb, device, pipe, open, | 269 | SDT_PROBE5(usb, device, pipe, open, | |
270 | iface, address, flags, ival, p); | 270 | iface, address, flags, ival, p); | |
271 | err = USBD_NORMAL_COMPLETION; | 271 | err = USBD_NORMAL_COMPLETION; | |
272 | 272 | |||
273 | out: if (p) | 273 | out: if (p) | |
274 | usbd_close_pipe(p); | 274 | usbd_close_pipe(p); | |
275 | if (piperef) | 275 | if (piperef) | |
276 | usbd_iface_pipeunref(iface); | 276 | usbd_iface_pipeunref(iface); | |
277 | return err; | 277 | return err; | |
278 | } | 278 | } | |
279 | 279 | |||
280 | usbd_status | 280 | usbd_status | |
281 | usbd_open_pipe_intr(struct usbd_interface *iface, uint8_t address, | 281 | usbd_open_pipe_intr(struct usbd_interface *iface, uint8_t address, | |
282 | uint8_t flags, struct usbd_pipe **pipe, | 282 | uint8_t flags, struct usbd_pipe **pipe, | |
283 | void *priv, void *buffer, uint32_t len, | 283 | void *priv, void *buffer, uint32_t len, | |
284 | usbd_callback cb, int ival) | 284 | usbd_callback cb, int ival) | |
285 | { | 285 | { | |
286 | usbd_status err; | 286 | usbd_status err; | |
287 | struct usbd_xfer *xfer; | 287 | struct usbd_xfer *xfer; | |
288 | struct usbd_pipe *ipipe; | 288 | struct usbd_pipe *ipipe; | |
289 | 289 | |||
290 | USBHIST_FUNC(); | 290 | USBHIST_FUNC(); | |
291 | USBHIST_CALLARGS(usbdebug, "address = %#jx flags = %#jx len = %jd", | 291 | USBHIST_CALLARGS(usbdebug, "address = %#jx flags = %#jx len = %jd", | |
292 | address, flags, len, 0); | 292 | address, flags, len, 0); | |
293 | 293 | |||
294 | err = usbd_open_pipe_ival(iface, address, | 294 | err = usbd_open_pipe_ival(iface, address, | |
295 | USBD_EXCLUSIVE_USE | (flags & USBD_MPSAFE), | 295 | USBD_EXCLUSIVE_USE | (flags & USBD_MPSAFE), | |
296 | &ipipe, ival); | 296 | &ipipe, ival); | |
297 | if (err) | 297 | if (err) | |
298 | return err; | 298 | return err; | |
299 | err = usbd_create_xfer(ipipe, len, flags, 0, &xfer); | 299 | err = usbd_create_xfer(ipipe, len, flags, 0, &xfer); | |
300 | if (err) | 300 | if (err) | |
301 | goto bad1; | 301 | goto bad1; | |
302 | 302 | |||
303 | usbd_setup_xfer(xfer, priv, buffer, len, flags, USBD_NO_TIMEOUT, cb); | 303 | usbd_setup_xfer(xfer, priv, buffer, len, flags, USBD_NO_TIMEOUT, cb); | |
304 | ipipe->up_intrxfer = xfer; | 304 | ipipe->up_intrxfer = xfer; | |
305 | ipipe->up_repeat = 1; | 305 | ipipe->up_repeat = 1; | |
306 | err = usbd_transfer(xfer); | 306 | err = usbd_transfer(xfer); | |
307 | *pipe = ipipe; | 307 | *pipe = ipipe; | |
308 | if (err != USBD_IN_PROGRESS) | 308 | if (err != USBD_IN_PROGRESS) | |
309 | goto bad3; | 309 | goto bad3; | |
310 | SDT_PROBE7(usb, device, pipe, open__intr, | 310 | SDT_PROBE7(usb, device, pipe, open__intr, | |
311 | iface, address, flags, ival, cb, priv, ipipe); | 311 | iface, address, flags, ival, cb, priv, ipipe); | |
312 | return USBD_NORMAL_COMPLETION; | 312 | return USBD_NORMAL_COMPLETION; | |
313 | 313 | |||
314 | bad3: | 314 | bad3: | |
315 | ipipe->up_intrxfer = NULL; | 315 | ipipe->up_intrxfer = NULL; | |
316 | ipipe->up_repeat = 0; | 316 | ipipe->up_repeat = 0; | |
317 | 317 | |||
318 | usbd_destroy_xfer(xfer); | 318 | usbd_destroy_xfer(xfer); | |
319 | bad1: | 319 | bad1: | |
320 | usbd_close_pipe(ipipe); | 320 | usbd_close_pipe(ipipe); | |
321 | return err; | 321 | return err; | |
322 | } | 322 | } | |
323 | 323 | |||
324 | usbd_status | 324 | usbd_status | |
325 | usbd_close_pipe(struct usbd_pipe *pipe) | 325 | usbd_close_pipe(struct usbd_pipe *pipe) | |
326 | { | 326 | { | |
327 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | 327 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | |
328 | 328 | |||
329 | KASSERT(pipe != NULL); | 329 | KASSERT(pipe != NULL); | |
330 | 330 | |||
331 | usbd_lock_pipe(pipe); | 331 | usbd_lock_pipe(pipe); | |
332 | SDT_PROBE1(usb, device, pipe, close, pipe); | 332 | SDT_PROBE1(usb, device, pipe, close, pipe); | |
333 | if (!SIMPLEQ_EMPTY(&pipe->up_queue)) { | 333 | if (!SIMPLEQ_EMPTY(&pipe->up_queue)) { | |
334 | printf("WARNING: pipe closed with active xfers on addr %d\n", | 334 | printf("WARNING: pipe closed with active xfers on addr %d\n", | |
335 | pipe->up_dev->ud_addr); | 335 | pipe->up_dev->ud_addr); | |
336 | usbd_ar_pipe(pipe); | 336 | usbd_ar_pipe(pipe); | |
337 | } | 337 | } | |
338 | KASSERT(SIMPLEQ_EMPTY(&pipe->up_queue)); | 338 | KASSERT(SIMPLEQ_EMPTY(&pipe->up_queue)); | |
339 | pipe->up_methods->upm_close(pipe); | 339 | pipe->up_methods->upm_close(pipe); | |
340 | usbd_unlock_pipe(pipe); | 340 | usbd_unlock_pipe(pipe); | |
341 | 341 | |||
342 | cv_destroy(&pipe->up_callingcv); | 342 | cv_destroy(&pipe->up_callingcv); | |
343 | if (pipe->up_intrxfer) | 343 | if (pipe->up_intrxfer) | |
344 | usbd_destroy_xfer(pipe->up_intrxfer); | 344 | usbd_destroy_xfer(pipe->up_intrxfer); | |
345 | usb_rem_task_wait(pipe->up_dev, &pipe->up_async_task, USB_TASKQ_DRIVER, | 345 | usb_rem_task_wait(pipe->up_dev, &pipe->up_async_task, USB_TASKQ_DRIVER, | |
346 | NULL); | 346 | NULL); | |
347 | usbd_endpoint_release(pipe->up_dev, pipe->up_endpoint); | 347 | usbd_endpoint_release(pipe->up_dev, pipe->up_endpoint); | |
348 | if (pipe->up_iface) | 348 | if (pipe->up_iface) | |
349 | usbd_iface_pipeunref(pipe->up_iface); | 349 | usbd_iface_pipeunref(pipe->up_iface); | |
350 | kmem_free(pipe, pipe->up_dev->ud_bus->ub_pipesize); | 350 | kmem_free(pipe, pipe->up_dev->ud_bus->ub_pipesize); | |
351 | 351 | |||
352 | return USBD_NORMAL_COMPLETION; | 352 | return USBD_NORMAL_COMPLETION; | |
353 | } | 353 | } | |
354 | 354 | |||
355 | usbd_status | 355 | usbd_status | |
356 | usbd_transfer(struct usbd_xfer *xfer) | 356 | usbd_transfer(struct usbd_xfer *xfer) | |
357 | { | 357 | { | |
358 | struct usbd_pipe *pipe = xfer->ux_pipe; | 358 | struct usbd_pipe *pipe = xfer->ux_pipe; | |
359 | usbd_status err; | 359 | usbd_status err; | |
360 | unsigned int size, flags; | 360 | unsigned int size, flags; | |
361 | 361 | |||
362 | USBHIST_FUNC(); USBHIST_CALLARGS(usbdebug, | 362 | USBHIST_FUNC(); USBHIST_CALLARGS(usbdebug, | |
363 | "xfer = %#jx, flags = %#jx, pipe = %#jx, running = %jd", | 363 | "xfer = %#jx, flags = %#jx, pipe = %#jx, running = %jd", | |
364 | (uintptr_t)xfer, xfer->ux_flags, (uintptr_t)pipe, pipe->up_running); | 364 | (uintptr_t)xfer, xfer->ux_flags, (uintptr_t)pipe, pipe->up_running); | |
365 | KASSERT(xfer->ux_status == USBD_NOT_STARTED); | 365 | KASSERT(xfer->ux_status == USBD_NOT_STARTED); | |
366 | SDT_PROBE1(usb, device, xfer, start, xfer); | 366 | SDT_PROBE1(usb, device, xfer, start, xfer); | |
367 | 367 | |||
368 | #ifdef USB_DEBUG | 368 | #ifdef USB_DEBUG | |
369 | if (usbdebug > 5) | 369 | if (usbdebug > 5) | |
370 | usbd_dump_queue(pipe); | 370 | usbd_dump_queue(pipe); | |
371 | #endif | 371 | #endif | |
372 | xfer->ux_done = 0; | 372 | xfer->ux_done = 0; | |
373 | 373 | |||
374 | if (pipe->up_aborting) { | 374 | if (pipe->up_aborting) { | |
375 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, aborting", | 375 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, aborting", | |
376 | (uintptr_t)xfer, 0, 0, 0); | 376 | (uintptr_t)xfer, 0, 0, 0); | |
377 | SDT_PROBE2(usb, device, xfer, done, xfer, USBD_CANCELLED); | 377 | SDT_PROBE2(usb, device, xfer, done, xfer, USBD_CANCELLED); | |
378 | return USBD_CANCELLED; | 378 | return USBD_CANCELLED; | |
379 | } | 379 | } | |
380 | 380 | |||
381 | KASSERT(xfer->ux_length == 0 || xfer->ux_buf != NULL); | 381 | KASSERT(xfer->ux_length == 0 || xfer->ux_buf != NULL); | |
382 | 382 | |||
383 | size = xfer->ux_length; | 383 | size = xfer->ux_length; | |
384 | flags = xfer->ux_flags; | 384 | flags = xfer->ux_flags; | |
385 | 385 | |||
386 | if (size != 0) { | 386 | if (size != 0) { | |
387 | /* | 387 | /* | |
388 | * Use the xfer buffer if none specified in transfer setup. | 388 | * Use the xfer buffer if none specified in transfer setup. | |
389 | * isoc transfers always use the xfer buffer, i.e. | 389 | * isoc transfers always use the xfer buffer, i.e. | |
390 | * ux_buffer is always NULL for isoc. | 390 | * ux_buffer is always NULL for isoc. | |
391 | */ | 391 | */ | |
392 | if (xfer->ux_buffer == NULL) { | 392 | if (xfer->ux_buffer == NULL) { | |
393 | xfer->ux_buffer = xfer->ux_buf; | 393 | xfer->ux_buffer = xfer->ux_buf; | |
394 | } | 394 | } | |
395 | 395 | |||
396 | /* | 396 | /* | |
397 | * If not using the xfer buffer copy data to the | 397 | * If not using the xfer buffer copy data to the | |
398 | * xfer buffer for OUT transfers of >0 length | 398 | * xfer buffer for OUT transfers of >0 length | |
399 | */ | 399 | */ | |
400 | if (xfer->ux_buffer != xfer->ux_buf) { | 400 | if (xfer->ux_buffer != xfer->ux_buf) { | |
401 | KASSERT(xfer->ux_buf); | 401 | KASSERT(xfer->ux_buf); | |
402 | if (!usbd_xfer_isread(xfer)) { | 402 | if (!usbd_xfer_isread(xfer)) { | |
403 | memcpy(xfer->ux_buf, xfer->ux_buffer, size); | 403 | memcpy(xfer->ux_buf, xfer->ux_buffer, size); | |
404 | } | 404 | } | |
405 | } | 405 | } | |
406 | } | 406 | } | |
407 | 407 | |||
408 | /* xfer is not valid after the transfer method unless synchronous */ | 408 | /* xfer is not valid after the transfer method unless synchronous */ | |
409 | SDT_PROBE2(usb, device, pipe, transfer__start, pipe, xfer); | 409 | SDT_PROBE2(usb, device, pipe, transfer__start, pipe, xfer); | |
410 | do { | 410 | do { | |
411 | usbd_lock_pipe(pipe); | 411 | usbd_lock_pipe(pipe); | |
412 | err = usb_insert_transfer(xfer); | 412 | err = usb_insert_transfer(xfer); | |
413 | usbd_unlock_pipe(pipe); | 413 | usbd_unlock_pipe(pipe); | |
414 | if (err) | 414 | if (err) | |
415 | break; | 415 | break; | |
416 | err = pipe->up_methods->upm_transfer(xfer); | 416 | err = pipe->up_methods->upm_transfer(xfer); | |
417 | } while (0); | 417 | } while (0); | |
418 | SDT_PROBE3(usb, device, pipe, transfer__done, pipe, xfer, err); | 418 | SDT_PROBE3(usb, device, pipe, transfer__done, pipe, xfer, err); | |
419 | 419 | |||
420 | if (err != USBD_IN_PROGRESS && err) { | 420 | if (err != USBD_IN_PROGRESS && err) { | |
421 | /* | 421 | /* | |
422 | * The transfer made it onto the pipe queue, but didn't get | 422 | * The transfer made it onto the pipe queue, but didn't get | |
423 | * accepted by the HCD for some reason. It needs removing | 423 | * accepted by the HCD for some reason. It needs removing | |
424 | * from the pipe queue. | 424 | * from the pipe queue. | |
425 | */ | 425 | */ | |
426 | USBHIST_LOG(usbdebug, "xfer failed: %jd, reinserting", | 426 | USBHIST_LOG(usbdebug, "xfer failed: %jd, reinserting", | |
427 | err, 0, 0, 0); | 427 | err, 0, 0, 0); | |
428 | usbd_lock_pipe(pipe); | 428 | usbd_lock_pipe(pipe); | |
429 | SDT_PROBE1(usb, device, xfer, preabort, xfer); | 429 | SDT_PROBE1(usb, device, xfer, preabort, xfer); | |
430 | #ifdef DIAGNOSTIC | 430 | #ifdef DIAGNOSTIC | |
431 | xfer->ux_state = XFER_BUSY; | 431 | xfer->ux_state = XFER_BUSY; | |
432 | #endif | 432 | #endif | |
433 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); | 433 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); | |
434 | if (pipe->up_serialise) | 434 | if (pipe->up_serialise) | |
435 | usbd_start_next(pipe); | 435 | usbd_start_next(pipe); | |
436 | usbd_unlock_pipe(pipe); | 436 | usbd_unlock_pipe(pipe); | |
437 | } | 437 | } | |
438 | 438 | |||
439 | if (!(flags & USBD_SYNCHRONOUS)) { | 439 | if (!(flags & USBD_SYNCHRONOUS)) { | |
440 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, not sync (err %jd)", | 440 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, not sync (err %jd)", | |
441 | (uintptr_t)xfer, err, 0, 0); | 441 | (uintptr_t)xfer, err, 0, 0); | |
442 | if (err != USBD_IN_PROGRESS) /* XXX Possible? */ | 442 | if (err != USBD_IN_PROGRESS) /* XXX Possible? */ | |
443 | SDT_PROBE2(usb, device, xfer, done, xfer, err); | 443 | SDT_PROBE2(usb, device, xfer, done, xfer, err); | |
444 | return err; | 444 | return err; | |
445 | } | 445 | } | |
446 | 446 | |||
447 | if (err != USBD_IN_PROGRESS) { | 447 | if (err != USBD_IN_PROGRESS) { | |
448 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, sync (err %jd)", | 448 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, sync (err %jd)", | |
449 | (uintptr_t)xfer, err, 0, 0); | 449 | (uintptr_t)xfer, err, 0, 0); | |
450 | SDT_PROBE2(usb, device, xfer, done, xfer, err); | 450 | SDT_PROBE2(usb, device, xfer, done, xfer, err); | |
451 | return err; | 451 | return err; | |
452 | } | 452 | } | |
453 | 453 | |||
454 | /* Sync transfer, wait for completion. */ | 454 | /* Sync transfer, wait for completion. */ | |
455 | usbd_lock_pipe(pipe); | 455 | usbd_lock_pipe(pipe); | |
456 | while (!xfer->ux_done) { | 456 | while (!xfer->ux_done) { | |
457 | if (pipe->up_dev->ud_bus->ub_usepolling) | 457 | if (pipe->up_dev->ud_bus->ub_usepolling) | |
458 | panic("usbd_transfer: not done"); | 458 | panic("usbd_transfer: not done"); | |
459 | USBHIST_LOG(usbdebug, "<- sleeping on xfer %#jx", | 459 | USBHIST_LOG(usbdebug, "<- sleeping on xfer %#jx", | |
460 | (uintptr_t)xfer, 0, 0, 0); | 460 | (uintptr_t)xfer, 0, 0, 0); | |
461 | 461 | |||
462 | err = 0; | 462 | err = 0; | |
463 | if ((flags & USBD_SYNCHRONOUS_SIG) != 0) { | 463 | if ((flags & USBD_SYNCHRONOUS_SIG) != 0) { | |
464 | err = cv_wait_sig(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); | 464 | err = cv_wait_sig(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); | |
465 | } else { | 465 | } else { | |
466 | cv_wait(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); | 466 | cv_wait(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); | |
467 | } | 467 | } | |
468 | if (err) { | 468 | if (err) { | |
469 | if (!xfer->ux_done) { | 469 | if (!xfer->ux_done) { | |
470 | SDT_PROBE1(usb, device, xfer, abort, xfer); | 470 | SDT_PROBE1(usb, device, xfer, abort, xfer); | |
471 | pipe->up_methods->upm_abort(xfer); | 471 | pipe->up_methods->upm_abort(xfer); | |
472 | } | 472 | } | |
473 | break; | 473 | break; | |
474 | } | 474 | } | |
475 | } | 475 | } | |
476 | SDT_PROBE2(usb, device, xfer, done, xfer, xfer->ux_status); | 476 | SDT_PROBE2(usb, device, xfer, done, xfer, xfer->ux_status); | |
477 | /* XXX Race to read xfer->ux_status? */ | 477 | /* XXX Race to read xfer->ux_status? */ | |
478 | usbd_unlock_pipe(pipe); | 478 | usbd_unlock_pipe(pipe); | |
479 | return xfer->ux_status; | 479 | return xfer->ux_status; | |
480 | } | 480 | } | |
481 | 481 | |||
482 | /* Like usbd_transfer(), but waits for completion. */ | 482 | /* Like usbd_transfer(), but waits for completion. */ | |
483 | usbd_status | 483 | usbd_status | |
484 | usbd_sync_transfer(struct usbd_xfer *xfer) | 484 | usbd_sync_transfer(struct usbd_xfer *xfer) | |
485 | { | 485 | { | |
486 | xfer->ux_flags |= USBD_SYNCHRONOUS; | 486 | xfer->ux_flags |= USBD_SYNCHRONOUS; | |
487 | return usbd_transfer(xfer); | 487 | return usbd_transfer(xfer); | |
488 | } | 488 | } | |
489 | 489 | |||
490 | /* Like usbd_transfer(), but waits for completion and listens for signals. */ | 490 | /* Like usbd_transfer(), but waits for completion and listens for signals. */ | |
491 | usbd_status | 491 | usbd_status | |
492 | usbd_sync_transfer_sig(struct usbd_xfer *xfer) | 492 | usbd_sync_transfer_sig(struct usbd_xfer *xfer) | |
493 | { | 493 | { | |
494 | xfer->ux_flags |= USBD_SYNCHRONOUS | USBD_SYNCHRONOUS_SIG; | 494 | xfer->ux_flags |= USBD_SYNCHRONOUS | USBD_SYNCHRONOUS_SIG; | |
495 | return usbd_transfer(xfer); | 495 | return usbd_transfer(xfer); | |
496 | } | 496 | } | |
497 | 497 | |||
498 | static void * | 498 | static void * | |
499 | usbd_alloc_buffer(struct usbd_xfer *xfer, uint32_t size) | 499 | usbd_alloc_buffer(struct usbd_xfer *xfer, uint32_t size) | |
500 | { | 500 | { | |
501 | KASSERT(xfer->ux_buf == NULL); | 501 | KASSERT(xfer->ux_buf == NULL); | |
502 | KASSERT(size != 0); | 502 | KASSERT(size != 0); | |
503 | 503 | |||
504 | xfer->ux_bufsize = 0; | 504 | xfer->ux_bufsize = 0; | |
505 | #if NUSB_DMA > 0 | 505 | #if NUSB_DMA > 0 | |
506 | struct usbd_bus *bus = xfer->ux_bus; | 506 | struct usbd_bus *bus = xfer->ux_bus; | |
507 | 507 | |||
508 | if (bus->ub_usedma) { | 508 | if (bus->ub_usedma) { | |
509 | usb_dma_t *dmap = &xfer->ux_dmabuf; | 509 | usb_dma_t *dmap = &xfer->ux_dmabuf; | |
510 | 510 | |||
511 | KASSERT((bus->ub_dmaflags & USBMALLOC_COHERENT) == 0); | 511 | KASSERT((bus->ub_dmaflags & USBMALLOC_COHERENT) == 0); | |
512 | int err = usb_allocmem(bus->ub_dmatag, size, 0, bus->ub_dmaflags, dmap); | 512 | int err = usb_allocmem(bus->ub_dmatag, size, 0, bus->ub_dmaflags, dmap); | |
513 | if (err) { | 513 | if (err) { | |
514 | return NULL; | 514 | return NULL; | |
515 | } | 515 | } | |
516 | xfer->ux_buf = KERNADDR(&xfer->ux_dmabuf, 0); | 516 | xfer->ux_buf = KERNADDR(&xfer->ux_dmabuf, 0); | |
517 | xfer->ux_bufsize = size; | 517 | xfer->ux_bufsize = size; | |
518 | 518 | |||
519 | return xfer->ux_buf; | 519 | return xfer->ux_buf; | |
520 | } | 520 | } | |
521 | #endif | 521 | #endif | |
522 | KASSERT(xfer->ux_bus->ub_usedma == false); | 522 | KASSERT(xfer->ux_bus->ub_usedma == false); | |
523 | xfer->ux_buf = kmem_alloc(size, KM_SLEEP); | 523 | xfer->ux_buf = kmem_alloc(size, KM_SLEEP); | |
524 | xfer->ux_bufsize = size; | 524 | xfer->ux_bufsize = size; | |
525 | return xfer->ux_buf; | 525 | return xfer->ux_buf; | |
526 | } | 526 | } | |
527 | 527 | |||
528 | static void | 528 | static void | |
529 | usbd_free_buffer(struct usbd_xfer *xfer) | 529 | usbd_free_buffer(struct usbd_xfer *xfer) | |
530 | { | 530 | { | |
531 | KASSERT(xfer->ux_buf != NULL); | 531 | KASSERT(xfer->ux_buf != NULL); | |
532 | KASSERT(xfer->ux_bufsize != 0); | 532 | KASSERT(xfer->ux_bufsize != 0); | |
533 | 533 | |||
534 | void *buf = xfer->ux_buf; | 534 | void *buf = xfer->ux_buf; | |
535 | uint32_t size = xfer->ux_bufsize; | 535 | uint32_t size = xfer->ux_bufsize; | |
536 | 536 | |||
537 | xfer->ux_buf = NULL; | 537 | xfer->ux_buf = NULL; | |
538 | xfer->ux_bufsize = 0; | 538 | xfer->ux_bufsize = 0; | |
539 | 539 | |||
540 | #if NUSB_DMA > 0 | 540 | #if NUSB_DMA > 0 | |
541 | struct usbd_bus *bus = xfer->ux_bus; | 541 | struct usbd_bus *bus = xfer->ux_bus; | |
542 | 542 | |||
543 | if (bus->ub_usedma) { | 543 | if (bus->ub_usedma) { | |
544 | usb_dma_t *dmap = &xfer->ux_dmabuf; | 544 | usb_dma_t *dmap = &xfer->ux_dmabuf; | |
545 | 545 | |||
546 | usb_freemem(dmap); | 546 | usb_freemem(dmap); | |
547 | return; | 547 | return; | |
548 | } | 548 | } | |
549 | #endif | 549 | #endif | |
550 | KASSERT(xfer->ux_bus->ub_usedma == false); | 550 | KASSERT(xfer->ux_bus->ub_usedma == false); | |
551 | 551 | |||
552 | kmem_free(buf, size); | 552 | kmem_free(buf, size); | |
553 | } | 553 | } | |
554 | 554 | |||
555 | void * | 555 | void * | |
556 | usbd_get_buffer(struct usbd_xfer *xfer) | 556 | usbd_get_buffer(struct usbd_xfer *xfer) | |
557 | { | 557 | { | |
558 | return xfer->ux_buf; | 558 | return xfer->ux_buf; | |
559 | } | 559 | } | |
560 | 560 | |||
561 | struct usbd_pipe * | 561 | struct usbd_pipe * | |
562 | usbd_get_pipe0(struct usbd_device *dev) | 562 | usbd_get_pipe0(struct usbd_device *dev) | |
563 | { | 563 | { | |
564 | 564 | |||
565 | return dev->ud_pipe0; | 565 | return dev->ud_pipe0; | |
566 | } | 566 | } | |
567 | 567 | |||
568 | static struct usbd_xfer * | 568 | static struct usbd_xfer * | |
569 | usbd_alloc_xfer(struct usbd_device *dev, unsigned int nframes) | 569 | usbd_alloc_xfer(struct usbd_device *dev, unsigned int nframes) | |
570 | { | 570 | { | |
571 | struct usbd_xfer *xfer; | 571 | struct usbd_xfer *xfer; | |
572 | 572 | |||
573 | USBHIST_FUNC(); | 573 | USBHIST_FUNC(); | |
574 | 574 | |||
575 | ASSERT_SLEEPABLE(); | 575 | ASSERT_SLEEPABLE(); | |
576 | 576 | |||
577 | xfer = dev->ud_bus->ub_methods->ubm_allocx(dev->ud_bus, nframes); | 577 | xfer = dev->ud_bus->ub_methods->ubm_allocx(dev->ud_bus, nframes); | |
578 | if (xfer == NULL) | 578 | if (xfer == NULL) | |
579 | goto out; | 579 | goto out; | |
580 | xfer->ux_bus = dev->ud_bus; | 580 | xfer->ux_bus = dev->ud_bus; | |
581 | callout_init(&xfer->ux_callout, CALLOUT_MPSAFE); | 581 | callout_init(&xfer->ux_callout, CALLOUT_MPSAFE); | |
582 | callout_setfunc(&xfer->ux_callout, usbd_xfer_timeout, xfer); | 582 | callout_setfunc(&xfer->ux_callout, usbd_xfer_timeout, xfer); | |
583 | cv_init(&xfer->ux_cv, "usbxfer"); | 583 | cv_init(&xfer->ux_cv, "usbxfer"); | |
584 | usb_init_task(&xfer->ux_aborttask, usbd_xfer_timeout_task, xfer, | 584 | usb_init_task(&xfer->ux_aborttask, usbd_xfer_timeout_task, xfer, | |
585 | USB_TASKQ_MPSAFE); | 585 | USB_TASKQ_MPSAFE); | |
586 | 586 | |||
587 | out: | 587 | out: | |
588 | USBHIST_CALLARGS(usbdebug, "returns %#jx", (uintptr_t)xfer, 0, 0, 0); | 588 | USBHIST_CALLARGS(usbdebug, "returns %#jx", (uintptr_t)xfer, 0, 0, 0); | |
589 | 589 | |||
590 | return xfer; | 590 | return xfer; | |
591 | } | 591 | } | |
592 | 592 | |||
593 | static usbd_status | 593 | static usbd_status | |
594 | usbd_free_xfer(struct usbd_xfer *xfer) | 594 | usbd_free_xfer(struct usbd_xfer *xfer) | |
595 | { | 595 | { | |
596 | USBHIST_FUNC(); | 596 | USBHIST_FUNC(); | |
597 | USBHIST_CALLARGS(usbdebug, "%#jx", (uintptr_t)xfer, 0, 0, 0); | 597 | USBHIST_CALLARGS(usbdebug, "%#jx", (uintptr_t)xfer, 0, 0, 0); | |
598 | 598 | |||
599 | if (xfer->ux_buf) { | 599 | if (xfer->ux_buf) { | |
600 | usbd_free_buffer(xfer); | 600 | usbd_free_buffer(xfer); | |
601 | } | 601 | } | |
602 | 602 | |||
603 | /* Wait for any straggling timeout to complete. */ | 603 | /* Wait for any straggling timeout to complete. */ | |
604 | mutex_enter(xfer->ux_bus->ub_lock); | 604 | mutex_enter(xfer->ux_bus->ub_lock); | |
605 | xfer->ux_timeout_reset = false; /* do not resuscitate */ | 605 | xfer->ux_timeout_reset = false; /* do not resuscitate */ | |
606 | callout_halt(&xfer->ux_callout, xfer->ux_bus->ub_lock); | 606 | callout_halt(&xfer->ux_callout, xfer->ux_bus->ub_lock); | |
607 | usb_rem_task_wait(xfer->ux_pipe->up_dev, &xfer->ux_aborttask, | 607 | usb_rem_task_wait(xfer->ux_pipe->up_dev, &xfer->ux_aborttask, | |
608 | USB_TASKQ_HC, xfer->ux_bus->ub_lock); | 608 | USB_TASKQ_HC, xfer->ux_bus->ub_lock); | |
609 | mutex_exit(xfer->ux_bus->ub_lock); | 609 | mutex_exit(xfer->ux_bus->ub_lock); | |
610 | 610 | |||
611 | cv_destroy(&xfer->ux_cv); | 611 | cv_destroy(&xfer->ux_cv); | |
612 | xfer->ux_bus->ub_methods->ubm_freex(xfer->ux_bus, xfer); | 612 | xfer->ux_bus->ub_methods->ubm_freex(xfer->ux_bus, xfer); | |
613 | return USBD_NORMAL_COMPLETION; | 613 | return USBD_NORMAL_COMPLETION; | |
614 | } | 614 | } | |
615 | 615 | |||
616 | int | 616 | int | |
617 | usbd_create_xfer(struct usbd_pipe *pipe, size_t len, unsigned int flags, | 617 | usbd_create_xfer(struct usbd_pipe *pipe, size_t len, unsigned int flags, | |
618 | unsigned int nframes, struct usbd_xfer **xp) | 618 | unsigned int nframes, struct usbd_xfer **xp) | |
619 | { | 619 | { | |
620 | KASSERT(xp != NULL); | 620 | KASSERT(xp != NULL); | |
621 | void *buf = NULL; | 621 | void *buf = NULL; | |
622 | 622 | |||
623 | struct usbd_xfer *xfer = usbd_alloc_xfer(pipe->up_dev, nframes); | 623 | struct usbd_xfer *xfer = usbd_alloc_xfer(pipe->up_dev, nframes); | |
624 | if (xfer == NULL) | 624 | if (xfer == NULL) | |
625 | return ENOMEM; | 625 | return ENOMEM; | |
626 | 626 | |||
627 | xfer->ux_pipe = pipe; | 627 | xfer->ux_pipe = pipe; | |
628 | xfer->ux_flags = flags; | 628 | xfer->ux_flags = flags; | |
629 | xfer->ux_nframes = nframes; | 629 | xfer->ux_nframes = nframes; | |
630 | xfer->ux_methods = pipe->up_methods; | 630 | xfer->ux_methods = pipe->up_methods; | |
631 | 631 | |||
632 | if (len) { | 632 | if (len) { | |
633 | buf = usbd_alloc_buffer(xfer, len); | 633 | buf = usbd_alloc_buffer(xfer, len); | |
634 | if (!buf) { | 634 | if (!buf) { | |
635 | usbd_free_xfer(xfer); | 635 | usbd_free_xfer(xfer); | |
636 | return ENOMEM; | 636 | return ENOMEM; | |
637 | } | 637 | } | |
638 | } | 638 | } | |
639 | 639 | |||
640 | if (xfer->ux_methods->upm_init) { | 640 | if (xfer->ux_methods->upm_init) { | |
641 | int err = xfer->ux_methods->upm_init(xfer); | 641 | int err = xfer->ux_methods->upm_init(xfer); | |
642 | if (err) { | 642 | if (err) { | |
643 | usbd_free_xfer(xfer); | 643 | usbd_free_xfer(xfer); | |
644 | return err; | 644 | return err; | |
645 | } | 645 | } | |
646 | } | 646 | } | |
647 | 647 | |||
648 | *xp = xfer; | 648 | *xp = xfer; | |
649 | SDT_PROBE5(usb, device, xfer, create, | 649 | SDT_PROBE5(usb, device, xfer, create, | |
650 | xfer, pipe, len, flags, nframes); | 650 | xfer, pipe, len, flags, nframes); | |
651 | return 0; | 651 | return 0; | |
652 | } | 652 | } | |
653 | 653 | |||
654 | void | 654 | void | |
655 | usbd_destroy_xfer(struct usbd_xfer *xfer) | 655 | usbd_destroy_xfer(struct usbd_xfer *xfer) | |
656 | { | 656 | { | |
657 | 657 | |||
658 | SDT_PROBE1(usb, device, xfer, destroy, xfer); | 658 | SDT_PROBE1(usb, device, xfer, destroy, xfer); | |
659 | if (xfer->ux_methods->upm_fini) | 659 | if (xfer->ux_methods->upm_fini) | |
660 | xfer->ux_methods->upm_fini(xfer); | 660 | xfer->ux_methods->upm_fini(xfer); | |
661 | 661 | |||
662 | usbd_free_xfer(xfer); | 662 | usbd_free_xfer(xfer); | |
663 | } | 663 | } | |
664 | 664 | |||
665 | void | 665 | void | |
666 | usbd_setup_xfer(struct usbd_xfer *xfer, void *priv, void *buffer, | 666 | usbd_setup_xfer(struct usbd_xfer *xfer, void *priv, void *buffer, | |
667 | uint32_t length, uint16_t flags, uint32_t timeout, usbd_callback callback) | 667 | uint32_t length, uint16_t flags, uint32_t timeout, usbd_callback callback) | |
668 | { | 668 | { | |
669 | KASSERT(xfer->ux_pipe); | 669 | KASSERT(xfer->ux_pipe); | |
670 | 670 | |||
671 | xfer->ux_priv = priv; | 671 | xfer->ux_priv = priv; | |
672 | xfer->ux_buffer = buffer; | 672 | xfer->ux_buffer = buffer; | |
673 | xfer->ux_length = length; | 673 | xfer->ux_length = length; | |
674 | xfer->ux_actlen = 0; | 674 | xfer->ux_actlen = 0; | |
675 | xfer->ux_flags = flags; | 675 | xfer->ux_flags = flags; | |
676 | xfer->ux_timeout = timeout; | 676 | xfer->ux_timeout = timeout; | |
677 | xfer->ux_status = USBD_NOT_STARTED; | 677 | xfer->ux_status = USBD_NOT_STARTED; | |
678 | xfer->ux_callback = callback; | 678 | xfer->ux_callback = callback; | |
679 | xfer->ux_rqflags &= ~URQ_REQUEST; | 679 | xfer->ux_rqflags &= ~URQ_REQUEST; | |
680 | xfer->ux_nframes = 0; | 680 | xfer->ux_nframes = 0; | |
681 | } | 681 | } | |
682 | 682 | |||
683 | void | 683 | void | |
684 | usbd_setup_default_xfer(struct usbd_xfer *xfer, struct usbd_device *dev, | 684 | usbd_setup_default_xfer(struct usbd_xfer *xfer, struct usbd_device *dev, | |
685 | void *priv, uint32_t timeout, usb_device_request_t *req, void *buffer, | 685 | void *priv, uint32_t timeout, usb_device_request_t *req, void *buffer, | |
686 | uint32_t length, uint16_t flags, usbd_callback callback) | 686 | uint32_t length, uint16_t flags, usbd_callback callback) | |
687 | { | 687 | { | |
688 | KASSERT(xfer->ux_pipe == dev->ud_pipe0); | 688 | KASSERT(xfer->ux_pipe == dev->ud_pipe0); | |
689 | 689 | |||
690 | xfer->ux_priv = priv; | 690 | xfer->ux_priv = priv; | |
691 | xfer->ux_buffer = buffer; | 691 | xfer->ux_buffer = buffer; | |
692 | xfer->ux_length = length; | 692 | xfer->ux_length = length; | |
693 | xfer->ux_actlen = 0; | 693 | xfer->ux_actlen = 0; | |
694 | xfer->ux_flags = flags; | 694 | xfer->ux_flags = flags; | |
695 | xfer->ux_timeout = timeout; | 695 | xfer->ux_timeout = timeout; | |
696 | xfer->ux_status = USBD_NOT_STARTED; | 696 | xfer->ux_status = USBD_NOT_STARTED; | |
697 | xfer->ux_callback = callback; | 697 | xfer->ux_callback = callback; | |
698 | xfer->ux_request = *req; | 698 | xfer->ux_request = *req; | |
699 | xfer->ux_rqflags |= URQ_REQUEST; | 699 | xfer->ux_rqflags |= URQ_REQUEST; | |
700 | xfer->ux_nframes = 0; | 700 | xfer->ux_nframes = 0; | |
701 | } | 701 | } | |
702 | 702 | |||
703 | void | 703 | void | |
704 | usbd_setup_isoc_xfer(struct usbd_xfer *xfer, void *priv, uint16_t *frlengths, | 704 | usbd_setup_isoc_xfer(struct usbd_xfer *xfer, void *priv, uint16_t *frlengths, | |
705 | uint32_t nframes, uint16_t flags, usbd_callback callback) | 705 | uint32_t nframes, uint16_t flags, usbd_callback callback) | |
706 | { | 706 | { | |
707 | xfer->ux_priv = priv; | 707 | xfer->ux_priv = priv; | |
708 | xfer->ux_buffer = NULL; | 708 | xfer->ux_buffer = NULL; | |
709 | xfer->ux_length = 0; | 709 | xfer->ux_length = 0; | |
710 | xfer->ux_actlen = 0; | 710 | xfer->ux_actlen = 0; | |
711 | xfer->ux_flags = flags; | 711 | xfer->ux_flags = flags; | |
712 | xfer->ux_timeout = USBD_NO_TIMEOUT; | 712 | xfer->ux_timeout = USBD_NO_TIMEOUT; | |
713 | xfer->ux_status = USBD_NOT_STARTED; | 713 | xfer->ux_status = USBD_NOT_STARTED; | |
714 | xfer->ux_callback = callback; | 714 | xfer->ux_callback = callback; | |
715 | xfer->ux_rqflags &= ~URQ_REQUEST; | 715 | xfer->ux_rqflags &= ~URQ_REQUEST; | |
716 | xfer->ux_frlengths = frlengths; | 716 | xfer->ux_frlengths = frlengths; | |
717 | xfer->ux_nframes = nframes; | 717 | xfer->ux_nframes = nframes; | |
718 | 718 | |||
719 | for (size_t i = 0; i < xfer->ux_nframes; i++) | 719 | for (size_t i = 0; i < xfer->ux_nframes; i++) | |
720 | xfer->ux_length += xfer->ux_frlengths[i]; | 720 | xfer->ux_length += xfer->ux_frlengths[i]; | |
721 | } | 721 | } | |
722 | 722 | |||
723 | void | 723 | void | |
724 | usbd_get_xfer_status(struct usbd_xfer *xfer, void **priv, | 724 | usbd_get_xfer_status(struct usbd_xfer *xfer, void **priv, | |
725 | void **buffer, uint32_t *count, usbd_status *status) | 725 | void **buffer, uint32_t *count, usbd_status *status) | |
726 | { | 726 | { | |
727 | if (priv != NULL) | 727 | if (priv != NULL) | |
728 | *priv = xfer->ux_priv; | 728 | *priv = xfer->ux_priv; | |
729 | if (buffer != NULL) | 729 | if (buffer != NULL) | |
730 | *buffer = xfer->ux_buffer; | 730 | *buffer = xfer->ux_buffer; | |
731 | if (count != NULL) | 731 | if (count != NULL) | |
732 | *count = xfer->ux_actlen; | 732 | *count = xfer->ux_actlen; | |
733 | if (status != NULL) | 733 | if (status != NULL) | |
734 | *status = xfer->ux_status; | 734 | *status = xfer->ux_status; | |
735 | } | 735 | } | |
736 | 736 | |||
737 | usb_config_descriptor_t * | 737 | usb_config_descriptor_t * | |
738 | usbd_get_config_descriptor(struct usbd_device *dev) | 738 | usbd_get_config_descriptor(struct usbd_device *dev) | |
739 | { | 739 | { | |
740 | KASSERT(dev != NULL); | 740 | KASSERT(dev != NULL); | |
741 | 741 | |||
742 | return dev->ud_cdesc; | 742 | return dev->ud_cdesc; | |
743 | } | 743 | } | |
744 | 744 | |||
745 | usb_interface_descriptor_t * | 745 | usb_interface_descriptor_t * | |
746 | usbd_get_interface_descriptor(struct usbd_interface *iface) | 746 | usbd_get_interface_descriptor(struct usbd_interface *iface) | |
747 | { | 747 | { | |
748 | KASSERT(iface != NULL); | 748 | KASSERT(iface != NULL); | |
749 | 749 | |||
750 | return iface->ui_idesc; | 750 | return iface->ui_idesc; | |
751 | } | 751 | } | |
752 | 752 | |||
753 | usb_device_descriptor_t * | 753 | usb_device_descriptor_t * | |
754 | usbd_get_device_descriptor(struct usbd_device *dev) | 754 | usbd_get_device_descriptor(struct usbd_device *dev) | |
755 | { | 755 | { | |
756 | KASSERT(dev != NULL); | 756 | KASSERT(dev != NULL); | |
757 | 757 | |||
758 | return &dev->ud_ddesc; | 758 | return &dev->ud_ddesc; | |
759 | } | 759 | } | |
760 | 760 | |||
761 | usb_endpoint_descriptor_t * | 761 | usb_endpoint_descriptor_t * | |
762 | usbd_interface2endpoint_descriptor(struct usbd_interface *iface, uint8_t index) | 762 | usbd_interface2endpoint_descriptor(struct usbd_interface *iface, uint8_t index) | |
763 | { | 763 | { | |
764 | 764 | |||
765 | if (index >= iface->ui_idesc->bNumEndpoints) | 765 | if (index >= iface->ui_idesc->bNumEndpoints) | |
766 | return NULL; | 766 | return NULL; | |
767 | return iface->ui_endpoints[index].ue_edesc; | 767 | return iface->ui_endpoints[index].ue_edesc; | |
768 | } | 768 | } | |
769 | 769 | |||
770 | /* Some drivers may wish to abort requests on the default pipe, * | 770 | /* Some drivers may wish to abort requests on the default pipe, * | |
771 | * but there is no mechanism for getting a handle on it. */ | 771 | * but there is no mechanism for getting a handle on it. */ | |
772 | usbd_status | 772 | void | |
773 | usbd_abort_default_pipe(struct usbd_device *device) | 773 | usbd_abort_default_pipe(struct usbd_device *device) | |
774 | { | 774 | { | |
775 | return usbd_abort_pipe(device->ud_pipe0); | 775 | usbd_abort_pipe(device->ud_pipe0); | |
776 | } | 776 | } | |
777 | 777 | |||
778 | usbd_status | 778 | void | |
779 | usbd_abort_pipe(struct usbd_pipe *pipe) | 779 | usbd_abort_pipe(struct usbd_pipe *pipe) | |
780 | { | 780 | { | |
781 | usbd_status err; | |||
782 | 781 | |||
783 | KASSERT(pipe != NULL); | 782 | KASSERT(pipe != NULL); | |
784 | 783 | |||
785 | usbd_lock_pipe(pipe); | 784 | usbd_lock_pipe(pipe); | |
786 | err = usbd_ar_pipe(pipe); | 785 | usbd_ar_pipe(pipe); | |
787 | usbd_unlock_pipe(pipe); | 786 | usbd_unlock_pipe(pipe); | |
788 | return err; | |||
789 | } | 787 | } | |
790 | 788 | |||
791 | usbd_status | 789 | usbd_status | |
792 | usbd_clear_endpoint_stall(struct usbd_pipe *pipe) | 790 | usbd_clear_endpoint_stall(struct usbd_pipe *pipe) | |
793 | { | 791 | { | |
794 | struct usbd_device *dev = pipe->up_dev; | 792 | struct usbd_device *dev = pipe->up_dev; | |
795 | usbd_status err; | 793 | usbd_status err; | |
796 | 794 | |||
797 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | 795 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | |
798 | SDT_PROBE1(usb, device, pipe, clear__endpoint__stall, pipe); | 796 | SDT_PROBE1(usb, device, pipe, clear__endpoint__stall, pipe); | |
799 | 797 | |||
800 | /* | 798 | /* | |
801 | * Clearing en endpoint stall resets the endpoint toggle, so | 799 | * Clearing en endpoint stall resets the endpoint toggle, so | |
802 | * do the same to the HC toggle. | 800 | * do the same to the HC toggle. | |
803 | */ | 801 | */ | |
804 | SDT_PROBE1(usb, device, pipe, clear__endpoint__toggle, pipe); | 802 | SDT_PROBE1(usb, device, pipe, clear__endpoint__toggle, pipe); | |
805 | pipe->up_methods->upm_cleartoggle(pipe); | 803 | pipe->up_methods->upm_cleartoggle(pipe); | |
806 | 804 | |||
807 | err = usbd_clear_endpoint_feature(dev, | 805 | err = usbd_clear_endpoint_feature(dev, | |
808 | pipe->up_endpoint->ue_edesc->bEndpointAddress, UF_ENDPOINT_HALT); | 806 | pipe->up_endpoint->ue_edesc->bEndpointAddress, UF_ENDPOINT_HALT); | |
809 | #if 0 | 807 | #if 0 | |
810 | XXX should we do this? | 808 | XXX should we do this? | |
811 | if (!err) { | 809 | if (!err) { | |
812 | pipe->state = USBD_PIPE_ACTIVE; | 810 | pipe->state = USBD_PIPE_ACTIVE; | |
813 | /* XXX activate pipe */ | 811 | /* XXX activate pipe */ | |
814 | } | 812 | } | |
815 | #endif | 813 | #endif | |
816 | return err; | 814 | return err; | |
817 | } | 815 | } | |
818 | 816 | |||
819 | void | 817 | void | |
820 | usbd_clear_endpoint_stall_task(void *arg) | 818 | usbd_clear_endpoint_stall_task(void *arg) | |
821 | { | 819 | { | |
822 | struct usbd_pipe *pipe = arg; | 820 | struct usbd_pipe *pipe = arg; | |
823 | struct usbd_device *dev = pipe->up_dev; | 821 | struct usbd_device *dev = pipe->up_dev; | |
824 | 822 | |||
825 | SDT_PROBE1(usb, device, pipe, clear__endpoint__stall, pipe); | 823 | SDT_PROBE1(usb, device, pipe, clear__endpoint__stall, pipe); | |
826 | SDT_PROBE1(usb, device, pipe, clear__endpoint__toggle, pipe); | 824 | SDT_PROBE1(usb, device, pipe, clear__endpoint__toggle, pipe); | |
827 | pipe->up_methods->upm_cleartoggle(pipe); | 825 | pipe->up_methods->upm_cleartoggle(pipe); | |
828 | 826 | |||
829 | (void)usbd_clear_endpoint_feature(dev, | 827 | (void)usbd_clear_endpoint_feature(dev, | |
830 | pipe->up_endpoint->ue_edesc->bEndpointAddress, UF_ENDPOINT_HALT); | 828 | pipe->up_endpoint->ue_edesc->bEndpointAddress, UF_ENDPOINT_HALT); | |
831 | } | 829 | } | |
832 | 830 | |||
833 | void | 831 | void | |
834 | usbd_clear_endpoint_stall_async(struct usbd_pipe *pipe) | 832 | usbd_clear_endpoint_stall_async(struct usbd_pipe *pipe) | |
835 | { | 833 | { | |
836 | usb_add_task(pipe->up_dev, &pipe->up_async_task, USB_TASKQ_DRIVER); | 834 | usb_add_task(pipe->up_dev, &pipe->up_async_task, USB_TASKQ_DRIVER); | |
837 | } | 835 | } | |
838 | 836 | |||
839 | void | 837 | void | |
840 | usbd_clear_endpoint_toggle(struct usbd_pipe *pipe) | 838 | usbd_clear_endpoint_toggle(struct usbd_pipe *pipe) | |
841 | { | 839 | { | |
842 | 840 | |||
843 | SDT_PROBE1(usb, device, pipe, clear__endpoint__toggle, pipe); | 841 | SDT_PROBE1(usb, device, pipe, clear__endpoint__toggle, pipe); | |
844 | pipe->up_methods->upm_cleartoggle(pipe); | 842 | pipe->up_methods->upm_cleartoggle(pipe); | |
845 | } | 843 | } | |
846 | 844 | |||
847 | usbd_status | 845 | usbd_status | |
848 | usbd_endpoint_count(struct usbd_interface *iface, uint8_t *count) | 846 | usbd_endpoint_count(struct usbd_interface *iface, uint8_t *count) | |
849 | { | 847 | { | |
850 | KASSERT(iface != NULL); | 848 | KASSERT(iface != NULL); | |
851 | KASSERT(iface->ui_idesc != NULL); | 849 | KASSERT(iface->ui_idesc != NULL); | |
852 | 850 | |||
853 | *count = iface->ui_idesc->bNumEndpoints; | 851 | *count = iface->ui_idesc->bNumEndpoints; | |
854 | return USBD_NORMAL_COMPLETION; | 852 | return USBD_NORMAL_COMPLETION; | |
855 | } | 853 | } | |
856 | 854 | |||
857 | usbd_status | 855 | usbd_status | |
858 | usbd_interface_count(struct usbd_device *dev, uint8_t *count) | 856 | usbd_interface_count(struct usbd_device *dev, uint8_t *count) | |
859 | { | 857 | { | |
860 | 858 | |||
861 | if (dev->ud_cdesc == NULL) | 859 | if (dev->ud_cdesc == NULL) | |
862 | return USBD_NOT_CONFIGURED; | 860 | return USBD_NOT_CONFIGURED; | |
863 | *count = dev->ud_cdesc->bNumInterface; | 861 | *count = dev->ud_cdesc->bNumInterface; | |
864 | return USBD_NORMAL_COMPLETION; | 862 | return USBD_NORMAL_COMPLETION; | |
865 | } | 863 | } | |
866 | 864 | |||
867 | void | 865 | void | |
868 | usbd_interface2device_handle(struct usbd_interface *iface, | 866 | usbd_interface2device_handle(struct usbd_interface *iface, | |
869 | struct usbd_device **dev) | 867 | struct usbd_device **dev) | |
870 | { | 868 | { | |
871 | 869 | |||
872 | *dev = iface->ui_dev; | 870 | *dev = iface->ui_dev; | |
873 | } | 871 | } | |
874 | 872 | |||
875 | usbd_status | 873 | usbd_status | |
876 | usbd_device2interface_handle(struct usbd_device *dev, | 874 | usbd_device2interface_handle(struct usbd_device *dev, | |
877 | uint8_t ifaceno, struct usbd_interface **iface) | 875 | uint8_t ifaceno, struct usbd_interface **iface) | |
878 | { | 876 | { | |
879 | 877 | |||
880 | if (dev->ud_cdesc == NULL) | 878 | if (dev->ud_cdesc == NULL) | |
881 | return USBD_NOT_CONFIGURED; | 879 | return USBD_NOT_CONFIGURED; | |
882 | if (ifaceno >= dev->ud_cdesc->bNumInterface) | 880 | if (ifaceno >= dev->ud_cdesc->bNumInterface) | |
883 | return USBD_INVAL; | 881 | return USBD_INVAL; | |
884 | *iface = &dev->ud_ifaces[ifaceno]; | 882 | *iface = &dev->ud_ifaces[ifaceno]; | |
885 | return USBD_NORMAL_COMPLETION; | 883 | return USBD_NORMAL_COMPLETION; | |
886 | } | 884 | } | |
887 | 885 | |||
888 | struct usbd_device * | 886 | struct usbd_device * | |
889 | usbd_pipe2device_handle(struct usbd_pipe *pipe) | 887 | usbd_pipe2device_handle(struct usbd_pipe *pipe) | |
890 | { | 888 | { | |
891 | KASSERT(pipe != NULL); | 889 | KASSERT(pipe != NULL); | |
892 | 890 | |||
893 | return pipe->up_dev; | 891 | return pipe->up_dev; | |
894 | } | 892 | } | |
895 | 893 | |||
896 | /* XXXX use altno */ | 894 | /* XXXX use altno */ | |
897 | usbd_status | 895 | usbd_status | |
898 | usbd_set_interface(struct usbd_interface *iface, int altidx) | 896 | usbd_set_interface(struct usbd_interface *iface, int altidx) | |
899 | { | 897 | { | |
900 | bool locked = false; | 898 | bool locked = false; | |
901 | usb_device_request_t req; | 899 | usb_device_request_t req; | |
902 | usbd_status err; | 900 | usbd_status err; | |
903 | 901 | |||
904 | USBHIST_FUNC(); | 902 | USBHIST_FUNC(); | |
905 | USBHIST_CALLARGS(usbdebug, "iface %#jx", (uintptr_t)iface, 0, 0, 0); | 903 | USBHIST_CALLARGS(usbdebug, "iface %#jx", (uintptr_t)iface, 0, 0, 0); | |
906 | 904 | |||
907 | err = usbd_iface_lock(iface); | 905 | err = usbd_iface_lock(iface); | |
908 | if (err) | 906 | if (err) | |
909 | goto out; | 907 | goto out; | |
910 | locked = true; | 908 | locked = true; | |
911 | 909 | |||
912 | err = usbd_fill_iface_data(iface->ui_dev, iface->ui_index, altidx); | 910 | err = usbd_fill_iface_data(iface->ui_dev, iface->ui_index, altidx); | |
913 | if (err) | 911 | if (err) | |
914 | goto out; | 912 | goto out; | |
915 | 913 | |||
916 | req.bmRequestType = UT_WRITE_INTERFACE; | 914 | req.bmRequestType = UT_WRITE_INTERFACE; | |
917 | req.bRequest = UR_SET_INTERFACE; | 915 | req.bRequest = UR_SET_INTERFACE; | |
918 | USETW(req.wValue, iface->ui_idesc->bAlternateSetting); | 916 | USETW(req.wValue, iface->ui_idesc->bAlternateSetting); | |
919 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); | 917 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); | |
920 | USETW(req.wLength, 0); | 918 | USETW(req.wLength, 0); | |
921 | err = usbd_do_request(iface->ui_dev, &req, 0); | 919 | err = usbd_do_request(iface->ui_dev, &req, 0); | |
922 | 920 | |||
923 | out: /* XXX back out iface data? */ | 921 | out: /* XXX back out iface data? */ | |
924 | if (locked) | 922 | if (locked) | |
925 | usbd_iface_unlock(iface); | 923 | usbd_iface_unlock(iface); | |
926 | return err; | 924 | return err; | |
927 | } | 925 | } | |
928 | 926 | |||
929 | int | 927 | int | |
930 | usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno) | 928 | usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno) | |
931 | { | 929 | { | |
932 | char *p = (char *)cdesc; | 930 | char *p = (char *)cdesc; | |
933 | char *end = p + UGETW(cdesc->wTotalLength); | 931 | char *end = p + UGETW(cdesc->wTotalLength); | |
934 | usb_interface_descriptor_t *d; | 932 | usb_interface_descriptor_t *d; | |
935 | int n; | 933 | int n; | |
936 | 934 | |||
937 | for (n = 0; p < end; p += d->bLength) { | 935 | for (n = 0; p < end; p += d->bLength) { | |
938 | d = (usb_interface_descriptor_t *)p; | 936 | d = (usb_interface_descriptor_t *)p; | |
939 | if (p + d->bLength <= end && | 937 | if (p + d->bLength <= end && | |
940 | d->bDescriptorType == UDESC_INTERFACE && | 938 | d->bDescriptorType == UDESC_INTERFACE && | |
941 | d->bInterfaceNumber == ifaceno) | 939 | d->bInterfaceNumber == ifaceno) | |
942 | n++; | 940 | n++; | |
943 | } | 941 | } | |
944 | return n; | 942 | return n; | |
945 | } | 943 | } | |
946 | 944 | |||
947 | int | 945 | int | |
948 | usbd_get_interface_altindex(struct usbd_interface *iface) | 946 | usbd_get_interface_altindex(struct usbd_interface *iface) | |
949 | { | 947 | { | |
950 | return iface->ui_altindex; | 948 | return iface->ui_altindex; | |
951 | } | 949 | } | |
952 | 950 | |||
953 | usbd_status | 951 | usbd_status | |
954 | usbd_get_interface(struct usbd_interface *iface, uint8_t *aiface) | 952 | usbd_get_interface(struct usbd_interface *iface, uint8_t *aiface) | |
955 | { | 953 | { | |
956 | usb_device_request_t req; | 954 | usb_device_request_t req; | |
957 | 955 | |||
958 | req.bmRequestType = UT_READ_INTERFACE; | 956 | req.bmRequestType = UT_READ_INTERFACE; | |
959 | req.bRequest = UR_GET_INTERFACE; | 957 | req.bRequest = UR_GET_INTERFACE; | |
960 | USETW(req.wValue, 0); | 958 | USETW(req.wValue, 0); | |
961 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); | 959 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); | |
962 | USETW(req.wLength, 1); | 960 | USETW(req.wLength, 1); | |
963 | return usbd_do_request(iface->ui_dev, &req, aiface); | 961 | return usbd_do_request(iface->ui_dev, &req, aiface); | |
964 | } | 962 | } | |
965 | 963 | |||
966 | /*** Internal routines ***/ | 964 | /*** Internal routines ***/ | |
967 | 965 | |||
968 | /* Dequeue all pipe operations, called with bus lock held. */ | 966 | /* Dequeue all pipe operations, called with bus lock held. */ | |
969 | Static usbd_status | 967 | Static void | |
970 | usbd_ar_pipe(struct usbd_pipe *pipe) | 968 | usbd_ar_pipe(struct usbd_pipe *pipe) | |
971 | { | 969 | { | |
972 | struct usbd_xfer *xfer; | 970 | struct usbd_xfer *xfer; | |
973 | 971 | |||
974 | USBHIST_FUNC(); | 972 | USBHIST_FUNC(); | |
975 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx", (uintptr_t)pipe, 0, 0, 0); | 973 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx", (uintptr_t)pipe, 0, 0, 0); | |
976 | SDT_PROBE1(usb, device, pipe, abort__start, pipe); | 974 | SDT_PROBE1(usb, device, pipe, abort__start, pipe); | |
977 | 975 | |||
978 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | 976 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | |
979 | 977 | |||
980 | #ifdef USB_DEBUG | 978 | #ifdef USB_DEBUG | |
981 | if (usbdebug > 5) | 979 | if (usbdebug > 5) | |
982 | usbd_dump_queue(pipe); | 980 | usbd_dump_queue(pipe); | |
983 | #endif | 981 | #endif | |
984 | pipe->up_repeat = 0; | 982 | pipe->up_repeat = 0; | |
985 | pipe->up_running = 0; | 983 | pipe->up_running = 0; | |
986 | pipe->up_aborting = 1; | 984 | pipe->up_aborting = 1; | |
987 | while ((xfer = SIMPLEQ_FIRST(&pipe->up_queue)) != NULL) { | 985 | while ((xfer = SIMPLEQ_FIRST(&pipe->up_queue)) != NULL) { | |
988 | USBHIST_LOG(usbdebug, "pipe = %#jx xfer = %#jx " | 986 | USBHIST_LOG(usbdebug, "pipe = %#jx xfer = %#jx " | |
989 | "(methods = %#jx)", (uintptr_t)pipe, (uintptr_t)xfer, | 987 | "(methods = %#jx)", (uintptr_t)pipe, (uintptr_t)xfer, | |
990 | (uintptr_t)pipe->up_methods, 0); | 988 | (uintptr_t)pipe->up_methods, 0); | |
991 | if (xfer->ux_status == USBD_NOT_STARTED) { | 989 | if (xfer->ux_status == USBD_NOT_STARTED) { | |
992 | SDT_PROBE1(usb, device, xfer, preabort, xfer); | 990 | SDT_PROBE1(usb, device, xfer, preabort, xfer); | |
993 | #ifdef DIAGNOSTIC | 991 | #ifdef DIAGNOSTIC | |
994 | xfer->ux_state = XFER_BUSY; | 992 | xfer->ux_state = XFER_BUSY; | |
995 | #endif | 993 | #endif | |
996 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); | 994 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); | |
997 | } else { | 995 | } else { | |
998 | /* Make the HC abort it (and invoke the callback). */ | 996 | /* Make the HC abort it (and invoke the callback). */ | |
999 | SDT_PROBE1(usb, device, xfer, abort, xfer); | 997 | SDT_PROBE1(usb, device, xfer, abort, xfer); | |
1000 | pipe->up_methods->upm_abort(xfer); | 998 | pipe->up_methods->upm_abort(xfer); | |
1001 | while (pipe->up_callingxfer == xfer) { | 999 | while (pipe->up_callingxfer == xfer) { | |
1002 | USBHIST_LOG(usbdebug, "wait for callback" | 1000 | USBHIST_LOG(usbdebug, "wait for callback" | |
1003 | "pipe = %#jx xfer = %#jx", | 1001 | "pipe = %#jx xfer = %#jx", | |
1004 | (uintptr_t)pipe, (uintptr_t)xfer, 0, 0); | 1002 | (uintptr_t)pipe, (uintptr_t)xfer, 0, 0); | |
1005 | cv_wait(&pipe->up_callingcv, | 1003 | cv_wait(&pipe->up_callingcv, | |
1006 | pipe->up_dev->ud_bus->ub_lock); | 1004 | pipe->up_dev->ud_bus->ub_lock); | |
1007 | } | 1005 | } | |
1008 | /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ | 1006 | /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ | |
1009 | } | 1007 | } | |
1010 | } | 1008 | } | |
1011 | pipe->up_aborting = 0; | 1009 | pipe->up_aborting = 0; | |
1012 | SDT_PROBE1(usb, device, pipe, abort__done, pipe); | 1010 | SDT_PROBE1(usb, device, pipe, abort__done, pipe); | |
1013 | return USBD_NORMAL_COMPLETION; | |||
1014 | } | 1011 | } | |
1015 | 1012 | |||
1016 | /* Called with USB lock held. */ | 1013 | /* Called with USB lock held. */ | |
1017 | void | 1014 | void | |
1018 | usb_transfer_complete(struct usbd_xfer *xfer) | 1015 | usb_transfer_complete(struct usbd_xfer *xfer) | |
1019 | { | 1016 | { | |
1020 | struct usbd_pipe *pipe = xfer->ux_pipe; | 1017 | struct usbd_pipe *pipe = xfer->ux_pipe; | |
1021 | struct usbd_bus *bus = pipe->up_dev->ud_bus; | 1018 | struct usbd_bus *bus = pipe->up_dev->ud_bus; | |
1022 | int sync = xfer->ux_flags & USBD_SYNCHRONOUS; | 1019 | int sync = xfer->ux_flags & USBD_SYNCHRONOUS; | |
1023 | int erred; | 1020 | int erred; | |
1024 | int polling = bus->ub_usepolling; | 1021 | int polling = bus->ub_usepolling; | |
1025 | int repeat = pipe->up_repeat; | 1022 | int repeat = pipe->up_repeat; | |
1026 | 1023 | |||
1027 | USBHIST_FUNC(); | 1024 | USBHIST_FUNC(); | |
1028 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx xfer = %#jx status = %jd " | 1025 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx xfer = %#jx status = %jd " | |
1029 | "actlen = %jd", (uintptr_t)pipe, (uintptr_t)xfer, xfer->ux_status, | 1026 | "actlen = %jd", (uintptr_t)pipe, (uintptr_t)xfer, xfer->ux_status, | |
1030 | xfer->ux_actlen); | 1027 | xfer->ux_actlen); | |
1031 | 1028 | |||
1032 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | 1029 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | |
1033 | KASSERTMSG(xfer->ux_state == XFER_ONQU, "xfer %p state is %x", xfer, | 1030 | KASSERTMSG(xfer->ux_state == XFER_ONQU, "xfer %p state is %x", xfer, | |
1034 | xfer->ux_state); | 1031 | xfer->ux_state); | |
1035 | KASSERT(pipe != NULL); | 1032 | KASSERT(pipe != NULL); | |
1036 | 1033 | |||
1037 | /* | 1034 | /* | |
1038 | * If device is known to miss out ack, then pretend that | 1035 | * If device is known to miss out ack, then pretend that | |
1039 | * output timeout is a success. Userland should handle | 1036 | * output timeout is a success. Userland should handle | |
1040 | * the logic to verify that the operation succeeded. | 1037 | * the logic to verify that the operation succeeded. | |
1041 | */ | 1038 | */ | |
1042 | if (pipe->up_dev->ud_quirks && | 1039 | if (pipe->up_dev->ud_quirks && | |
1043 | pipe->up_dev->ud_quirks->uq_flags & UQ_MISS_OUT_ACK && | 1040 | pipe->up_dev->ud_quirks->uq_flags & UQ_MISS_OUT_ACK && | |
1044 | xfer->ux_status == USBD_TIMEOUT && | 1041 | xfer->ux_status == USBD_TIMEOUT && | |
1045 | !usbd_xfer_isread(xfer)) { | 1042 | !usbd_xfer_isread(xfer)) { | |
1046 | USBHIST_LOG(usbdebug, "Possible output ack miss for xfer %#jx: " | 1043 | USBHIST_LOG(usbdebug, "Possible output ack miss for xfer %#jx: " | |
1047 | "hiding write timeout to %jd.%jd for %ju bytes written", | 1044 | "hiding write timeout to %jd.%jd for %ju bytes written", | |
1048 | (uintptr_t)xfer, curlwp->l_proc->p_pid, curlwp->l_lid, | 1045 | (uintptr_t)xfer, curlwp->l_proc->p_pid, curlwp->l_lid, | |
1049 | xfer->ux_length); | 1046 | xfer->ux_length); | |
1050 | 1047 | |||
1051 | xfer->ux_status = USBD_NORMAL_COMPLETION; | 1048 | xfer->ux_status = USBD_NORMAL_COMPLETION; | |
1052 | xfer->ux_actlen = xfer->ux_length; | 1049 | xfer->ux_actlen = xfer->ux_length; | |
1053 | } | 1050 | } | |
1054 | 1051 | |||
1055 | erred = xfer->ux_status == USBD_CANCELLED || | 1052 | erred = xfer->ux_status == USBD_CANCELLED || | |
1056 | xfer->ux_status == USBD_TIMEOUT; | 1053 | xfer->ux_status == USBD_TIMEOUT; | |
1057 | 1054 | |||
1058 | if (!repeat) { | 1055 | if (!repeat) { | |
1059 | /* Remove request from queue. */ | 1056 | /* Remove request from queue. */ | |
1060 | 1057 | |||
1061 | KASSERTMSG(!SIMPLEQ_EMPTY(&pipe->up_queue), | 1058 | KASSERTMSG(!SIMPLEQ_EMPTY(&pipe->up_queue), | |
1062 | "pipe %p is empty, but xfer %p wants to complete", pipe, | 1059 | "pipe %p is empty, but xfer %p wants to complete", pipe, | |
1063 | xfer); | 1060 | xfer); | |
1064 | KASSERTMSG(xfer == SIMPLEQ_FIRST(&pipe->up_queue), | 1061 | KASSERTMSG(xfer == SIMPLEQ_FIRST(&pipe->up_queue), | |
1065 | "xfer %p is not start of queue (%p is at start)", xfer, | 1062 | "xfer %p is not start of queue (%p is at start)", xfer, | |
1066 | SIMPLEQ_FIRST(&pipe->up_queue)); | 1063 | SIMPLEQ_FIRST(&pipe->up_queue)); | |
1067 | 1064 | |||
1068 | #ifdef DIAGNOSTIC | 1065 | #ifdef DIAGNOSTIC | |
1069 | xfer->ux_state = XFER_BUSY; | 1066 | xfer->ux_state = XFER_BUSY; | |
1070 | #endif | 1067 | #endif | |
1071 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); | 1068 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); | |
1072 | } | 1069 | } | |
1073 | USBHIST_LOG(usbdebug, "xfer %#jx: repeat %jd new head = %#jx", | 1070 | USBHIST_LOG(usbdebug, "xfer %#jx: repeat %jd new head = %#jx", | |
1074 | (uintptr_t)xfer, repeat, (uintptr_t)SIMPLEQ_FIRST(&pipe->up_queue), | 1071 | (uintptr_t)xfer, repeat, (uintptr_t)SIMPLEQ_FIRST(&pipe->up_queue), | |
1075 | 0); | 1072 | 0); | |
1076 | 1073 | |||
1077 | /* Count completed transfers. */ | 1074 | /* Count completed transfers. */ | |
1078 | ++pipe->up_dev->ud_bus->ub_stats.uds_requests | 1075 | ++pipe->up_dev->ud_bus->ub_stats.uds_requests | |
1079 | [pipe->up_endpoint->ue_edesc->bmAttributes & UE_XFERTYPE]; | 1076 | [pipe->up_endpoint->ue_edesc->bmAttributes & UE_XFERTYPE]; | |
1080 | 1077 | |||
1081 | xfer->ux_done = 1; | 1078 | xfer->ux_done = 1; | |
1082 | if (!xfer->ux_status && xfer->ux_actlen < xfer->ux_length && | 1079 | if (!xfer->ux_status && xfer->ux_actlen < xfer->ux_length && | |
1083 | !(xfer->ux_flags & USBD_SHORT_XFER_OK)) { | 1080 | !(xfer->ux_flags & USBD_SHORT_XFER_OK)) { | |
1084 | USBHIST_LOG(usbdebug, "short transfer %jd < %jd", | 1081 | USBHIST_LOG(usbdebug, "short transfer %jd < %jd", | |
1085 | xfer->ux_actlen, xfer->ux_length, 0, 0); | 1082 | xfer->ux_actlen, xfer->ux_length, 0, 0); | |
1086 | xfer->ux_status = USBD_SHORT_XFER; | 1083 | xfer->ux_status = USBD_SHORT_XFER; | |
1087 | } | 1084 | } | |
1088 | 1085 | |||
1089 | USBHIST_LOG(usbdebug, "xfer %#jx doing done %#jx", (uintptr_t)xfer, | 1086 | USBHIST_LOG(usbdebug, "xfer %#jx doing done %#jx", (uintptr_t)xfer, | |
1090 | (uintptr_t)pipe->up_methods->upm_done, 0, 0); | 1087 | (uintptr_t)pipe->up_methods->upm_done, 0, 0); | |
1091 | SDT_PROBE2(usb, device, xfer, done, xfer, xfer->ux_status); | 1088 | SDT_PROBE2(usb, device, xfer, done, xfer, xfer->ux_status); | |
1092 | pipe->up_methods->upm_done(xfer); | 1089 | pipe->up_methods->upm_done(xfer); | |
1093 | 1090 | |||
1094 | if (xfer->ux_length != 0 && xfer->ux_buffer != xfer->ux_buf) { | 1091 | if (xfer->ux_length != 0 && xfer->ux_buffer != xfer->ux_buf) { | |
1095 | KDASSERTMSG(xfer->ux_actlen <= xfer->ux_length, | 1092 | KDASSERTMSG(xfer->ux_actlen <= xfer->ux_length, | |
1096 | "actlen %d length %d",xfer->ux_actlen, xfer->ux_length); | 1093 | "actlen %d length %d",xfer->ux_actlen, xfer->ux_length); | |
1097 | 1094 | |||
1098 | /* Only if IN transfer */ | 1095 | /* Only if IN transfer */ | |
1099 | if (usbd_xfer_isread(xfer)) { | 1096 | if (usbd_xfer_isread(xfer)) { | |
1100 | memcpy(xfer->ux_buffer, xfer->ux_buf, xfer->ux_actlen); | 1097 | memcpy(xfer->ux_buffer, xfer->ux_buf, xfer->ux_actlen); | |
1101 | } | 1098 | } | |
1102 | } | 1099 | } | |
1103 | 1100 | |||
1104 | USBHIST_LOG(usbdebug, "xfer %#jx doing callback %#jx status %jd", | 1101 | USBHIST_LOG(usbdebug, "xfer %#jx doing callback %#jx status %jd", | |
1105 | (uintptr_t)xfer, (uintptr_t)xfer->ux_callback, xfer->ux_status, 0); | 1102 | (uintptr_t)xfer, (uintptr_t)xfer->ux_callback, xfer->ux_status, 0); | |
1106 | 1103 | |||
1107 | if (xfer->ux_callback) { | 1104 | if (xfer->ux_callback) { | |
1108 | if (!polling) { | 1105 | if (!polling) { | |
1109 | KASSERT(pipe->up_callingxfer == NULL); | 1106 | KASSERT(pipe->up_callingxfer == NULL); | |
1110 | pipe->up_callingxfer = xfer; | 1107 | pipe->up_callingxfer = xfer; | |
1111 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); | 1108 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); | |
1112 | if (!(pipe->up_flags & USBD_MPSAFE)) | 1109 | if (!(pipe->up_flags & USBD_MPSAFE)) | |
1113 | KERNEL_LOCK(1, curlwp); | 1110 | KERNEL_LOCK(1, curlwp); | |
1114 | } | 1111 | } | |
1115 | 1112 | |||
1116 | xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status); | 1113 | xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status); | |
1117 | 1114 | |||
1118 | if (!polling) { | 1115 | if (!polling) { | |
1119 | if (!(pipe->up_flags & USBD_MPSAFE)) | 1116 | if (!(pipe->up_flags & USBD_MPSAFE)) | |
1120 | KERNEL_UNLOCK_ONE(curlwp); | 1117 | KERNEL_UNLOCK_ONE(curlwp); | |
1121 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); | 1118 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); | |
1122 | KASSERT(pipe->up_callingxfer == xfer); | 1119 | KASSERT(pipe->up_callingxfer == xfer); | |
1123 | pipe->up_callingxfer = NULL; | 1120 | pipe->up_callingxfer = NULL; | |
1124 | cv_broadcast(&pipe->up_callingcv); | 1121 | cv_broadcast(&pipe->up_callingcv); | |
1125 | } | 1122 | } | |
1126 | } | 1123 | } | |
1127 | 1124 | |||
1128 | if (sync && !polling) { | 1125 | if (sync && !polling) { | |
1129 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, wakeup", | 1126 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, wakeup", | |
1130 | (uintptr_t)xfer, 0, 0, 0); | 1127 | (uintptr_t)xfer, 0, 0, 0); | |
1131 | cv_broadcast(&xfer->ux_cv); | 1128 | cv_broadcast(&xfer->ux_cv); | |
1132 | } | 1129 | } | |
1133 | 1130 | |||
1134 | if (repeat) { | 1131 | if (repeat) { | |
1135 | xfer->ux_actlen = 0; | 1132 | xfer->ux_actlen = 0; | |
1136 | xfer->ux_status = USBD_NOT_STARTED; | 1133 | xfer->ux_status = USBD_NOT_STARTED; | |
1137 | } else { | 1134 | } else { | |
1138 | /* XXX should we stop the queue on all errors? */ | 1135 | /* XXX should we stop the queue on all errors? */ | |
1139 | if (erred && pipe->up_iface != NULL) /* not control pipe */ | 1136 | if (erred && pipe->up_iface != NULL) /* not control pipe */ | |
1140 | pipe->up_running = 0; | 1137 | pipe->up_running = 0; | |
1141 | } | 1138 | } | |
1142 | if (pipe->up_running && pipe->up_serialise) | 1139 | if (pipe->up_running && pipe->up_serialise) | |
1143 | usbd_start_next(pipe); | 1140 | usbd_start_next(pipe); | |
1144 | } | 1141 | } | |
1145 | 1142 | |||
1146 | /* Called with USB lock held. */ | 1143 | /* Called with USB lock held. */ | |
1147 | static usbd_status | 1144 | static usbd_status | |
1148 | usb_insert_transfer(struct usbd_xfer *xfer) | 1145 | usb_insert_transfer(struct usbd_xfer *xfer) | |
1149 | { | 1146 | { | |
1150 | struct usbd_pipe *pipe = xfer->ux_pipe; | 1147 | struct usbd_pipe *pipe = xfer->ux_pipe; | |
1151 | usbd_status err; | 1148 | usbd_status err; | |
1152 | 1149 | |||
1153 | USBHIST_FUNC(); USBHIST_CALLARGS(usbdebug, | 1150 | USBHIST_FUNC(); USBHIST_CALLARGS(usbdebug, | |
1154 | "xfer = %#jx pipe = %#jx running = %jd timeout = %jd", | 1151 | "xfer = %#jx pipe = %#jx running = %jd timeout = %jd", | |
1155 | (uintptr_t)xfer, (uintptr_t)pipe, | 1152 | (uintptr_t)xfer, (uintptr_t)pipe, | |
1156 | pipe->up_running, xfer->ux_timeout); | 1153 | pipe->up_running, xfer->ux_timeout); | |
1157 | 1154 | |||
1158 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | 1155 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | |
1159 | KASSERTMSG(xfer->ux_state == XFER_BUSY, "xfer %p state is %x", xfer, | 1156 | KASSERTMSG(xfer->ux_state == XFER_BUSY, "xfer %p state is %x", xfer, | |
1160 | xfer->ux_state); | 1157 | xfer->ux_state); | |
1161 | 1158 | |||
1162 | #ifdef DIAGNOSTIC | 1159 | #ifdef DIAGNOSTIC | |
1163 | xfer->ux_state = XFER_ONQU; | 1160 | xfer->ux_state = XFER_ONQU; | |
1164 | #endif | 1161 | #endif | |
1165 | SIMPLEQ_INSERT_TAIL(&pipe->up_queue, xfer, ux_next); | 1162 | SIMPLEQ_INSERT_TAIL(&pipe->up_queue, xfer, ux_next); | |
1166 | if (pipe->up_running && pipe->up_serialise) | 1163 | if (pipe->up_running && pipe->up_serialise) | |
1167 | err = USBD_IN_PROGRESS; | 1164 | err = USBD_IN_PROGRESS; | |
1168 | else { | 1165 | else { | |
1169 | pipe->up_running = 1; | 1166 | pipe->up_running = 1; | |
1170 | err = USBD_NORMAL_COMPLETION; | 1167 | err = USBD_NORMAL_COMPLETION; | |
1171 | } | 1168 | } | |
1172 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, err %jd", (uintptr_t)xfer, | 1169 | USBHIST_LOG(usbdebug, "<- done xfer %#jx, err %jd", (uintptr_t)xfer, | |
1173 | err, 0, 0); | 1170 | err, 0, 0); | |
1174 | return err; | 1171 | return err; | |
1175 | } | 1172 | } | |
1176 | 1173 | |||
1177 | /* Called with USB lock held. */ | 1174 | /* Called with USB lock held. */ | |
1178 | void | 1175 | void | |
1179 | usbd_start_next(struct usbd_pipe *pipe) | 1176 | usbd_start_next(struct usbd_pipe *pipe) | |
1180 | { | 1177 | { | |
1181 | struct usbd_xfer *xfer; | 1178 | struct usbd_xfer *xfer; | |
1182 | usbd_status err; | 1179 | usbd_status err; | |
1183 | 1180 | |||
1184 | USBHIST_FUNC(); | 1181 | USBHIST_FUNC(); | |
1185 | 1182 | |||
1186 | KASSERT(pipe != NULL); | 1183 | KASSERT(pipe != NULL); | |
1187 | KASSERT(pipe->up_methods != NULL); | 1184 | KASSERT(pipe->up_methods != NULL); | |
1188 | KASSERT(pipe->up_methods->upm_start != NULL); | 1185 | KASSERT(pipe->up_methods->upm_start != NULL); | |
1189 | KASSERT(pipe->up_serialise == true); | 1186 | KASSERT(pipe->up_serialise == true); | |
1190 | 1187 | |||
1191 | int polling = pipe->up_dev->ud_bus->ub_usepolling; | 1188 | int polling = pipe->up_dev->ud_bus->ub_usepolling; | |
1192 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | 1189 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | |
1193 | 1190 | |||
1194 | /* Get next request in queue. */ | 1191 | /* Get next request in queue. */ | |
1195 | xfer = SIMPLEQ_FIRST(&pipe->up_queue); | 1192 | xfer = SIMPLEQ_FIRST(&pipe->up_queue); | |
1196 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx, xfer = %#jx", (uintptr_t)pipe, | 1193 | USBHIST_CALLARGS(usbdebug, "pipe = %#jx, xfer = %#jx", (uintptr_t)pipe, | |
1197 | (uintptr_t)xfer, 0, 0); | 1194 | (uintptr_t)xfer, 0, 0); | |
1198 | if (xfer == NULL) { | 1195 | if (xfer == NULL) { | |
1199 | pipe->up_running = 0; | 1196 | pipe->up_running = 0; | |
1200 | } else { | 1197 | } else { | |
1201 | if (!polling) | 1198 | if (!polling) | |
1202 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); | 1199 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); | |
1203 | SDT_PROBE2(usb, device, pipe, start, pipe, xfer); | 1200 | SDT_PROBE2(usb, device, pipe, start, pipe, xfer); | |
1204 | err = pipe->up_methods->upm_start(xfer); | 1201 | err = pipe->up_methods->upm_start(xfer); | |
1205 | if (!polling) | 1202 | if (!polling) | |
1206 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); | 1203 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); | |
1207 | 1204 | |||
1208 | if (err != USBD_IN_PROGRESS) { | 1205 | if (err != USBD_IN_PROGRESS) { | |
1209 | USBHIST_LOG(usbdebug, "error = %jd", err, 0, 0, 0); | 1206 | USBHIST_LOG(usbdebug, "error = %jd", err, 0, 0, 0); | |
1210 | pipe->up_running = 0; | 1207 | pipe->up_running = 0; | |
1211 | /* XXX do what? */ | 1208 | /* XXX do what? */ | |
1212 | } | 1209 | } | |
1213 | } | 1210 | } | |
1214 | 1211 | |||
1215 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | 1212 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | |
1216 | } | 1213 | } | |
1217 | 1214 | |||
1218 | usbd_status | 1215 | usbd_status | |
1219 | usbd_do_request(struct usbd_device *dev, usb_device_request_t *req, void *data) | 1216 | usbd_do_request(struct usbd_device *dev, usb_device_request_t *req, void *data) | |
1220 | { | 1217 | { | |
1221 | 1218 | |||
1222 | return usbd_do_request_flags(dev, req, data, 0, 0, | 1219 | return usbd_do_request_flags(dev, req, data, 0, 0, | |
1223 | USBD_DEFAULT_TIMEOUT); | 1220 | USBD_DEFAULT_TIMEOUT); | |
1224 | } | 1221 | } | |
1225 | 1222 | |||
1226 | usbd_status | 1223 | usbd_status | |
1227 | usbd_do_request_flags(struct usbd_device *dev, usb_device_request_t *req, | 1224 | usbd_do_request_flags(struct usbd_device *dev, usb_device_request_t *req, | |
1228 | void *data, uint16_t flags, int *actlen, uint32_t timeout) | 1225 | void *data, uint16_t flags, int *actlen, uint32_t timeout) | |
1229 | { | 1226 | { | |
1230 | size_t len = UGETW(req->wLength); | 1227 | size_t len = UGETW(req->wLength); | |
1231 | 1228 | |||
1232 | return usbd_do_request_len(dev, req, len, data, flags, actlen, timeout); | 1229 | return usbd_do_request_len(dev, req, len, data, flags, actlen, timeout); | |
1233 | } | 1230 | } | |
1234 | 1231 | |||
1235 | usbd_status | 1232 | usbd_status | |
1236 | usbd_do_request_len(struct usbd_device *dev, usb_device_request_t *req, | 1233 | usbd_do_request_len(struct usbd_device *dev, usb_device_request_t *req, | |
1237 | size_t len, void *data, uint16_t flags, int *actlen, uint32_t timeout) | 1234 | size_t len, void *data, uint16_t flags, int *actlen, uint32_t timeout) | |
1238 | { | 1235 | { | |
1239 | struct usbd_xfer *xfer; | 1236 | struct usbd_xfer *xfer; | |
1240 | usbd_status err; | 1237 | usbd_status err; | |
1241 | 1238 | |||
1242 | KASSERT(len >= UGETW(req->wLength)); | 1239 | KASSERT(len >= UGETW(req->wLength)); | |
1243 | 1240 | |||
1244 | USBHIST_FUNC(); | 1241 | USBHIST_FUNC(); | |
1245 | USBHIST_CALLARGS(usbdebug, "dev=%#jx req=%jx flags=%jx len=%jx", | 1242 | USBHIST_CALLARGS(usbdebug, "dev=%#jx req=%jx flags=%jx len=%jx", | |
1246 | (uintptr_t)dev, (uintptr_t)req, flags, len); | 1243 | (uintptr_t)dev, (uintptr_t)req, flags, len); | |
1247 | 1244 | |||
1248 | ASSERT_SLEEPABLE(); | 1245 | ASSERT_SLEEPABLE(); | |
1249 | 1246 | |||
1250 | int error = usbd_create_xfer(dev->ud_pipe0, len, 0, 0, &xfer); | 1247 | int error = usbd_create_xfer(dev->ud_pipe0, len, 0, 0, &xfer); | |
1251 | if (error) | 1248 | if (error) | |
1252 | return USBD_NOMEM; | 1249 | return USBD_NOMEM; | |
1253 | 1250 | |||
1254 | usbd_setup_default_xfer(xfer, dev, 0, timeout, req, data, | 1251 | usbd_setup_default_xfer(xfer, dev, 0, timeout, req, data, | |
1255 | UGETW(req->wLength), flags, NULL); | 1252 | UGETW(req->wLength), flags, NULL); | |
1256 | KASSERT(xfer->ux_pipe == dev->ud_pipe0); | 1253 | KASSERT(xfer->ux_pipe == dev->ud_pipe0); | |
1257 | err = usbd_sync_transfer(xfer); | 1254 | err = usbd_sync_transfer(xfer); | |
1258 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) | 1255 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) | |
1259 | if (xfer->ux_actlen > xfer->ux_length) { | 1256 | if (xfer->ux_actlen > xfer->ux_length) { | |
1260 | USBHIST_LOG(usbdebug, "overrun addr = %jd type = 0x%02jx", | 1257 | USBHIST_LOG(usbdebug, "overrun addr = %jd type = 0x%02jx", | |
1261 | dev->ud_addr, xfer->ux_request.bmRequestType, 0, 0); | 1258 | dev->ud_addr, xfer->ux_request.bmRequestType, 0, 0); | |
1262 | USBHIST_LOG(usbdebug, " req = 0x%02jx val = %jd " | 1259 | USBHIST_LOG(usbdebug, " req = 0x%02jx val = %jd " | |
1263 | "index = %jd", | 1260 | "index = %jd", | |
1264 | xfer->ux_request.bRequest, UGETW(xfer->ux_request.wValue), | 1261 | xfer->ux_request.bRequest, UGETW(xfer->ux_request.wValue), | |
1265 | UGETW(xfer->ux_request.wIndex), 0); | 1262 | UGETW(xfer->ux_request.wIndex), 0); | |
1266 | USBHIST_LOG(usbdebug, " rlen = %jd length = %jd " | 1263 | USBHIST_LOG(usbdebug, " rlen = %jd length = %jd " | |
1267 | "actlen = %jd", | 1264 | "actlen = %jd", | |
1268 | UGETW(xfer->ux_request.wLength), | 1265 | UGETW(xfer->ux_request.wLength), | |
1269 | xfer->ux_length, xfer->ux_actlen, 0); | 1266 | xfer->ux_length, xfer->ux_actlen, 0); | |
1270 | } | 1267 | } | |
1271 | #endif | 1268 | #endif | |
1272 | if (actlen != NULL) | 1269 | if (actlen != NULL) | |
1273 | *actlen = xfer->ux_actlen; | 1270 | *actlen = xfer->ux_actlen; | |
1274 | 1271 | |||
1275 | usbd_destroy_xfer(xfer); | 1272 | usbd_destroy_xfer(xfer); | |
1276 | 1273 | |||
1277 | if (err) { | 1274 | if (err) { | |
1278 | USBHIST_LOG(usbdebug, "returning err = %jd", err, 0, 0, 0); | 1275 | USBHIST_LOG(usbdebug, "returning err = %jd", err, 0, 0, 0); | |
1279 | } | 1276 | } | |
1280 | return err; | 1277 | return err; | |
1281 | } | 1278 | } | |
1282 | 1279 | |||
1283 | static void | 1280 | static void | |
1284 | usbd_request_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) | 1281 | usbd_request_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) | |
1285 | { | 1282 | { | |
1286 | usbd_destroy_xfer(xfer); | 1283 | usbd_destroy_xfer(xfer); | |
1287 | } | 1284 | } | |
1288 | 1285 | |||
1289 | /* | 1286 | /* | |
1290 | * Execute a request without waiting for completion. | 1287 | * Execute a request without waiting for completion. | |
1291 | * Can be used from interrupt context. | 1288 | * Can be used from interrupt context. | |
1292 | */ | 1289 | */ | |
1293 | usbd_status | 1290 | usbd_status | |
1294 | usbd_request_async(struct usbd_device *dev, struct usbd_xfer *xfer, | 1291 | usbd_request_async(struct usbd_device *dev, struct usbd_xfer *xfer, | |
1295 | usb_device_request_t *req, void *priv, usbd_callback callback) | 1292 | usb_device_request_t *req, void *priv, usbd_callback callback) | |
1296 | { | 1293 | { | |
1297 | usbd_status err; | 1294 | usbd_status err; | |
1298 | 1295 | |||
1299 | if (callback == NULL) | 1296 | if (callback == NULL) | |
1300 | callback = usbd_request_async_cb; | 1297 | callback = usbd_request_async_cb; | |
1301 | 1298 | |||
1302 | usbd_setup_default_xfer(xfer, dev, priv, | 1299 | usbd_setup_default_xfer(xfer, dev, priv, | |
1303 | USBD_DEFAULT_TIMEOUT, req, NULL, UGETW(req->wLength), 0, | 1300 | USBD_DEFAULT_TIMEOUT, req, NULL, UGETW(req->wLength), 0, | |
1304 | callback); | 1301 | callback); | |
1305 | err = usbd_transfer(xfer); | 1302 | err = usbd_transfer(xfer); | |
1306 | if (err != USBD_IN_PROGRESS) { | 1303 | if (err != USBD_IN_PROGRESS) { | |
1307 | usbd_destroy_xfer(xfer); | 1304 | usbd_destroy_xfer(xfer); | |
1308 | return (err); | 1305 | return (err); | |
1309 | } | 1306 | } | |
1310 | return (USBD_NORMAL_COMPLETION); | 1307 | return (USBD_NORMAL_COMPLETION); | |
1311 | } | 1308 | } | |
1312 | 1309 | |||
1313 | const struct usbd_quirks * | 1310 | const struct usbd_quirks * | |
1314 | usbd_get_quirks(struct usbd_device *dev) | 1311 | usbd_get_quirks(struct usbd_device *dev) | |
1315 | { | 1312 | { | |
1316 | #ifdef DIAGNOSTIC | 1313 | #ifdef DIAGNOSTIC | |
1317 | if (dev == NULL) { | 1314 | if (dev == NULL) { | |
1318 | printf("usbd_get_quirks: dev == NULL\n"); | 1315 | printf("usbd_get_quirks: dev == NULL\n"); | |
1319 | return 0; | 1316 | return 0; | |
1320 | } | 1317 | } | |
1321 | #endif | 1318 | #endif | |
1322 | return dev->ud_quirks; | 1319 | return dev->ud_quirks; | |
1323 | } | 1320 | } | |
1324 | 1321 | |||
1325 | /* XXX do periodic free() of free list */ | 1322 | /* XXX do periodic free() of free list */ | |
1326 | 1323 | |||
1327 | /* | 1324 | /* | |
1328 | * Called from keyboard driver when in polling mode. | 1325 | * Called from keyboard driver when in polling mode. | |
1329 | */ | 1326 | */ | |
1330 | void | 1327 | void | |
1331 | usbd_dopoll(struct usbd_interface *iface) | 1328 | usbd_dopoll(struct usbd_interface *iface) | |
1332 | { | 1329 | { | |
1333 | iface->ui_dev->ud_bus->ub_methods->ubm_dopoll(iface->ui_dev->ud_bus); | 1330 | iface->ui_dev->ud_bus->ub_methods->ubm_dopoll(iface->ui_dev->ud_bus); | |
1334 | } | 1331 | } | |
1335 | 1332 | |||
1336 | /* | 1333 | /* | |
1337 | * This is for keyboard driver as well, which only operates in polling | 1334 | * This is for keyboard driver as well, which only operates in polling | |
1338 | * mode from the ask root, etc., prompt and from DDB. | 1335 | * mode from the ask root, etc., prompt and from DDB. | |
1339 | */ | 1336 | */ | |
1340 | void | 1337 | void | |
1341 | usbd_set_polling(struct usbd_device *dev, int on) | 1338 | usbd_set_polling(struct usbd_device *dev, int on) | |
1342 | { | 1339 | { | |
1343 | if (on) | 1340 | if (on) | |
1344 | dev->ud_bus->ub_usepolling++; | 1341 | dev->ud_bus->ub_usepolling++; | |
1345 | else | 1342 | else | |
1346 | dev->ud_bus->ub_usepolling--; | 1343 | dev->ud_bus->ub_usepolling--; | |
1347 | 1344 | |||
1348 | /* Kick the host controller when switching modes */ | 1345 | /* Kick the host controller when switching modes */ | |
1349 | mutex_enter(dev->ud_bus->ub_lock); | 1346 | mutex_enter(dev->ud_bus->ub_lock); | |
1350 | dev->ud_bus->ub_methods->ubm_softint(dev->ud_bus); | 1347 | dev->ud_bus->ub_methods->ubm_softint(dev->ud_bus); | |
1351 | mutex_exit(dev->ud_bus->ub_lock); | 1348 | mutex_exit(dev->ud_bus->ub_lock); | |
1352 | } | 1349 | } | |
1353 | 1350 | |||
1354 | 1351 | |||
1355 | usb_endpoint_descriptor_t * | 1352 | usb_endpoint_descriptor_t * | |
1356 | usbd_get_endpoint_descriptor(struct usbd_interface *iface, uint8_t address) | 1353 | usbd_get_endpoint_descriptor(struct usbd_interface *iface, uint8_t address) | |
1357 | { | 1354 | { | |
1358 | struct usbd_endpoint *ep; | 1355 | struct usbd_endpoint *ep; | |
1359 | int i; | 1356 | int i; | |
1360 | 1357 | |||
1361 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { | 1358 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { | |
1362 | ep = &iface->ui_endpoints[i]; | 1359 | ep = &iface->ui_endpoints[i]; | |
1363 | if (ep->ue_edesc->bEndpointAddress == address) | 1360 | if (ep->ue_edesc->bEndpointAddress == address) | |
1364 | return iface->ui_endpoints[i].ue_edesc; | 1361 | return iface->ui_endpoints[i].ue_edesc; | |
1365 | } | 1362 | } | |
1366 | return NULL; | 1363 | return NULL; | |
1367 | } | 1364 | } | |
1368 | 1365 | |||
1369 | /* | 1366 | /* | |
1370 | * usbd_ratecheck() can limit the number of error messages that occurs. | 1367 | * usbd_ratecheck() can limit the number of error messages that occurs. | |
1371 | * When a device is unplugged it may take up to 0.25s for the hub driver | 1368 | * When a device is unplugged it may take up to 0.25s for the hub driver | |
1372 | * to notice it. If the driver continuously tries to do I/O operations | 1369 | * to notice it. If the driver continuously tries to do I/O operations | |
1373 | * this can generate a large number of messages. | 1370 | * this can generate a large number of messages. | |
1374 | */ | 1371 | */ | |
1375 | int | 1372 | int | |
1376 | usbd_ratecheck(struct timeval *last) | 1373 | usbd_ratecheck(struct timeval *last) | |
1377 | { | 1374 | { | |
1378 | static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ | 1375 | static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ | |
1379 | 1376 | |||
1380 | return ratecheck(last, &errinterval); | 1377 | return ratecheck(last, &errinterval); | |
1381 | } | 1378 | } | |
1382 | 1379 | |||
1383 | /* | 1380 | /* | |
1384 | * Search for a vendor/product pair in an array. The item size is | 1381 | * Search for a vendor/product pair in an array. The item size is | |
1385 | * given as an argument. | 1382 | * given as an argument. | |
1386 | */ | 1383 | */ | |
1387 | const struct usb_devno * | 1384 | const struct usb_devno * | |
1388 | usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz, | 1385 | usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz, | |
1389 | uint16_t vendor, uint16_t product) | 1386 | uint16_t vendor, uint16_t product) | |
1390 | { | 1387 | { | |
1391 | while (nentries-- > 0) { | 1388 | while (nentries-- > 0) { | |
1392 | uint16_t tproduct = tbl->ud_product; | 1389 | uint16_t tproduct = tbl->ud_product; | |
1393 | if (tbl->ud_vendor == vendor && | 1390 | if (tbl->ud_vendor == vendor && | |
1394 | (tproduct == product || tproduct == USB_PRODUCT_ANY)) | 1391 | (tproduct == product || tproduct == USB_PRODUCT_ANY)) | |
1395 | return tbl; | 1392 | return tbl; | |
1396 | tbl = (const struct usb_devno *)((const char *)tbl + sz); | 1393 | tbl = (const struct usb_devno *)((const char *)tbl + sz); | |
1397 | } | 1394 | } | |
1398 | return NULL; | 1395 | return NULL; | |
1399 | } | 1396 | } | |
1400 | 1397 | |||
1401 | usbd_status | 1398 | usbd_status | |
1402 | usbd_get_string(struct usbd_device *dev, int si, char *buf) | 1399 | usbd_get_string(struct usbd_device *dev, int si, char *buf) | |
1403 | { | 1400 | { | |
1404 | return usbd_get_string0(dev, si, buf, 1); | 1401 | return usbd_get_string0(dev, si, buf, 1); | |
1405 | } | 1402 | } | |
1406 | 1403 | |||
1407 | usbd_status | 1404 | usbd_status | |
1408 | usbd_get_string0(struct usbd_device *dev, int si, char *buf, int unicode) | 1405 | usbd_get_string0(struct usbd_device *dev, int si, char *buf, int unicode) | |
1409 | { | 1406 | { | |
1410 | int swap = dev->ud_quirks->uq_flags & UQ_SWAP_UNICODE; | 1407 | int swap = dev->ud_quirks->uq_flags & UQ_SWAP_UNICODE; | |
1411 | usb_string_descriptor_t us; | 1408 | usb_string_descriptor_t us; | |
1412 | char *s; | 1409 | char *s; | |
1413 | int i, n; | 1410 | int i, n; | |
1414 | uint16_t c; | 1411 | uint16_t c; | |
1415 | usbd_status err; | 1412 | usbd_status err; | |
1416 | int size; | 1413 | int size; | |
1417 | 1414 | |||
1418 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | 1415 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | |
1419 | 1416 | |||
1420 | buf[0] = '\0'; | 1417 | buf[0] = '\0'; | |
1421 | if (si == 0) | 1418 | if (si == 0) | |
1422 | return USBD_INVAL; | 1419 | return USBD_INVAL; | |
1423 | if (dev->ud_quirks->uq_flags & UQ_NO_STRINGS) | 1420 | if (dev->ud_quirks->uq_flags & UQ_NO_STRINGS) | |
1424 | return USBD_STALLED; | 1421 | return USBD_STALLED; | |
1425 | if (dev->ud_langid == USBD_NOLANG) { | 1422 | if (dev->ud_langid == USBD_NOLANG) { | |
1426 | /* Set up default language */ | 1423 | /* Set up default language */ | |
1427 | err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us, | 1424 | err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us, | |
1428 | &size); | 1425 | &size); | |
1429 | if (err || size < 4) { | 1426 | if (err || size < 4) { | |
1430 | USBHIST_LOG(usbdebug, "getting lang failed, using 0", | 1427 | USBHIST_LOG(usbdebug, "getting lang failed, using 0", | |
1431 | 0, 0, 0, 0); | 1428 | 0, 0, 0, 0); | |
1432 | dev->ud_langid = 0; /* Well, just pick something then */ | 1429 | dev->ud_langid = 0; /* Well, just pick something then */ | |
1433 | } else { | 1430 | } else { | |
1434 | /* Pick the first language as the default. */ | 1431 | /* Pick the first language as the default. */ | |
1435 | dev->ud_langid = UGETW(us.bString[0]); | 1432 | dev->ud_langid = UGETW(us.bString[0]); | |
1436 | } | 1433 | } | |
1437 | } | 1434 | } | |
1438 | err = usbd_get_string_desc(dev, si, dev->ud_langid, &us, &size); | 1435 | err = usbd_get_string_desc(dev, si, dev->ud_langid, &us, &size); | |
1439 | if (err) | 1436 | if (err) | |
1440 | return err; | 1437 | return err; | |
1441 | s = buf; | 1438 | s = buf; | |
1442 | n = size / 2 - 1; | 1439 | n = size / 2 - 1; | |
1443 | if (unicode) { | 1440 | if (unicode) { | |
1444 | for (i = 0; i < n; i++) { | 1441 | for (i = 0; i < n; i++) { | |
1445 | c = UGETW(us.bString[i]); | 1442 | c = UGETW(us.bString[i]); | |
1446 | if (swap) | 1443 | if (swap) | |
1447 | c = (c >> 8) | (c << 8); | 1444 | c = (c >> 8) | (c << 8); | |
1448 | s += wput_utf8(s, 3, c); | 1445 | s += wput_utf8(s, 3, c); | |
1449 | } | 1446 | } | |
1450 | *s++ = 0; | 1447 | *s++ = 0; | |
1451 | } | 1448 | } | |
1452 | #ifdef COMPAT_30 | 1449 | #ifdef COMPAT_30 | |
1453 | else { | 1450 | else { | |
1454 | for (i = 0; i < n; i++) { | 1451 | for (i = 0; i < n; i++) { | |
1455 | c = UGETW(us.bString[i]); | 1452 | c = UGETW(us.bString[i]); | |
1456 | if (swap) | 1453 | if (swap) | |
1457 | c = (c >> 8) | (c << 8); | 1454 | c = (c >> 8) | (c << 8); | |
1458 | *s++ = (c < 0x80) ? c : '?'; | 1455 | *s++ = (c < 0x80) ? c : '?'; | |
1459 | } | 1456 | } | |
1460 | *s++ = 0; | 1457 | *s++ = 0; | |
1461 | } | 1458 | } | |
1462 | #endif | 1459 | #endif | |
1463 | return USBD_NORMAL_COMPLETION; | 1460 | return USBD_NORMAL_COMPLETION; | |
1464 | } | 1461 | } | |
1465 | 1462 | |||
1466 | /* | 1463 | /* | |
1467 | * usbd_xfer_trycomplete(xfer) | 1464 | * usbd_xfer_trycomplete(xfer) | |
1468 | * | 1465 | * | |
1469 | * Try to claim xfer for completion. Return true if successful, | 1466 | * Try to claim xfer for completion. Return true if successful, | |
1470 | * false if the xfer has been synchronously aborted or has timed | 1467 | * false if the xfer has been synchronously aborted or has timed | |
1471 | * out. | 1468 | * out. | |
1472 | * | 1469 | * | |
1473 | * If this returns true, caller is responsible for setting | 1470 | * If this returns true, caller is responsible for setting | |
1474 | * xfer->ux_status and calling usb_transfer_complete. To be used | 1471 | * xfer->ux_status and calling usb_transfer_complete. To be used | |
1475 | * in a host controller interrupt handler. | 1472 | * in a host controller interrupt handler. | |
1476 | * | 1473 | * | |
1477 | * Caller must either hold the bus lock or have the bus in polling | 1474 | * Caller must either hold the bus lock or have the bus in polling | |
1478 | * mode. | 1475 | * mode. | |
1479 | */ | 1476 | */ | |
1480 | bool | 1477 | bool | |
1481 | usbd_xfer_trycomplete(struct usbd_xfer *xfer) | 1478 | usbd_xfer_trycomplete(struct usbd_xfer *xfer) | |
1482 | { | 1479 | { | |
1483 | struct usbd_bus *bus __diagused = xfer->ux_bus; | 1480 | struct usbd_bus *bus __diagused = xfer->ux_bus; | |
1484 | 1481 | |||
1485 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | 1482 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | |
1486 | 1483 | |||
1487 | /* | 1484 | /* | |
1488 | * If software has completed it, either by synchronous abort or | 1485 | * If software has completed it, either by synchronous abort or | |
1489 | * by timeout, too late. | 1486 | * by timeout, too late. | |
1490 | */ | 1487 | */ | |
1491 | if (xfer->ux_status != USBD_IN_PROGRESS) | 1488 | if (xfer->ux_status != USBD_IN_PROGRESS) | |
1492 | return false; | 1489 | return false; | |
1493 | 1490 | |||
1494 | /* | 1491 | /* | |
1495 | * We are completing the xfer. Cancel the timeout if we can, | 1492 | * We are completing the xfer. Cancel the timeout if we can, | |
1496 | * but only asynchronously. See usbd_xfer_cancel_timeout_async | 1493 | * but only asynchronously. See usbd_xfer_cancel_timeout_async | |
1497 | * for why we need not wait for the callout or task here. | 1494 | * for why we need not wait for the callout or task here. | |
1498 | */ | 1495 | */ | |
1499 | usbd_xfer_cancel_timeout_async(xfer); | 1496 | usbd_xfer_cancel_timeout_async(xfer); | |
1500 | 1497 | |||
1501 | /* Success! Note: Caller must set xfer->ux_status afterwar. */ | 1498 | /* Success! Note: Caller must set xfer->ux_status afterwar. */ | |
1502 | return true; | 1499 | return true; | |
1503 | } | 1500 | } | |
1504 | 1501 | |||
1505 | /* | 1502 | /* | |
1506 | * usbd_xfer_abort(xfer) | 1503 | * usbd_xfer_abort(xfer) | |
1507 | * | 1504 | * | |
1508 | * Try to claim xfer to abort. If successful, mark it completed | 1505 | * Try to claim xfer to abort. If successful, mark it completed | |
1509 | * with USBD_CANCELLED and call the bus-specific method to abort | 1506 | * with USBD_CANCELLED and call the bus-specific method to abort | |
1510 | * at the hardware level. | 1507 | * at the hardware level. | |
1511 | * | 1508 | * | |
1512 | * To be called in thread context from struct | 1509 | * To be called in thread context from struct | |
1513 | * usbd_pipe_methods::upm_abort. | 1510 | * usbd_pipe_methods::upm_abort. | |
1514 | * | 1511 | * | |
1515 | * Caller must hold the bus lock. | 1512 | * Caller must hold the bus lock. | |
1516 | */ | 1513 | */ | |
1517 | void | 1514 | void | |
1518 | usbd_xfer_abort(struct usbd_xfer *xfer) | 1515 | usbd_xfer_abort(struct usbd_xfer *xfer) | |
1519 | { | 1516 | { | |
1520 | struct usbd_bus *bus = xfer->ux_bus; | 1517 | struct usbd_bus *bus = xfer->ux_bus; | |
1521 | 1518 | |||
1522 | KASSERT(mutex_owned(bus->ub_lock)); | 1519 | KASSERT(mutex_owned(bus->ub_lock)); | |
1523 | 1520 | |||
1524 | /* | 1521 | /* | |
1525 | * If host controller interrupt or timer interrupt has | 1522 | * If host controller interrupt or timer interrupt has | |
1526 | * completed it, too late. But the xfer cannot be | 1523 | * completed it, too late. But the xfer cannot be | |
1527 | * cancelled already -- only one caller can synchronously | 1524 | * cancelled already -- only one caller can synchronously | |
1528 | * abort. | 1525 | * abort. | |
1529 | */ | 1526 | */ | |
1530 | KASSERT(xfer->ux_status != USBD_CANCELLED); | 1527 | KASSERT(xfer->ux_status != USBD_CANCELLED); | |
1531 | if (xfer->ux_status != USBD_IN_PROGRESS) | 1528 | if (xfer->ux_status != USBD_IN_PROGRESS) | |
1532 | return; | 1529 | return; | |
1533 | 1530 | |||
1534 | /* | 1531 | /* | |
1535 | * Cancel the timeout if we can, but only asynchronously; see | 1532 | * Cancel the timeout if we can, but only asynchronously; see | |
1536 | * usbd_xfer_cancel_timeout_async for why we need not wait for | 1533 | * usbd_xfer_cancel_timeout_async for why we need not wait for | |
1537 | * the callout or task here. | 1534 | * the callout or task here. | |
1538 | */ | 1535 | */ | |
1539 | usbd_xfer_cancel_timeout_async(xfer); | 1536 | usbd_xfer_cancel_timeout_async(xfer); | |
1540 | 1537 | |||
1541 | /* | 1538 | /* | |
1542 | * We beat everyone else. Claim the status as cancelled and do | 1539 | * We beat everyone else. Claim the status as cancelled and do | |
1543 | * the bus-specific dance to abort the hardware. | 1540 | * the bus-specific dance to abort the hardware. | |
1544 | */ | 1541 | */ | |
1545 | xfer->ux_status = USBD_CANCELLED; | 1542 | xfer->ux_status = USBD_CANCELLED; | |
1546 | bus->ub_methods->ubm_abortx(xfer); | 1543 | bus->ub_methods->ubm_abortx(xfer); | |
1547 | } | 1544 | } | |
1548 | 1545 | |||
1549 | /* | 1546 | /* | |
1550 | * usbd_xfer_timeout(xfer) | 1547 | * usbd_xfer_timeout(xfer) | |
1551 | * | 1548 | * | |
1552 | * Called at IPL_SOFTCLOCK when too much time has elapsed waiting | 1549 | * Called at IPL_SOFTCLOCK when too much time has elapsed waiting | |
1553 | * for xfer to complete. Since we can't abort the xfer at | 1550 | * for xfer to complete. Since we can't abort the xfer at | |
1554 | * IPL_SOFTCLOCK, defer to a usb_task to run it in thread context, | 1551 | * IPL_SOFTCLOCK, defer to a usb_task to run it in thread context, | |
1555 | * unless the xfer has completed or aborted concurrently -- and if | 1552 | * unless the xfer has completed or aborted concurrently -- and if | |
1556 | * the xfer has also been resubmitted, take care of rescheduling | 1553 | * the xfer has also been resubmitted, take care of rescheduling | |
1557 | * the callout. | 1554 | * the callout. | |
1558 | */ | 1555 | */ | |
1559 | static void | 1556 | static void | |
1560 | usbd_xfer_timeout(void *cookie) | 1557 | usbd_xfer_timeout(void *cookie) | |
1561 | { | 1558 | { | |
1562 | struct usbd_xfer *xfer = cookie; | 1559 | struct usbd_xfer *xfer = cookie; | |
1563 | struct usbd_bus *bus = xfer->ux_bus; | 1560 | struct usbd_bus *bus = xfer->ux_bus; | |
1564 | struct usbd_device *dev = xfer->ux_pipe->up_dev; | 1561 | struct usbd_device *dev = xfer->ux_pipe->up_dev; | |
1565 | 1562 | |||
1566 | /* Acquire the lock so we can transition the timeout state. */ | 1563 | /* Acquire the lock so we can transition the timeout state. */ | |
1567 | mutex_enter(bus->ub_lock); | 1564 | mutex_enter(bus->ub_lock); | |
1568 | 1565 | |||
1569 | /* | 1566 | /* | |
1570 | * Use usbd_xfer_probe_timeout to check whether the timeout is | 1567 | * Use usbd_xfer_probe_timeout to check whether the timeout is | |
1571 | * still valid, or to reschedule the callout if necessary. If | 1568 | * still valid, or to reschedule the callout if necessary. If | |
1572 | * it is still valid, schedule the task. | 1569 | * it is still valid, schedule the task. | |
1573 | */ | 1570 | */ | |
1574 | if (usbd_xfer_probe_timeout(xfer)) | 1571 | if (usbd_xfer_probe_timeout(xfer)) | |
1575 | usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC); | 1572 | usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC); | |
1576 | 1573 | |||
1577 | /* | 1574 | /* | |
1578 | * Notify usbd_xfer_cancel_timeout_async that we may have | 1575 | * Notify usbd_xfer_cancel_timeout_async that we may have | |
1579 | * scheduled the task. This causes callout_invoking to return | 1576 | * scheduled the task. This causes callout_invoking to return | |
1580 | * false in usbd_xfer_cancel_timeout_async so that it can tell | 1577 | * false in usbd_xfer_cancel_timeout_async so that it can tell | |
1581 | * which stage in the callout->task->abort process we're at. | 1578 | * which stage in the callout->task->abort process we're at. | |
1582 | */ | 1579 | */ | |
1583 | callout_ack(&xfer->ux_callout); | 1580 | callout_ack(&xfer->ux_callout); | |
1584 | 1581 | |||
1585 | /* All done -- release the lock. */ | 1582 | /* All done -- release the lock. */ | |
1586 | mutex_exit(bus->ub_lock); | 1583 | mutex_exit(bus->ub_lock); | |
1587 | } | 1584 | } | |
1588 | 1585 | |||
1589 | /* | 1586 | /* | |
1590 | * usbd_xfer_timeout_task(xfer) | 1587 | * usbd_xfer_timeout_task(xfer) | |
1591 | * | 1588 | * | |
1592 | * Called in thread context when too much time has elapsed waiting | 1589 | * Called in thread context when too much time has elapsed waiting | |
1593 | * for xfer to complete. Abort the xfer with USBD_TIMEOUT, unless | 1590 | * for xfer to complete. Abort the xfer with USBD_TIMEOUT, unless | |
1594 | * it has completed or aborted concurrently -- and if the xfer has | 1591 | * it has completed or aborted concurrently -- and if the xfer has | |
1595 | * also been resubmitted, take care of rescheduling the callout. | 1592 | * also been resubmitted, take care of rescheduling the callout. | |
1596 | */ | 1593 | */ | |
1597 | static void | 1594 | static void | |
1598 | usbd_xfer_timeout_task(void *cookie) | 1595 | usbd_xfer_timeout_task(void *cookie) | |
1599 | { | 1596 | { | |
1600 | struct usbd_xfer *xfer = cookie; | 1597 | struct usbd_xfer *xfer = cookie; | |
1601 | struct usbd_bus *bus = xfer->ux_bus; | 1598 | struct usbd_bus *bus = xfer->ux_bus; | |
1602 | 1599 | |||
1603 | /* Acquire the lock so we can transition the timeout state. */ | 1600 | /* Acquire the lock so we can transition the timeout state. */ | |
1604 | mutex_enter(bus->ub_lock); | 1601 | mutex_enter(bus->ub_lock); | |
1605 | 1602 | |||
1606 | /* | 1603 | /* | |
1607 | * Use usbd_xfer_probe_timeout to check whether the timeout is | 1604 | * Use usbd_xfer_probe_timeout to check whether the timeout is | |
1608 | * still valid, or to reschedule the callout if necessary. If | 1605 | * still valid, or to reschedule the callout if necessary. If | |
1609 | * it is not valid -- the timeout has been asynchronously | 1606 | * it is not valid -- the timeout has been asynchronously | |
1610 | * cancelled, or the xfer has already been resubmitted -- then | 1607 | * cancelled, or the xfer has already been resubmitted -- then | |
1611 | * we're done here. | 1608 | * we're done here. | |
1612 | */ | 1609 | */ | |
1613 | if (!usbd_xfer_probe_timeout(xfer)) | 1610 | if (!usbd_xfer_probe_timeout(xfer)) | |
1614 | goto out; | 1611 | goto out; | |
1615 | 1612 | |||
1616 | /* | 1613 | /* | |
1617 | * May have completed or been aborted, but we're the only one | 1614 | * May have completed or been aborted, but we're the only one | |
1618 | * who can time it out. If it has completed or been aborted, | 1615 | * who can time it out. If it has completed or been aborted, | |
1619 | * no need to timeout. | 1616 | * no need to timeout. | |
1620 | */ | 1617 | */ | |
1621 | KASSERT(xfer->ux_status != USBD_TIMEOUT); | 1618 | KASSERT(xfer->ux_status != USBD_TIMEOUT); | |
1622 | if (xfer->ux_status != USBD_IN_PROGRESS) | 1619 | if (xfer->ux_status != USBD_IN_PROGRESS) | |
1623 | goto out; | 1620 | goto out; | |
1624 | 1621 | |||
1625 | /* | 1622 | /* | |
1626 | * We beat everyone else. Claim the status as timed out and do | 1623 | * We beat everyone else. Claim the status as timed out and do | |
1627 | * the bus-specific dance to abort the hardware. | 1624 | * the bus-specific dance to abort the hardware. | |
1628 | */ | 1625 | */ | |
1629 | xfer->ux_status = USBD_TIMEOUT; | 1626 | xfer->ux_status = USBD_TIMEOUT; | |
1630 | bus->ub_methods->ubm_abortx(xfer); | 1627 | bus->ub_methods->ubm_abortx(xfer); | |
1631 | 1628 | |||
1632 | out: /* All done -- release the lock. */ | 1629 | out: /* All done -- release the lock. */ | |
1633 | mutex_exit(bus->ub_lock); | 1630 | mutex_exit(bus->ub_lock); | |
1634 | } | 1631 | } | |
1635 | 1632 | |||
1636 | /* | 1633 | /* | |
1637 | * usbd_xfer_probe_timeout(xfer) | 1634 | * usbd_xfer_probe_timeout(xfer) | |
1638 | * | 1635 | * | |
1639 | * Probe the status of xfer's timeout. Acknowledge and process a | 1636 | * Probe the status of xfer's timeout. Acknowledge and process a | |
1640 | * request to reschedule. Return true if the timeout is still | 1637 | * request to reschedule. Return true if the timeout is still | |
1641 | * valid and the caller should take further action (queueing a | 1638 | * valid and the caller should take further action (queueing a | |
1642 | * task or aborting the xfer), false if it must stop here. | 1639 | * task or aborting the xfer), false if it must stop here. | |
1643 | */ | 1640 | */ | |
1644 | static bool | 1641 | static bool | |
1645 | usbd_xfer_probe_timeout(struct usbd_xfer *xfer) | 1642 | usbd_xfer_probe_timeout(struct usbd_xfer *xfer) | |
1646 | { | 1643 | { | |
1647 | struct usbd_bus *bus = xfer->ux_bus; | 1644 | struct usbd_bus *bus = xfer->ux_bus; | |
1648 | bool valid; | 1645 | bool valid; | |
1649 | 1646 | |||
1650 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | 1647 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | |
1651 | 1648 | |||
1652 | /* The timeout must be set. */ | 1649 | /* The timeout must be set. */ | |
1653 | KASSERT(xfer->ux_timeout_set); | 1650 | KASSERT(xfer->ux_timeout_set); | |
1654 | 1651 | |||
1655 | /* | 1652 | /* | |
1656 | * Neither callout nor task may be pending; they execute | 1653 | * Neither callout nor task may be pending; they execute | |
1657 | * alternately in lock step. | 1654 | * alternately in lock step. | |
1658 | */ | 1655 | */ | |
1659 | KASSERT(!callout_pending(&xfer->ux_callout)); | 1656 | KASSERT(!callout_pending(&xfer->ux_callout)); | |
1660 | KASSERT(!usb_task_pending(xfer->ux_pipe->up_dev, &xfer->ux_aborttask)); | 1657 | KASSERT(!usb_task_pending(xfer->ux_pipe->up_dev, &xfer->ux_aborttask)); | |
1661 | 1658 | |||
1662 | /* There are a few cases... */ | 1659 | /* There are a few cases... */ | |
1663 | if (bus->ub_methods->ubm_dying(bus)) { | 1660 | if (bus->ub_methods->ubm_dying(bus)) { | |
1664 | /* Host controller dying. Drop it all on the floor. */ | 1661 | /* Host controller dying. Drop it all on the floor. */ | |
1665 | xfer->ux_timeout_set = false; | 1662 | xfer->ux_timeout_set = false; | |
1666 | xfer->ux_timeout_reset = false; | 1663 | xfer->ux_timeout_reset = false; | |
1667 | valid = false; | 1664 | valid = false; | |
1668 | } else if (xfer->ux_timeout_reset) { | 1665 | } else if (xfer->ux_timeout_reset) { | |
1669 | /* | 1666 | /* | |
1670 | * The xfer completed _and_ got resubmitted while we | 1667 | * The xfer completed _and_ got resubmitted while we | |
1671 | * waited for the lock. Acknowledge the request to | 1668 | * waited for the lock. Acknowledge the request to | |
1672 | * reschedule, and reschedule it if there is a timeout | 1669 | * reschedule, and reschedule it if there is a timeout | |
1673 | * and the bus is not polling. | 1670 | * and the bus is not polling. | |
1674 | */ | 1671 | */ | |
1675 | xfer->ux_timeout_reset = false; | 1672 | xfer->ux_timeout_reset = false; | |
1676 | if (xfer->ux_timeout && !bus->ub_usepolling) { | 1673 | if (xfer->ux_timeout && !bus->ub_usepolling) { | |
1677 | KASSERT(xfer->ux_timeout_set); | 1674 | KASSERT(xfer->ux_timeout_set); | |
1678 | callout_schedule(&xfer->ux_callout, | 1675 | callout_schedule(&xfer->ux_callout, | |
1679 | mstohz(xfer->ux_timeout)); | 1676 | mstohz(xfer->ux_timeout)); | |
1680 | } else { | 1677 | } else { | |
1681 | /* No more callout or task scheduled. */ | 1678 | /* No more callout or task scheduled. */ | |
1682 | xfer->ux_timeout_set = false; | 1679 | xfer->ux_timeout_set = false; | |
1683 | } | 1680 | } | |
1684 | valid = false; | 1681 | valid = false; | |
1685 | } else if (xfer->ux_status != USBD_IN_PROGRESS) { | 1682 | } else if (xfer->ux_status != USBD_IN_PROGRESS) { | |
1686 | /* | 1683 | /* | |
1687 | * The xfer has completed by hardware completion or by | 1684 | * The xfer has completed by hardware completion or by | |
1688 | * software abort, and has not been resubmitted, so the | 1685 | * software abort, and has not been resubmitted, so the | |
1689 | * timeout must be unset, and is no longer valid for | 1686 | * timeout must be unset, and is no longer valid for | |
1690 | * the caller. | 1687 | * the caller. | |
1691 | */ | 1688 | */ | |
1692 | xfer->ux_timeout_set = false; | 1689 | xfer->ux_timeout_set = false; | |
1693 | valid = false; | 1690 | valid = false; | |
1694 | } else { | 1691 | } else { | |
1695 | /* | 1692 | /* | |
1696 | * The xfer has not yet completed, so the timeout is | 1693 | * The xfer has not yet completed, so the timeout is | |
1697 | * valid. | 1694 | * valid. | |
1698 | */ | 1695 | */ | |
1699 | valid = true; | 1696 | valid = true; | |
1700 | } | 1697 | } | |
1701 | 1698 | |||
1702 | /* Any reset must have been processed. */ | 1699 | /* Any reset must have been processed. */ | |
1703 | KASSERT(!xfer->ux_timeout_reset); | 1700 | KASSERT(!xfer->ux_timeout_reset); | |
1704 | 1701 | |||
1705 | /* | 1702 | /* | |
1706 | * Either we claim the timeout is set, or the callout is idle. | 1703 | * Either we claim the timeout is set, or the callout is idle. | |
1707 | * If the timeout is still set, we may be handing off to the | 1704 | * If the timeout is still set, we may be handing off to the | |
1708 | * task instead, so this is an if but not an iff. | 1705 | * task instead, so this is an if but not an iff. | |
1709 | */ | 1706 | */ | |
1710 | KASSERT(xfer->ux_timeout_set || !callout_pending(&xfer->ux_callout)); | 1707 | KASSERT(xfer->ux_timeout_set || !callout_pending(&xfer->ux_callout)); | |
1711 | 1708 | |||
1712 | /* | 1709 | /* | |
1713 | * The task must be idle now. | 1710 | * The task must be idle now. | |
1714 | * | 1711 | * | |
1715 | * - If the caller is the callout, _and_ the timeout is still | 1712 | * - If the caller is the callout, _and_ the timeout is still | |
1716 | * valid, the caller will schedule it, but it hasn't been | 1713 | * valid, the caller will schedule it, but it hasn't been | |
1717 | * scheduled yet. (If the timeout is not valid, the task | 1714 | * scheduled yet. (If the timeout is not valid, the task | |
1718 | * should not be scheduled.) | 1715 | * should not be scheduled.) | |
1719 | * | 1716 | * | |
1720 | * - If the caller is the task, it cannot be scheduled again | 1717 | * - If the caller is the task, it cannot be scheduled again | |
1721 | * until the callout runs again, which won't happen until we | 1718 | * until the callout runs again, which won't happen until we | |
1722 | * next release the lock. | 1719 | * next release the lock. | |
1723 | */ | 1720 | */ | |
1724 | KASSERT(!usb_task_pending(xfer->ux_pipe->up_dev, &xfer->ux_aborttask)); | 1721 | KASSERT(!usb_task_pending(xfer->ux_pipe->up_dev, &xfer->ux_aborttask)); | |
1725 | 1722 | |||
1726 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | 1723 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | |
1727 | 1724 | |||
1728 | return valid; | 1725 | return valid; | |
1729 | } | 1726 | } | |
1730 | 1727 | |||
1731 | /* | 1728 | /* | |
1732 | * usbd_xfer_schedule_timeout(xfer) | 1729 | * usbd_xfer_schedule_timeout(xfer) | |
1733 | * | 1730 | * | |
1734 | * Ensure that xfer has a timeout. If the callout is already | 1731 | * Ensure that xfer has a timeout. If the callout is already | |
1735 | * queued or the task is already running, request that they | 1732 | * queued or the task is already running, request that they | |
1736 | * reschedule the callout. If not, and if we're not polling, | 1733 | * reschedule the callout. If not, and if we're not polling, | |
1737 | * schedule the callout anew. | 1734 | * schedule the callout anew. | |
1738 | * | 1735 | * | |
1739 | * To be called in thread context from struct | 1736 | * To be called in thread context from struct | |
1740 | * usbd_pipe_methods::upm_start. | 1737 | * usbd_pipe_methods::upm_start. | |
1741 | */ | 1738 | */ | |
1742 | void | 1739 | void | |
1743 | usbd_xfer_schedule_timeout(struct usbd_xfer *xfer) | 1740 | usbd_xfer_schedule_timeout(struct usbd_xfer *xfer) | |
1744 | { | 1741 | { | |
1745 | struct usbd_bus *bus = xfer->ux_bus; | 1742 | struct usbd_bus *bus = xfer->ux_bus; | |
1746 | 1743 | |||
1747 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | 1744 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | |
1748 | 1745 | |||
1749 | if (xfer->ux_timeout_set) { | 1746 | if (xfer->ux_timeout_set) { | |
1750 | /* | 1747 | /* | |
1751 | * Callout or task has fired from a prior completed | 1748 | * Callout or task has fired from a prior completed | |
1752 | * xfer but has not yet noticed that the xfer is done. | 1749 | * xfer but has not yet noticed that the xfer is done. | |
1753 | * Ask it to reschedule itself to ux_timeout. | 1750 | * Ask it to reschedule itself to ux_timeout. | |
1754 | */ | 1751 | */ | |
1755 | xfer->ux_timeout_reset = true; | 1752 | xfer->ux_timeout_reset = true; | |
1756 | } else if (xfer->ux_timeout && !bus->ub_usepolling) { | 1753 | } else if (xfer->ux_timeout && !bus->ub_usepolling) { | |
1757 | /* Callout is not scheduled. Schedule it. */ | 1754 | /* Callout is not scheduled. Schedule it. */ | |
1758 | KASSERT(!callout_pending(&xfer->ux_callout)); | 1755 | KASSERT(!callout_pending(&xfer->ux_callout)); | |
1759 | callout_schedule(&xfer->ux_callout, mstohz(xfer->ux_timeout)); | 1756 | callout_schedule(&xfer->ux_callout, mstohz(xfer->ux_timeout)); | |
1760 | xfer->ux_timeout_set = true; | 1757 | xfer->ux_timeout_set = true; | |
1761 | } | 1758 | } | |
1762 | 1759 | |||
1763 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | 1760 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | |
1764 | } | 1761 | } | |
1765 | 1762 | |||
1766 | /* | 1763 | /* | |
1767 | * usbd_xfer_cancel_timeout_async(xfer) | 1764 | * usbd_xfer_cancel_timeout_async(xfer) | |
1768 | * | 1765 | * | |
1769 | * Cancel the callout and the task of xfer, which have not yet run | 1766 | * Cancel the callout and the task of xfer, which have not yet run | |
1770 | * to completion, but don't wait for the callout or task to finish | 1767 | * to completion, but don't wait for the callout or task to finish | |
1771 | * running. | 1768 | * running. | |
1772 | * | 1769 | * | |
1773 | * If they have already fired, at worst they are waiting for the | 1770 | * If they have already fired, at worst they are waiting for the | |
1774 | * bus lock. They will see that the xfer is no longer in progress | 1771 | * bus lock. They will see that the xfer is no longer in progress | |
1775 | * and give up, or they will see that the xfer has been | 1772 | * and give up, or they will see that the xfer has been | |
1776 | * resubmitted with a new timeout and reschedule the callout. | 1773 | * resubmitted with a new timeout and reschedule the callout. | |
1777 | * | 1774 | * | |
1778 | * If a resubmitted request completed so fast that the callout | 1775 | * If a resubmitted request completed so fast that the callout | |
1779 | * didn't have time to process a timer reset, just cancel the | 1776 | * didn't have time to process a timer reset, just cancel the | |
1780 | * timer reset. | 1777 | * timer reset. | |
1781 | */ | 1778 | */ | |
1782 | static void | 1779 | static void | |
1783 | usbd_xfer_cancel_timeout_async(struct usbd_xfer *xfer) | 1780 | usbd_xfer_cancel_timeout_async(struct usbd_xfer *xfer) | |
1784 | { | 1781 | { | |
1785 | struct usbd_bus *bus __diagused = xfer->ux_bus; | 1782 | struct usbd_bus *bus __diagused = xfer->ux_bus; | |
1786 | 1783 | |||
1787 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | 1784 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | |
1788 | 1785 | |||
1789 | /* | 1786 | /* | |
1790 | * If the timer wasn't running anyway, forget about it. This | 1787 | * If the timer wasn't running anyway, forget about it. This | |
1791 | * can happen if we are completing an isochronous transfer | 1788 | * can happen if we are completing an isochronous transfer | |
1792 | * which doesn't use the same timeout logic. | 1789 | * which doesn't use the same timeout logic. | |
1793 | */ | 1790 | */ | |
1794 | if (!xfer->ux_timeout_set) | 1791 | if (!xfer->ux_timeout_set) | |
1795 | return; | 1792 | return; | |
1796 | 1793 | |||
1797 | xfer->ux_timeout_reset = false; | 1794 | xfer->ux_timeout_reset = false; | |
1798 | if (!callout_stop(&xfer->ux_callout)) { | 1795 | if (!callout_stop(&xfer->ux_callout)) { | |
1799 | /* | 1796 | /* | |
1800 | * We stopped the callout before it ran. The timeout | 1797 | * We stopped the callout before it ran. The timeout | |
1801 | * is no longer set. | 1798 | * is no longer set. | |
1802 | */ | 1799 | */ | |
1803 | xfer->ux_timeout_set = false; | 1800 | xfer->ux_timeout_set = false; | |
1804 | } else if (callout_invoking(&xfer->ux_callout)) { | 1801 | } else if (callout_invoking(&xfer->ux_callout)) { | |
1805 | /* | 1802 | /* | |
1806 | * The callout has begun to run but it has not yet | 1803 | * The callout has begun to run but it has not yet | |
1807 | * acquired the lock and called callout_ack. The task | 1804 | * acquired the lock and called callout_ack. The task | |
1808 | * cannot be queued yet, and the callout cannot have | 1805 | * cannot be queued yet, and the callout cannot have | |
1809 | * been rescheduled yet. | 1806 | * been rescheduled yet. | |
1810 | * | 1807 | * | |
1811 | * By the time the callout acquires the lock, we will | 1808 | * By the time the callout acquires the lock, we will | |
1812 | * have transitioned from USBD_IN_PROGRESS to a | 1809 | * have transitioned from USBD_IN_PROGRESS to a | |
1813 | * completed status, and possibly also resubmitted the | 1810 | * completed status, and possibly also resubmitted the | |
1814 | * xfer and set xfer->ux_timeout_reset = true. In both | 1811 | * xfer and set xfer->ux_timeout_reset = true. In both | |
1815 | * cases, the callout will DTRT, so no further action | 1812 | * cases, the callout will DTRT, so no further action | |
1816 | * is needed here. | 1813 | * is needed here. | |
1817 | */ | 1814 | */ | |
1818 | } else if (usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask)) { | 1815 | } else if (usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask)) { | |
1819 | /* | 1816 | /* | |
1820 | * The callout had fired and scheduled the task, but we | 1817 | * The callout had fired and scheduled the task, but we | |
1821 | * stopped the task before it could run. The timeout | 1818 | * stopped the task before it could run. The timeout | |
1822 | * is therefore no longer set -- the next resubmission | 1819 | * is therefore no longer set -- the next resubmission | |
1823 | * of the xfer must schedule a new timeout. | 1820 | * of the xfer must schedule a new timeout. | |
1824 | * | 1821 | * | |
1825 | * The callout should not be pending at this point: | 1822 | * The callout should not be pending at this point: | |
1826 | * it is scheduled only under the lock, and only when | 1823 | * it is scheduled only under the lock, and only when | |
1827 | * xfer->ux_timeout_set is false, or by the callout or | 1824 | * xfer->ux_timeout_set is false, or by the callout or | |
1828 | * task itself when xfer->ux_timeout_reset is true. | 1825 | * task itself when xfer->ux_timeout_reset is true. | |
1829 | */ | 1826 | */ | |
1830 | xfer->ux_timeout_set = false; | 1827 | xfer->ux_timeout_set = false; | |
1831 | } | 1828 | } | |
1832 | 1829 | |||
1833 | /* | 1830 | /* | |
1834 | * The callout cannot be scheduled and the task cannot be | 1831 | * The callout cannot be scheduled and the task cannot be | |
1835 | * queued at this point. Either we cancelled them, or they are | 1832 | * queued at this point. Either we cancelled them, or they are | |
1836 | * already running and waiting for the bus lock. | 1833 | * already running and waiting for the bus lock. | |
1837 | */ | 1834 | */ | |
1838 | KASSERT(!callout_pending(&xfer->ux_callout)); | 1835 | KASSERT(!callout_pending(&xfer->ux_callout)); | |
1839 | KASSERT(!usb_task_pending(xfer->ux_pipe->up_dev, &xfer->ux_aborttask)); | 1836 | KASSERT(!usb_task_pending(xfer->ux_pipe->up_dev, &xfer->ux_aborttask)); | |
1840 | 1837 | |||
1841 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | 1838 | KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock)); | |
1842 | } | 1839 | } |
--- src/sys/dev/usb/usbdi.h 2022/02/14 09:22:30 1.104
+++ src/sys/dev/usb/usbdi.h 2022/03/03 06:05:38 1.105
@@ -1,318 +1,318 @@ | @@ -1,318 +1,318 @@ | |||
1 | /* $NetBSD: usbdi.h,v 1.104 2022/02/14 09:22:30 riastradh Exp $ */ | 1 | /* $NetBSD: usbdi.h,v 1.105 2022/03/03 06:05:38 riastradh Exp $ */ | |
2 | /* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */ | 2 | /* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | 5 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | |
6 | * All rights reserved. | 6 | * All rights reserved. | |
7 | * | 7 | * | |
8 | * This code is derived from software contributed to The NetBSD Foundation | 8 | * This code is derived from software contributed to The NetBSD Foundation | |
9 | * by Lennart Augustsson (lennart@augustsson.net) at | 9 | * by Lennart Augustsson (lennart@augustsson.net) at | |
10 | * Carlstedt Research & Technology. | 10 | * Carlstedt Research & Technology. | |
11 | * | 11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | 14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | 15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | 16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | 17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | 18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | 19 | * documentation and/or other materials provided with the distribution. | |
20 | * | 20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | * POSSIBILITY OF SUCH DAMAGE. | 31 | * POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | 32 | */ | |
33 | 33 | |||
34 | #ifndef _USBDI_H_ | 34 | #ifndef _USBDI_H_ | |
35 | #define _USBDI_H_ | 35 | #define _USBDI_H_ | |
36 | 36 | |||
37 | #include <sys/types.h> | 37 | #include <sys/types.h> | |
38 | 38 | |||
39 | #include <dev/usb/usb.h> | 39 | #include <dev/usb/usb.h> | |
40 | 40 | |||
41 | struct usbd_bus; | 41 | struct usbd_bus; | |
42 | struct usbd_device; | 42 | struct usbd_device; | |
43 | struct usbd_interface; | 43 | struct usbd_interface; | |
44 | struct usbd_pipe; | 44 | struct usbd_pipe; | |
45 | struct usbd_xfer; | 45 | struct usbd_xfer; | |
46 | 46 | |||
47 | typedef enum { /* keep in sync with usbd_error_strs */ | 47 | typedef enum { /* keep in sync with usbd_error_strs */ | |
48 | USBD_NORMAL_COMPLETION = 0, /* must be 0 */ | 48 | USBD_NORMAL_COMPLETION = 0, /* must be 0 */ | |
49 | USBD_IN_PROGRESS, /* 1 */ | 49 | USBD_IN_PROGRESS, /* 1 */ | |
50 | /* errors */ | 50 | /* errors */ | |
51 | USBD_PENDING_REQUESTS, /* 2 */ | 51 | USBD_PENDING_REQUESTS, /* 2 */ | |
52 | USBD_NOT_STARTED, /* 3 */ | 52 | USBD_NOT_STARTED, /* 3 */ | |
53 | USBD_INVAL, /* 4 */ | 53 | USBD_INVAL, /* 4 */ | |
54 | USBD_NOMEM, /* 5 */ | 54 | USBD_NOMEM, /* 5 */ | |
55 | USBD_CANCELLED, /* 6 */ | 55 | USBD_CANCELLED, /* 6 */ | |
56 | USBD_BAD_ADDRESS, /* 7 */ | 56 | USBD_BAD_ADDRESS, /* 7 */ | |
57 | USBD_IN_USE, /* 8 */ | 57 | USBD_IN_USE, /* 8 */ | |
58 | USBD_NO_ADDR, /* 9 */ | 58 | USBD_NO_ADDR, /* 9 */ | |
59 | USBD_SET_ADDR_FAILED, /* 10 */ | 59 | USBD_SET_ADDR_FAILED, /* 10 */ | |
60 | USBD_NO_POWER, /* 11 */ | 60 | USBD_NO_POWER, /* 11 */ | |
61 | USBD_TOO_DEEP, /* 12 */ | 61 | USBD_TOO_DEEP, /* 12 */ | |
62 | USBD_IOERROR, /* 13 */ | 62 | USBD_IOERROR, /* 13 */ | |
63 | USBD_NOT_CONFIGURED, /* 14 */ | 63 | USBD_NOT_CONFIGURED, /* 14 */ | |
64 | USBD_TIMEOUT, /* 15 */ | 64 | USBD_TIMEOUT, /* 15 */ | |
65 | USBD_SHORT_XFER, /* 16 */ | 65 | USBD_SHORT_XFER, /* 16 */ | |
66 | USBD_STALLED, /* 17 */ | 66 | USBD_STALLED, /* 17 */ | |
67 | USBD_INTERRUPTED, /* 18 */ | 67 | USBD_INTERRUPTED, /* 18 */ | |
68 | 68 | |||
69 | USBD_ERROR_MAX /* must be last */ | 69 | USBD_ERROR_MAX /* must be last */ | |
70 | } usbd_status; | 70 | } usbd_status; | |
71 | 71 | |||
72 | typedef void (*usbd_callback)(struct usbd_xfer *, void *, usbd_status); | 72 | typedef void (*usbd_callback)(struct usbd_xfer *, void *, usbd_status); | |
73 | 73 | |||
74 | /* Use default (specified by ep. desc.) interval on interrupt pipe */ | 74 | /* Use default (specified by ep. desc.) interval on interrupt pipe */ | |
75 | #define USBD_DEFAULT_INTERVAL (-1) | 75 | #define USBD_DEFAULT_INTERVAL (-1) | |
76 | 76 | |||
77 | /* Open flags */ | 77 | /* Open flags */ | |
78 | #define USBD_EXCLUSIVE_USE 0x01 | 78 | #define USBD_EXCLUSIVE_USE 0x01 | |
79 | #define USBD_MPSAFE 0x80 | 79 | #define USBD_MPSAFE 0x80 | |
80 | 80 | |||
81 | /* Request flags */ | 81 | /* Request flags */ | |
82 | #define USBD_SYNCHRONOUS 0x02 /* wait for completion */ | 82 | #define USBD_SYNCHRONOUS 0x02 /* wait for completion */ | |
83 | /* in usb.h #define USBD_SHORT_XFER_OK 0x04*/ /* allow short reads */ | 83 | /* in usb.h #define USBD_SHORT_XFER_OK 0x04*/ /* allow short reads */ | |
84 | #define USBD_FORCE_SHORT_XFER 0x08 /* force last short packet on write */ | 84 | #define USBD_FORCE_SHORT_XFER 0x08 /* force last short packet on write */ | |
85 | #define USBD_SYNCHRONOUS_SIG 0x10 /* if waiting for completion, | 85 | #define USBD_SYNCHRONOUS_SIG 0x10 /* if waiting for completion, | |
86 | * also take signals */ | 86 | * also take signals */ | |
87 | 87 | |||
88 | #define USBD_NO_TIMEOUT 0 | 88 | #define USBD_NO_TIMEOUT 0 | |
89 | #define USBD_DEFAULT_TIMEOUT 5000 /* ms = 5 s */ | 89 | #define USBD_DEFAULT_TIMEOUT 5000 /* ms = 5 s */ | |
90 | #define USBD_CONFIG_TIMEOUT (3*USBD_DEFAULT_TIMEOUT) | 90 | #define USBD_CONFIG_TIMEOUT (3*USBD_DEFAULT_TIMEOUT) | |
91 | 91 | |||
92 | #define DEVINFOSIZE 1024 | 92 | #define DEVINFOSIZE 1024 | |
93 | 93 | |||
94 | usbd_status usbd_open_pipe_intr(struct usbd_interface *, uint8_t, uint8_t, | 94 | usbd_status usbd_open_pipe_intr(struct usbd_interface *, uint8_t, uint8_t, | |
95 | struct usbd_pipe **, void *, void *, uint32_t, usbd_callback, int); | 95 | struct usbd_pipe **, void *, void *, uint32_t, usbd_callback, int); | |
96 | usbd_status usbd_open_pipe(struct usbd_interface *, uint8_t, uint8_t, | 96 | usbd_status usbd_open_pipe(struct usbd_interface *, uint8_t, uint8_t, | |
97 | struct usbd_pipe **); | 97 | struct usbd_pipe **); | |
98 | usbd_status usbd_close_pipe(struct usbd_pipe *); | 98 | usbd_status usbd_close_pipe(struct usbd_pipe *); | |
99 | 99 | |||
100 | usbd_status usbd_transfer(struct usbd_xfer *); | 100 | usbd_status usbd_transfer(struct usbd_xfer *); | |
101 | 101 | |||
102 | void *usbd_get_buffer(struct usbd_xfer *); | 102 | void *usbd_get_buffer(struct usbd_xfer *); | |
103 | struct usbd_pipe *usbd_get_pipe0(struct usbd_device *); | 103 | struct usbd_pipe *usbd_get_pipe0(struct usbd_device *); | |
104 | 104 | |||
105 | int usbd_create_xfer(struct usbd_pipe *, size_t, unsigned int, unsigned int, | 105 | int usbd_create_xfer(struct usbd_pipe *, size_t, unsigned int, unsigned int, | |
106 | struct usbd_xfer **); | 106 | struct usbd_xfer **); | |
107 | void usbd_destroy_xfer(struct usbd_xfer *); | 107 | void usbd_destroy_xfer(struct usbd_xfer *); | |
108 | 108 | |||
109 | void usbd_setup_xfer(struct usbd_xfer *, void *, void *, | 109 | void usbd_setup_xfer(struct usbd_xfer *, void *, void *, | |
110 | uint32_t, uint16_t, uint32_t, usbd_callback); | 110 | uint32_t, uint16_t, uint32_t, usbd_callback); | |
111 | 111 | |||
112 | void usbd_setup_default_xfer(struct usbd_xfer *, struct usbd_device *, | 112 | void usbd_setup_default_xfer(struct usbd_xfer *, struct usbd_device *, | |
113 | void *, uint32_t, usb_device_request_t *, void *, | 113 | void *, uint32_t, usb_device_request_t *, void *, | |
114 | uint32_t, uint16_t, usbd_callback); | 114 | uint32_t, uint16_t, usbd_callback); | |
115 | 115 | |||
116 | void usbd_setup_isoc_xfer(struct usbd_xfer *, void *, uint16_t *, | 116 | void usbd_setup_isoc_xfer(struct usbd_xfer *, void *, uint16_t *, | |
117 | uint32_t, uint16_t, usbd_callback); | 117 | uint32_t, uint16_t, usbd_callback); | |
118 | 118 | |||
119 | void usbd_get_xfer_status(struct usbd_xfer *, void **, | 119 | void usbd_get_xfer_status(struct usbd_xfer *, void **, | |
120 | void **, uint32_t *, usbd_status *); | 120 | void **, uint32_t *, usbd_status *); | |
121 | 121 | |||
122 | usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor | 122 | usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor | |
123 | (struct usbd_interface *, uint8_t); | 123 | (struct usbd_interface *, uint8_t); | |
124 | 124 | |||
125 | usbd_status usbd_abort_pipe(struct usbd_pipe *); | 125 | void usbd_abort_pipe(struct usbd_pipe *); | |
126 | usbd_status usbd_abort_default_pipe(struct usbd_device *); | 126 | void usbd_abort_default_pipe(struct usbd_device *); | |
127 | 127 | |||
128 | usbd_status usbd_clear_endpoint_stall(struct usbd_pipe *); | 128 | usbd_status usbd_clear_endpoint_stall(struct usbd_pipe *); | |
129 | void usbd_clear_endpoint_stall_async(struct usbd_pipe *); | 129 | void usbd_clear_endpoint_stall_async(struct usbd_pipe *); | |
130 | 130 | |||
131 | void usbd_clear_endpoint_toggle(struct usbd_pipe *); | 131 | void usbd_clear_endpoint_toggle(struct usbd_pipe *); | |
132 | usbd_status usbd_endpoint_count(struct usbd_interface *, uint8_t *); | 132 | usbd_status usbd_endpoint_count(struct usbd_interface *, uint8_t *); | |
133 | 133 | |||
134 | usbd_status usbd_interface_count(struct usbd_device *, uint8_t *); | 134 | usbd_status usbd_interface_count(struct usbd_device *, uint8_t *); | |
135 | 135 | |||
136 | void usbd_interface2device_handle(struct usbd_interface *, struct usbd_device **); | 136 | void usbd_interface2device_handle(struct usbd_interface *, struct usbd_device **); | |
137 | usbd_status usbd_device2interface_handle(struct usbd_device *, | 137 | usbd_status usbd_device2interface_handle(struct usbd_device *, | |
138 | uint8_t, struct usbd_interface **); | 138 | uint8_t, struct usbd_interface **); | |
139 | 139 | |||
140 | struct usbd_device *usbd_pipe2device_handle(struct usbd_pipe *); | 140 | struct usbd_device *usbd_pipe2device_handle(struct usbd_pipe *); | |
141 | 141 | |||
142 | usbd_status usbd_sync_transfer(struct usbd_xfer *); | 142 | usbd_status usbd_sync_transfer(struct usbd_xfer *); | |
143 | usbd_status usbd_sync_transfer_sig(struct usbd_xfer *); | 143 | usbd_status usbd_sync_transfer_sig(struct usbd_xfer *); | |
144 | 144 | |||
145 | usbd_status usbd_do_request(struct usbd_device *, usb_device_request_t *, void *); | 145 | usbd_status usbd_do_request(struct usbd_device *, usb_device_request_t *, void *); | |
146 | usbd_status usbd_request_async(struct usbd_device *, struct usbd_xfer *, | 146 | usbd_status usbd_request_async(struct usbd_device *, struct usbd_xfer *, | |
147 | usb_device_request_t *, void *, usbd_callback); | 147 | usb_device_request_t *, void *, usbd_callback); | |
148 | usbd_status usbd_do_request_flags(struct usbd_device *, usb_device_request_t *, | 148 | usbd_status usbd_do_request_flags(struct usbd_device *, usb_device_request_t *, | |
149 | void *, uint16_t, int *, uint32_t); | 149 | void *, uint16_t, int *, uint32_t); | |
150 | usbd_status usbd_do_request_len(struct usbd_device *dev, | 150 | usbd_status usbd_do_request_len(struct usbd_device *dev, | |
151 | usb_device_request_t *req, size_t len, void *data, uint16_t flags, | 151 | usb_device_request_t *req, size_t len, void *data, uint16_t flags, | |
152 | int *actlen, uint32_t timeout); | 152 | int *actlen, uint32_t timeout); | |
153 | 153 | |||
154 | usb_interface_descriptor_t * | 154 | usb_interface_descriptor_t * | |
155 | usbd_get_interface_descriptor(struct usbd_interface *); | 155 | usbd_get_interface_descriptor(struct usbd_interface *); | |
156 | usb_endpoint_descriptor_t * | 156 | usb_endpoint_descriptor_t * | |
157 | usbd_get_endpoint_descriptor(struct usbd_interface *, uint8_t); | 157 | usbd_get_endpoint_descriptor(struct usbd_interface *, uint8_t); | |
158 | 158 | |||
159 | usb_config_descriptor_t *usbd_get_config_descriptor(struct usbd_device *); | 159 | usb_config_descriptor_t *usbd_get_config_descriptor(struct usbd_device *); | |
160 | usb_device_descriptor_t *usbd_get_device_descriptor(struct usbd_device *); | 160 | usb_device_descriptor_t *usbd_get_device_descriptor(struct usbd_device *); | |
161 | 161 | |||
162 | usbd_status usbd_set_interface(struct usbd_interface *, int); | 162 | usbd_status usbd_set_interface(struct usbd_interface *, int); | |
163 | usbd_status usbd_get_interface(struct usbd_interface *, uint8_t *); | 163 | usbd_status usbd_get_interface(struct usbd_interface *, uint8_t *); | |
164 | 164 | |||
165 | int usbd_get_no_alts(usb_config_descriptor_t *, int); | 165 | int usbd_get_no_alts(usb_config_descriptor_t *, int); | |
166 | 166 | |||
167 | void usbd_fill_deviceinfo(struct usbd_device *, struct usb_device_info *, int); | 167 | void usbd_fill_deviceinfo(struct usbd_device *, struct usb_device_info *, int); | |
168 | int usbd_get_interface_altindex(struct usbd_interface *); | 168 | int usbd_get_interface_altindex(struct usbd_interface *); | |
169 | 169 | |||
170 | usb_interface_descriptor_t *usbd_find_idesc(usb_config_descriptor_t *, | 170 | usb_interface_descriptor_t *usbd_find_idesc(usb_config_descriptor_t *, | |
171 | int, int); | 171 | int, int); | |
172 | usb_endpoint_descriptor_t *usbd_find_edesc(usb_config_descriptor_t *, | 172 | usb_endpoint_descriptor_t *usbd_find_edesc(usb_config_descriptor_t *, | |
173 | int, int, int); | 173 | int, int, int); | |
174 | 174 | |||
175 | void usbd_dopoll(struct usbd_interface *); | 175 | void usbd_dopoll(struct usbd_interface *); | |
176 | void usbd_set_polling(struct usbd_device *, int); | 176 | void usbd_set_polling(struct usbd_device *, int); | |
177 | 177 | |||
178 | const char *usbd_errstr(usbd_status); | 178 | const char *usbd_errstr(usbd_status); | |
179 | 179 | |||
180 | void usbd_add_dev_event(int, struct usbd_device *); | 180 | void usbd_add_dev_event(int, struct usbd_device *); | |
181 | void usbd_add_drv_event(int, struct usbd_device *, device_t); | 181 | void usbd_add_drv_event(int, struct usbd_device *, device_t); | |
182 | 182 | |||
183 | char *usbd_devinfo_alloc(struct usbd_device *, int); | 183 | char *usbd_devinfo_alloc(struct usbd_device *, int); | |
184 | void usbd_devinfo_free(char *); | 184 | void usbd_devinfo_free(char *); | |
185 | 185 | |||
186 | const struct usbd_quirks *usbd_get_quirks(struct usbd_device *); | 186 | const struct usbd_quirks *usbd_get_quirks(struct usbd_device *); | |
187 | 187 | |||
188 | usbd_status usbd_reload_device_desc(struct usbd_device *); | 188 | usbd_status usbd_reload_device_desc(struct usbd_device *); | |
189 | 189 | |||
190 | int usbd_ratecheck(struct timeval *); | 190 | int usbd_ratecheck(struct timeval *); | |
191 | 191 | |||
192 | usbd_status usbd_get_string(struct usbd_device *, int, char *); | 192 | usbd_status usbd_get_string(struct usbd_device *, int, char *); | |
193 | usbd_status usbd_get_string0(struct usbd_device *, int, char *, int); | 193 | usbd_status usbd_get_string0(struct usbd_device *, int, char *, int); | |
194 | 194 | |||
195 | /* For use by HCI drivers, not USB device drivers */ | 195 | /* For use by HCI drivers, not USB device drivers */ | |
196 | void usbd_xfer_schedule_timeout(struct usbd_xfer *); | 196 | void usbd_xfer_schedule_timeout(struct usbd_xfer *); | |
197 | bool usbd_xfer_trycomplete(struct usbd_xfer *); | 197 | bool usbd_xfer_trycomplete(struct usbd_xfer *); | |
198 | void usbd_xfer_abort(struct usbd_xfer *); | 198 | void usbd_xfer_abort(struct usbd_xfer *); | |
199 | 199 | |||
200 | /* Used to clear endpoint stalls from the softint */ | 200 | /* Used to clear endpoint stalls from the softint */ | |
201 | void usbd_clear_endpoint_stall_task(void *); | 201 | void usbd_clear_endpoint_stall_task(void *); | |
202 | 202 | |||
203 | /* | 203 | /* | |
204 | * The usb_task structs form a queue of things to run in the USB event | 204 | * The usb_task structs form a queue of things to run in the USB event | |
205 | * thread. Normally this is just device discovery when a connect/disconnect | 205 | * thread. Normally this is just device discovery when a connect/disconnect | |
206 | * has been detected. But it may also be used by drivers that need to | 206 | * has been detected. But it may also be used by drivers that need to | |
207 | * perform (short) tasks that must have a process context. | 207 | * perform (short) tasks that must have a process context. | |
208 | */ | 208 | */ | |
209 | struct usb_task { | 209 | struct usb_task { | |
210 | TAILQ_ENTRY(usb_task) next; | 210 | TAILQ_ENTRY(usb_task) next; | |
211 | void (*fun)(void *); | 211 | void (*fun)(void *); | |
212 | void *arg; | 212 | void *arg; | |
213 | volatile unsigned queue; | 213 | volatile unsigned queue; | |
214 | int flags; | 214 | int flags; | |
215 | }; | 215 | }; | |
216 | #define USB_TASKQ_HC 0 | 216 | #define USB_TASKQ_HC 0 | |
217 | #define USB_TASKQ_DRIVER 1 | 217 | #define USB_TASKQ_DRIVER 1 | |
218 | #define USB_NUM_TASKQS 2 | 218 | #define USB_NUM_TASKQS 2 | |
219 | #define USB_TASKQ_NAMES {"usbtask-hc", "usbtask-dr"} | 219 | #define USB_TASKQ_NAMES {"usbtask-hc", "usbtask-dr"} | |
220 | #define USB_TASKQ_MPSAFE 0x80 | 220 | #define USB_TASKQ_MPSAFE 0x80 | |
221 | 221 | |||
222 | void usb_add_task(struct usbd_device *, struct usb_task *, int); | 222 | void usb_add_task(struct usbd_device *, struct usb_task *, int); | |
223 | bool usb_rem_task(struct usbd_device *, struct usb_task *); | 223 | bool usb_rem_task(struct usbd_device *, struct usb_task *); | |
224 | bool usb_rem_task_wait(struct usbd_device *, struct usb_task *, int, | 224 | bool usb_rem_task_wait(struct usbd_device *, struct usb_task *, int, | |
225 | kmutex_t *); | 225 | kmutex_t *); | |
226 | bool usb_task_pending(struct usbd_device *, struct usb_task *); | 226 | bool usb_task_pending(struct usbd_device *, struct usb_task *); | |
227 | #define usb_init_task(t, f, a, fl) ((t)->fun = (f), (t)->arg = (a), (t)->queue = USB_NUM_TASKQS, (t)->flags = (fl)) | 227 | #define usb_init_task(t, f, a, fl) ((t)->fun = (f), (t)->arg = (a), (t)->queue = USB_NUM_TASKQS, (t)->flags = (fl)) | |
228 | 228 | |||
229 | bool usb_in_event_thread(device_t); | 229 | bool usb_in_event_thread(device_t); | |
230 | 230 | |||
231 | struct usb_devno { | 231 | struct usb_devno { | |
232 | uint16_t ud_vendor; | 232 | uint16_t ud_vendor; | |
233 | uint16_t ud_product; | 233 | uint16_t ud_product; | |
234 | }; | 234 | }; | |
235 | const struct usb_devno *usb_match_device(const struct usb_devno *, | 235 | const struct usb_devno *usb_match_device(const struct usb_devno *, | |
236 | u_int, u_int, uint16_t, uint16_t); | 236 | u_int, u_int, uint16_t, uint16_t); | |
237 | #define usb_lookup(tbl, vendor, product) \ | 237 | #define usb_lookup(tbl, vendor, product) \ | |
238 | usb_match_device((const struct usb_devno *)(tbl), sizeof(tbl) / sizeof((tbl)[0]), sizeof((tbl)[0]), (vendor), (product)) | 238 | usb_match_device((const struct usb_devno *)(tbl), sizeof(tbl) / sizeof((tbl)[0]), sizeof((tbl)[0]), (vendor), (product)) | |
239 | #define USB_PRODUCT_ANY 0xffff | 239 | #define USB_PRODUCT_ANY 0xffff | |
240 | 240 | |||
241 | /* compat callbacks */ | 241 | /* compat callbacks */ | |
242 | void usbd_devinfo_vp(struct usbd_device *, char *, size_t, char *, size_t, | 242 | void usbd_devinfo_vp(struct usbd_device *, char *, size_t, char *, size_t, | |
243 | int, int); | 243 | int, int); | |
244 | int usbd_printBCD(char *, size_t, int); | 244 | int usbd_printBCD(char *, size_t, int); | |
245 | 245 | |||
246 | 246 | |||
247 | /* NetBSD attachment information */ | 247 | /* NetBSD attachment information */ | |
248 | 248 | |||
249 | /* Attach data */ | 249 | /* Attach data */ | |
250 | struct usb_attach_arg { | 250 | struct usb_attach_arg { | |
251 | int uaa_port; | 251 | int uaa_port; | |
252 | int uaa_vendor; | 252 | int uaa_vendor; | |
253 | int uaa_product; | 253 | int uaa_product; | |
254 | int uaa_release; | 254 | int uaa_release; | |
255 | struct usbd_device * uaa_device; /* current device */ | 255 | struct usbd_device * uaa_device; /* current device */ | |
256 | int uaa_class; | 256 | int uaa_class; | |
257 | int uaa_subclass; | 257 | int uaa_subclass; | |
258 | int uaa_proto; | 258 | int uaa_proto; | |
259 | int uaa_usegeneric; | 259 | int uaa_usegeneric; | |
260 | }; | 260 | }; | |
261 | 261 | |||
262 | struct usbif_attach_arg { | 262 | struct usbif_attach_arg { | |
263 | int uiaa_port; | 263 | int uiaa_port; | |
264 | int uiaa_configno; | 264 | int uiaa_configno; | |
265 | int uiaa_ifaceno; | 265 | int uiaa_ifaceno; | |
266 | int uiaa_vendor; | 266 | int uiaa_vendor; | |
267 | int uiaa_product; | 267 | int uiaa_product; | |
268 | int uiaa_release; | 268 | int uiaa_release; | |
269 | struct usbd_device * uiaa_device; /* current device */ | 269 | struct usbd_device * uiaa_device; /* current device */ | |
270 | 270 | |||
271 | struct usbd_interface * uiaa_iface; /* current interface */ | 271 | struct usbd_interface * uiaa_iface; /* current interface */ | |
272 | int uiaa_class; | 272 | int uiaa_class; | |
273 | int uiaa_subclass; | 273 | int uiaa_subclass; | |
274 | int uiaa_proto; | 274 | int uiaa_proto; | |
275 | 275 | |||
276 | /* XXX need accounting for interfaces not matched to */ | 276 | /* XXX need accounting for interfaces not matched to */ | |
277 | 277 | |||
278 | struct usbd_interface **uiaa_ifaces; /* all interfaces */ | 278 | struct usbd_interface **uiaa_ifaces; /* all interfaces */ | |
279 | int uiaa_nifaces; /* number of interfaces */ | 279 | int uiaa_nifaces; /* number of interfaces */ | |
280 | }; | 280 | }; | |
281 | 281 | |||
282 | /* Match codes. */ | 282 | /* Match codes. */ | |
283 | #define UMATCH_HIGHEST 15 | 283 | #define UMATCH_HIGHEST 15 | |
284 | /* First five codes is for a whole device. */ | 284 | /* First five codes is for a whole device. */ | |
285 | #define UMATCH_VENDOR_PRODUCT_REV 14 | 285 | #define UMATCH_VENDOR_PRODUCT_REV 14 | |
286 | #define UMATCH_VENDOR_PRODUCT 13 | 286 | #define UMATCH_VENDOR_PRODUCT 13 | |
287 | #define UMATCH_VENDOR_DEVCLASS_DEVPROTO 12 | 287 | #define UMATCH_VENDOR_DEVCLASS_DEVPROTO 12 | |
288 | #define UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO 11 | 288 | #define UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO 11 | |
289 | #define UMATCH_DEVCLASS_DEVSUBCLASS 10 | 289 | #define UMATCH_DEVCLASS_DEVSUBCLASS 10 | |
290 | /* Next six codes are for interfaces. */ | 290 | /* Next six codes are for interfaces. */ | |
291 | #define UMATCH_VENDOR_PRODUCT_REV_CONF_IFACE 9 | 291 | #define UMATCH_VENDOR_PRODUCT_REV_CONF_IFACE 9 | |
292 | #define UMATCH_VENDOR_PRODUCT_CONF_IFACE 8 | 292 | #define UMATCH_VENDOR_PRODUCT_CONF_IFACE 8 | |
293 | #define UMATCH_VENDOR_IFACESUBCLASS_IFACEPROTO 7 | 293 | #define UMATCH_VENDOR_IFACESUBCLASS_IFACEPROTO 7 | |
294 | #define UMATCH_VENDOR_IFACESUBCLASS 6 | 294 | #define UMATCH_VENDOR_IFACESUBCLASS 6 | |
295 | #define UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO 5 | 295 | #define UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO 5 | |
296 | #define UMATCH_IFACECLASS_IFACESUBCLASS 4 | 296 | #define UMATCH_IFACECLASS_IFACESUBCLASS 4 | |
297 | #define UMATCH_IFACECLASS 3 | 297 | #define UMATCH_IFACECLASS 3 | |
298 | #define UMATCH_IFACECLASS_GENERIC 2 | 298 | #define UMATCH_IFACECLASS_GENERIC 2 | |
299 | /* Generic driver */ | 299 | /* Generic driver */ | |
300 | #define UMATCH_GENERIC 1 | 300 | #define UMATCH_GENERIC 1 | |
301 | /* No match */ | 301 | /* No match */ | |
302 | #define UMATCH_NONE 0 | 302 | #define UMATCH_NONE 0 | |
303 | 303 | |||
304 | 304 | |||
305 | /* | 305 | /* | |
306 | * IPL_USB is defined as IPL_VM for drivers that have not been made MP safe. | 306 | * IPL_USB is defined as IPL_VM for drivers that have not been made MP safe. | |
307 | * IPL_VM (currently) takes the kernel lock. | 307 | * IPL_VM (currently) takes the kernel lock. | |
308 | * | 308 | * | |
309 | * Eventually, IPL_USB can/should be changed | 309 | * Eventually, IPL_USB can/should be changed | |
310 | */ | 310 | */ | |
311 | #define IPL_USB IPL_VM | 311 | #define IPL_USB IPL_VM | |
312 | #define splhardusb splvm | 312 | #define splhardusb splvm | |
313 | 313 | |||
314 | #define SOFTINT_USB SOFTINT_SERIAL | 314 | #define SOFTINT_USB SOFTINT_SERIAL | |
315 | #define IPL_SOFTUSB IPL_SOFTSERIAL | 315 | #define IPL_SOFTUSB IPL_SOFTSERIAL | |
316 | #define splusb splsoftserial | 316 | #define splusb splsoftserial | |
317 | 317 | |||
318 | #endif /* _USBDI_H_ */ | 318 | #endif /* _USBDI_H_ */ |
--- src/sys/dev/usb/usbnet.c 2022/03/03 05:56:44 1.91
+++ src/sys/dev/usb/usbnet.c 2022/03/03 06:05:38 1.92
@@ -1,1646 +1,1637 @@ | @@ -1,1646 +1,1637 @@ | |||
1 | /* $NetBSD: usbnet.c,v 1.91 2022/03/03 05:56:44 riastradh Exp $ */ | 1 | /* $NetBSD: usbnet.c,v 1.92 2022/03/03 06:05:38 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2019 Matthew R. Green | 4 | * Copyright (c) 2019 Matthew R. Green | |
5 | * All rights reserved. | 5 | * 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 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | /* | 29 | /* | |
30 | * Common code shared between USB network drivers. | 30 | * Common code shared between USB network drivers. | |
31 | */ | 31 | */ | |
32 | 32 | |||
33 | #include <sys/cdefs.h> | 33 | #include <sys/cdefs.h> | |
34 | __KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.91 2022/03/03 05:56:44 riastradh Exp $"); | 34 | __KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.92 2022/03/03 06:05:38 riastradh Exp $"); | |
35 | 35 | |||
36 | #include <sys/param.h> | 36 | #include <sys/param.h> | |
37 | #include <sys/kernel.h> | 37 | #include <sys/kernel.h> | |
38 | #include <sys/kmem.h> | 38 | #include <sys/kmem.h> | |
39 | #include <sys/module.h> | 39 | #include <sys/module.h> | |
40 | #include <sys/atomic.h> | 40 | #include <sys/atomic.h> | |
41 | 41 | |||
42 | #include <dev/usb/usbnet.h> | 42 | #include <dev/usb/usbnet.h> | |
43 | #include <dev/usb/usbhist.h> | 43 | #include <dev/usb/usbhist.h> | |
44 | 44 | |||
45 | struct usbnet_cdata { | 45 | struct usbnet_cdata { | |
46 | struct usbnet_chain *uncd_tx_chain; | 46 | struct usbnet_chain *uncd_tx_chain; | |
47 | struct usbnet_chain *uncd_rx_chain; | 47 | struct usbnet_chain *uncd_rx_chain; | |
48 | 48 | |||
49 | int uncd_tx_prod; | 49 | int uncd_tx_prod; | |
50 | int uncd_tx_cnt; | 50 | int uncd_tx_cnt; | |
51 | }; | 51 | }; | |
52 | 52 | |||
53 | struct usbnet_private { | 53 | struct usbnet_private { | |
54 | /* | 54 | /* | |
55 | * - unp_core_lock protects most of this structure, the public one, | 55 | * - unp_core_lock protects most of this structure, the public one, | |
56 | * and the MII / media data. | 56 | * and the MII / media data. | |
57 | * - unp_rxlock protects the rx path and its data | 57 | * - unp_rxlock protects the rx path and its data | |
58 | * - unp_txlock protects the tx path and its data | 58 | * - unp_txlock protects the tx path and its data | |
59 | * | 59 | * | |
60 | * the lock ordering is: | 60 | * the lock ordering is: | |
61 | * ifnet lock -> unp_core_lock -> unp_rxlock -> unp_txlock | 61 | * ifnet lock -> unp_core_lock -> unp_rxlock -> unp_txlock | |
62 | * -> unp_mcastlock | 62 | * -> unp_mcastlock | |
63 | * - ifnet lock is not needed for unp_core_lock, but if ifnet lock is | 63 | * - ifnet lock is not needed for unp_core_lock, but if ifnet lock is | |
64 | * involved, it must be taken first | 64 | * involved, it must be taken first | |
65 | */ | 65 | */ | |
66 | kmutex_t unp_core_lock; | 66 | kmutex_t unp_core_lock; | |
67 | kmutex_t unp_rxlock; | 67 | kmutex_t unp_rxlock; | |
68 | kmutex_t unp_txlock; | 68 | kmutex_t unp_txlock; | |
69 | 69 | |||
70 | kmutex_t unp_mcastlock; | 70 | kmutex_t unp_mcastlock; | |
71 | bool unp_mcastactive; | 71 | bool unp_mcastactive; | |
72 | 72 | |||
73 | struct usbnet_cdata unp_cdata; | 73 | struct usbnet_cdata unp_cdata; | |
74 | 74 | |||
75 | struct ethercom unp_ec; | 75 | struct ethercom unp_ec; | |
76 | struct mii_data unp_mii; | 76 | struct mii_data unp_mii; | |
77 | struct usb_task unp_ticktask; | 77 | struct usb_task unp_ticktask; | |
78 | struct callout unp_stat_ch; | 78 | struct callout unp_stat_ch; | |
79 | struct usbd_pipe *unp_ep[USBNET_ENDPT_MAX]; | 79 | struct usbd_pipe *unp_ep[USBNET_ENDPT_MAX]; | |
80 | 80 | |||
81 | volatile bool unp_dying; | 81 | volatile bool unp_dying; | |
82 | bool unp_stopping; | 82 | bool unp_stopping; | |
83 | bool unp_attached; | 83 | bool unp_attached; | |
84 | bool unp_ifp_attached; | 84 | bool unp_ifp_attached; | |
85 | bool unp_link; | 85 | bool unp_link; | |
86 | 86 | |||
87 | int unp_timer; | 87 | int unp_timer; | |
88 | unsigned short unp_if_flags; | 88 | unsigned short unp_if_flags; | |
89 | unsigned unp_number; | 89 | unsigned unp_number; | |
90 | 90 | |||
91 | krndsource_t unp_rndsrc; | 91 | krndsource_t unp_rndsrc; | |
92 | 92 | |||
93 | struct timeval unp_rx_notice; | 93 | struct timeval unp_rx_notice; | |
94 | struct timeval unp_tx_notice; | 94 | struct timeval unp_tx_notice; | |
95 | struct timeval unp_intr_notice; | 95 | struct timeval unp_intr_notice; | |
96 | }; | 96 | }; | |
97 | 97 | |||
98 | #define un_cdata(un) (&(un)->un_pri->unp_cdata) | 98 | #define un_cdata(un) (&(un)->un_pri->unp_cdata) | |
99 | 99 | |||
100 | volatile unsigned usbnet_number; | 100 | volatile unsigned usbnet_number; | |
101 | 101 | |||
102 | static void usbnet_isowned_rx(struct usbnet *); | 102 | static void usbnet_isowned_rx(struct usbnet *); | |
103 | static void usbnet_isowned_tx(struct usbnet *); | 103 | static void usbnet_isowned_tx(struct usbnet *); | |
104 | 104 | |||
105 | static kmutex_t * | 105 | static kmutex_t * | |
106 | usbnet_mutex_core(struct usbnet *un) | 106 | usbnet_mutex_core(struct usbnet *un) | |
107 | { | 107 | { | |
108 | return &un->un_pri->unp_core_lock; | 108 | return &un->un_pri->unp_core_lock; | |
109 | } | 109 | } | |
110 | 110 | |||
111 | static __inline__ void | 111 | static __inline__ void | |
112 | usbnet_isowned_core(struct usbnet *un) | 112 | usbnet_isowned_core(struct usbnet *un) | |
113 | { | 113 | { | |
114 | KASSERT(mutex_owned(usbnet_mutex_core(un))); | 114 | KASSERT(mutex_owned(usbnet_mutex_core(un))); | |
115 | } | 115 | } | |
116 | 116 | |||
117 | static int usbnet_modcmd(modcmd_t, void *); | 117 | static int usbnet_modcmd(modcmd_t, void *); | |
118 | 118 | |||
119 | #ifdef USB_DEBUG | 119 | #ifdef USB_DEBUG | |
120 | #ifndef USBNET_DEBUG | 120 | #ifndef USBNET_DEBUG | |
121 | #define usbnetdebug 0 | 121 | #define usbnetdebug 0 | |
122 | #else | 122 | #else | |
123 | static int usbnetdebug = 0; | 123 | static int usbnetdebug = 0; | |
124 | 124 | |||
125 | SYSCTL_SETUP(sysctl_hw_usbnet_setup, "sysctl hw.usbnet setup") | 125 | SYSCTL_SETUP(sysctl_hw_usbnet_setup, "sysctl hw.usbnet setup") | |
126 | { | 126 | { | |
127 | int err; | 127 | int err; | |
128 | const struct sysctlnode *rnode; | 128 | const struct sysctlnode *rnode; | |
129 | const struct sysctlnode *cnode; | 129 | const struct sysctlnode *cnode; | |
130 | 130 | |||
131 | err = sysctl_createv(clog, 0, NULL, &rnode, | 131 | err = sysctl_createv(clog, 0, NULL, &rnode, | |
132 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "usbnet", | 132 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "usbnet", | |
133 | SYSCTL_DESCR("usbnet global controls"), | 133 | SYSCTL_DESCR("usbnet global controls"), | |
134 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | 134 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | |
135 | 135 | |||
136 | if (err) | 136 | if (err) | |
137 | goto fail; | 137 | goto fail; | |
138 | 138 | |||
139 | /* control debugging printfs */ | 139 | /* control debugging printfs */ | |
140 | err = sysctl_createv(clog, 0, &rnode, &cnode, | 140 | err = sysctl_createv(clog, 0, &rnode, &cnode, | |
141 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | 141 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | |
142 | "debug", SYSCTL_DESCR("Enable debugging output"), | 142 | "debug", SYSCTL_DESCR("Enable debugging output"), | |
143 | NULL, 0, &usbnetdebug, sizeof(usbnetdebug), CTL_CREATE, CTL_EOL); | 143 | NULL, 0, &usbnetdebug, sizeof(usbnetdebug), CTL_CREATE, CTL_EOL); | |
144 | if (err) | 144 | if (err) | |
145 | goto fail; | 145 | goto fail; | |
146 | 146 | |||
147 | return; | 147 | return; | |
148 | fail: | 148 | fail: | |
149 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | 149 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | |
150 | } | 150 | } | |
151 | 151 | |||
152 | #endif /* USBNET_DEBUG */ | 152 | #endif /* USBNET_DEBUG */ | |
153 | #endif /* USB_DEBUG */ | 153 | #endif /* USB_DEBUG */ | |
154 | 154 | |||
155 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(usbnetdebug,1,FMT,A,B,C,D) | 155 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(usbnetdebug,1,FMT,A,B,C,D) | |
156 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(usbnetdebug,N,FMT,A,B,C,D) | 156 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(usbnetdebug,N,FMT,A,B,C,D) | |
157 | #define USBNETHIST_FUNC() USBHIST_FUNC() | 157 | #define USBNETHIST_FUNC() USBHIST_FUNC() | |
158 | #define USBNETHIST_CALLED(name) USBHIST_CALLED(usbnetdebug) | 158 | #define USBNETHIST_CALLED(name) USBHIST_CALLED(usbnetdebug) | |
159 | #define USBNETHIST_CALLARGS(FMT,A,B,C,D) \ | 159 | #define USBNETHIST_CALLARGS(FMT,A,B,C,D) \ | |
160 | USBHIST_CALLARGS(usbnetdebug,FMT,A,B,C,D) | 160 | USBHIST_CALLARGS(usbnetdebug,FMT,A,B,C,D) | |
161 | #define USBNETHIST_CALLARGSN(N,FMT,A,B,C,D) \ | 161 | #define USBNETHIST_CALLARGSN(N,FMT,A,B,C,D) \ | |
162 | USBHIST_CALLARGSN(usbnetdebug,N,FMT,A,B,C,D) | 162 | USBHIST_CALLARGSN(usbnetdebug,N,FMT,A,B,C,D) | |
163 | 163 | |||
164 | /* Callback vectors. */ | 164 | /* Callback vectors. */ | |
165 | 165 | |||
166 | static void | 166 | static void | |
167 | uno_stop(struct usbnet *un, struct ifnet *ifp, int disable) | 167 | uno_stop(struct usbnet *un, struct ifnet *ifp, int disable) | |
168 | { | 168 | { | |
169 | KASSERTMSG(!un->un_pri->unp_ifp_attached || IFNET_LOCKED(ifp), | 169 | KASSERTMSG(!un->un_pri->unp_ifp_attached || IFNET_LOCKED(ifp), | |
170 | "%s", ifp->if_xname); | 170 | "%s", ifp->if_xname); | |
171 | usbnet_isowned_core(un); | 171 | usbnet_isowned_core(un); | |
172 | if (un->un_ops->uno_stop) | 172 | if (un->un_ops->uno_stop) | |
173 | (*un->un_ops->uno_stop)(ifp, disable); | 173 | (*un->un_ops->uno_stop)(ifp, disable); | |
174 | } | 174 | } | |
175 | 175 | |||
176 | static int | 176 | static int | |
177 | uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) | 177 | uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) | |
178 | { | 178 | { | |
179 | 179 | |||
180 | KASSERTMSG(cmd != SIOCADDMULTI, "%s", ifp->if_xname); | 180 | KASSERTMSG(cmd != SIOCADDMULTI, "%s", ifp->if_xname); | |
181 | KASSERTMSG(cmd != SIOCDELMULTI, "%s", ifp->if_xname); | 181 | KASSERTMSG(cmd != SIOCDELMULTI, "%s", ifp->if_xname); | |
182 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | 182 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | |
183 | 183 | |||
184 | if (un->un_ops->uno_ioctl) | 184 | if (un->un_ops->uno_ioctl) | |
185 | return (*un->un_ops->uno_ioctl)(ifp, cmd, data); | 185 | return (*un->un_ops->uno_ioctl)(ifp, cmd, data); | |
186 | return 0; | 186 | return 0; | |
187 | } | 187 | } | |
188 | 188 | |||
189 | static int | 189 | static int | |
190 | uno_override_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) | 190 | uno_override_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) | |
191 | { | 191 | { | |
192 | 192 | |||
193 | switch (cmd) { | 193 | switch (cmd) { | |
194 | case SIOCADDMULTI: | 194 | case SIOCADDMULTI: | |
195 | case SIOCDELMULTI: | 195 | case SIOCDELMULTI: | |
196 | break; | 196 | break; | |
197 | default: | 197 | default: | |
198 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | 198 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | |
199 | } | 199 | } | |
200 | 200 | |||
201 | return (*un->un_ops->uno_override_ioctl)(ifp, cmd, data); | 201 | return (*un->un_ops->uno_override_ioctl)(ifp, cmd, data); | |
202 | } | 202 | } | |
203 | 203 | |||
204 | static int | 204 | static int | |
205 | uno_init(struct usbnet *un, struct ifnet *ifp) | 205 | uno_init(struct usbnet *un, struct ifnet *ifp) | |
206 | { | 206 | { | |
207 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | 207 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | |
208 | return un->un_ops->uno_init ? (*un->un_ops->uno_init)(ifp) : 0; | 208 | return un->un_ops->uno_init ? (*un->un_ops->uno_init)(ifp) : 0; | |
209 | } | 209 | } | |
210 | 210 | |||
211 | static int | 211 | static int | |
212 | uno_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 212 | uno_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
213 | { | 213 | { | |
214 | usbnet_isowned_core(un); | 214 | usbnet_isowned_core(un); | |
215 | return (*un->un_ops->uno_read_reg)(un, phy, reg, val); | 215 | return (*un->un_ops->uno_read_reg)(un, phy, reg, val); | |
216 | } | 216 | } | |
217 | 217 | |||
218 | static int | 218 | static int | |
219 | uno_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 219 | uno_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
220 | { | 220 | { | |
221 | usbnet_isowned_core(un); | 221 | usbnet_isowned_core(un); | |
222 | return (*un->un_ops->uno_write_reg)(un, phy, reg, val); | 222 | return (*un->un_ops->uno_write_reg)(un, phy, reg, val); | |
223 | } | 223 | } | |
224 | 224 | |||
225 | static void | 225 | static void | |
226 | uno_mii_statchg(struct usbnet *un, struct ifnet *ifp) | 226 | uno_mii_statchg(struct usbnet *un, struct ifnet *ifp) | |
227 | { | 227 | { | |
228 | usbnet_isowned_core(un); | 228 | usbnet_isowned_core(un); | |
229 | (*un->un_ops->uno_statchg)(ifp); | 229 | (*un->un_ops->uno_statchg)(ifp); | |
230 | } | 230 | } | |
231 | 231 | |||
232 | static unsigned | 232 | static unsigned | |
233 | uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 233 | uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
234 | { | 234 | { | |
235 | usbnet_isowned_tx(un); | 235 | usbnet_isowned_tx(un); | |
236 | return (*un->un_ops->uno_tx_prepare)(un, m, c); | 236 | return (*un->un_ops->uno_tx_prepare)(un, m, c); | |
237 | } | 237 | } | |
238 | 238 | |||
239 | static void | 239 | static void | |
240 | uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 240 | uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
241 | { | 241 | { | |
242 | usbnet_isowned_rx(un); | 242 | usbnet_isowned_rx(un); | |
243 | (*un->un_ops->uno_rx_loop)(un, c, total_len); | 243 | (*un->un_ops->uno_rx_loop)(un, c, total_len); | |
244 | } | 244 | } | |
245 | 245 | |||
246 | static void | 246 | static void | |
247 | uno_tick(struct usbnet *un) | 247 | uno_tick(struct usbnet *un) | |
248 | { | 248 | { | |
249 | if (un->un_ops->uno_tick) | 249 | if (un->un_ops->uno_tick) | |
250 | (*un->un_ops->uno_tick)(un); | 250 | (*un->un_ops->uno_tick)(un); | |
251 | } | 251 | } | |
252 | 252 | |||
253 | static void | 253 | static void | |
254 | uno_intr(struct usbnet *un, usbd_status status) | 254 | uno_intr(struct usbnet *un, usbd_status status) | |
255 | { | 255 | { | |
256 | if (un->un_ops->uno_intr) | 256 | if (un->un_ops->uno_intr) | |
257 | (*un->un_ops->uno_intr)(un, status); | 257 | (*un->un_ops->uno_intr)(un, status); | |
258 | } | 258 | } | |
259 | 259 | |||
260 | /* Interrupt handling. */ | 260 | /* Interrupt handling. */ | |
261 | 261 | |||
262 | static struct mbuf * | 262 | static struct mbuf * | |
263 | usbnet_newbuf(size_t buflen) | 263 | usbnet_newbuf(size_t buflen) | |
264 | { | 264 | { | |
265 | struct mbuf *m; | 265 | struct mbuf *m; | |
266 | 266 | |||
267 | if (buflen > MCLBYTES) | 267 | if (buflen > MCLBYTES) | |
268 | return NULL; | 268 | return NULL; | |
269 | 269 | |||
270 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 270 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
271 | if (m == NULL) | 271 | if (m == NULL) | |
272 | return NULL; | 272 | return NULL; | |
273 | 273 | |||
274 | if (buflen > MHLEN - ETHER_ALIGN) { | 274 | if (buflen > MHLEN - ETHER_ALIGN) { | |
275 | MCLGET(m, M_DONTWAIT); | 275 | MCLGET(m, M_DONTWAIT); | |
276 | if (!(m->m_flags & M_EXT)) { | 276 | if (!(m->m_flags & M_EXT)) { | |
277 | m_freem(m); | 277 | m_freem(m); | |
278 | return NULL; | 278 | return NULL; | |
279 | } | 279 | } | |
280 | } | 280 | } | |
281 | 281 | |||
282 | m_adj(m, ETHER_ALIGN); | 282 | m_adj(m, ETHER_ALIGN); | |
283 | m->m_len = m->m_pkthdr.len = buflen; | 283 | m->m_len = m->m_pkthdr.len = buflen; | |
284 | 284 | |||
285 | return m; | 285 | return m; | |
286 | } | 286 | } | |
287 | 287 | |||
288 | /* | 288 | /* | |
289 | * usbnet_rxeof() is designed to be the done callback for rx completion. | 289 | * usbnet_rxeof() is designed to be the done callback for rx completion. | |
290 | * it provides generic setup and finalisation, calls a different usbnet | 290 | * it provides generic setup and finalisation, calls a different usbnet | |
291 | * rx_loop callback in the middle, which can use usbnet_enqueue() to | 291 | * rx_loop callback in the middle, which can use usbnet_enqueue() to | |
292 | * enqueue a packet for higher levels (or usbnet_input() if previously | 292 | * enqueue a packet for higher levels (or usbnet_input() if previously | |
293 | * using if_input() path.) | 293 | * using if_input() path.) | |
294 | */ | 294 | */ | |
295 | void | 295 | void | |
296 | usbnet_enqueue(struct usbnet * const un, uint8_t *buf, size_t buflen, | 296 | usbnet_enqueue(struct usbnet * const un, uint8_t *buf, size_t buflen, | |
297 | int csum_flags, uint32_t csum_data, int mbuf_flags) | 297 | int csum_flags, uint32_t csum_data, int mbuf_flags) | |
298 | { | 298 | { | |
299 | USBNETHIST_FUNC(); | 299 | USBNETHIST_FUNC(); | |
300 | struct ifnet * const ifp = usbnet_ifp(un); | 300 | struct ifnet * const ifp = usbnet_ifp(un); | |
301 | struct usbnet_private * const unp __unused = un->un_pri; | 301 | struct usbnet_private * const unp __unused = un->un_pri; | |
302 | struct mbuf *m; | 302 | struct mbuf *m; | |
303 | 303 | |||
304 | USBNETHIST_CALLARGSN(5, "%jd: enter: len=%ju csf %#jx mbf %#jx", | 304 | USBNETHIST_CALLARGSN(5, "%jd: enter: len=%ju csf %#jx mbf %#jx", | |
305 | unp->unp_number, buflen, csum_flags, mbuf_flags); | 305 | unp->unp_number, buflen, csum_flags, mbuf_flags); | |
306 | 306 | |||
307 | usbnet_isowned_rx(un); | 307 | usbnet_isowned_rx(un); | |
308 | 308 | |||
309 | m = usbnet_newbuf(buflen); | 309 | m = usbnet_newbuf(buflen); | |
310 | if (m == NULL) { | 310 | if (m == NULL) { | |
311 | DPRINTF("%jd: no memory", unp->unp_number, 0, 0, 0); | 311 | DPRINTF("%jd: no memory", unp->unp_number, 0, 0, 0); | |
312 | if_statinc(ifp, if_ierrors); | 312 | if_statinc(ifp, if_ierrors); | |
313 | return; | 313 | return; | |
314 | } | 314 | } | |
315 | 315 | |||
316 | m_set_rcvif(m, ifp); | 316 | m_set_rcvif(m, ifp); | |
317 | m->m_pkthdr.csum_flags = csum_flags; | 317 | m->m_pkthdr.csum_flags = csum_flags; | |
318 | m->m_pkthdr.csum_data = csum_data; | 318 | m->m_pkthdr.csum_data = csum_data; | |
319 | m->m_flags |= mbuf_flags; | 319 | m->m_flags |= mbuf_flags; | |
320 | memcpy(mtod(m, uint8_t *), buf, buflen); | 320 | memcpy(mtod(m, uint8_t *), buf, buflen); | |
321 | 321 | |||
322 | /* push the packet up */ | 322 | /* push the packet up */ | |
323 | if_percpuq_enqueue(ifp->if_percpuq, m); | 323 | if_percpuq_enqueue(ifp->if_percpuq, m); | |
324 | } | 324 | } | |
325 | 325 | |||
326 | void | 326 | void | |
327 | usbnet_input(struct usbnet * const un, uint8_t *buf, size_t buflen) | 327 | usbnet_input(struct usbnet * const un, uint8_t *buf, size_t buflen) | |
328 | { | 328 | { | |
329 | USBNETHIST_FUNC(); | 329 | USBNETHIST_FUNC(); | |
330 | struct ifnet * const ifp = usbnet_ifp(un); | 330 | struct ifnet * const ifp = usbnet_ifp(un); | |
331 | struct usbnet_private * const unp __unused = un->un_pri; | 331 | struct usbnet_private * const unp __unused = un->un_pri; | |
332 | struct mbuf *m; | 332 | struct mbuf *m; | |
333 | 333 | |||
334 | USBNETHIST_CALLARGSN(5, "%jd: enter: buf %#jx len %ju", | 334 | USBNETHIST_CALLARGSN(5, "%jd: enter: buf %#jx len %ju", | |
335 | unp->unp_number, (uintptr_t)buf, buflen, 0); | 335 | unp->unp_number, (uintptr_t)buf, buflen, 0); | |
336 | 336 | |||
337 | usbnet_isowned_rx(un); | 337 | usbnet_isowned_rx(un); | |
338 | 338 | |||
339 | m = usbnet_newbuf(buflen); | 339 | m = usbnet_newbuf(buflen); | |
340 | if (m == NULL) { | 340 | if (m == NULL) { | |
341 | if_statinc(ifp, if_ierrors); | 341 | if_statinc(ifp, if_ierrors); | |
342 | return; | 342 | return; | |
343 | } | 343 | } | |
344 | 344 | |||
345 | m_set_rcvif(m, ifp); | 345 | m_set_rcvif(m, ifp); | |
346 | memcpy(mtod(m, char *), buf, buflen); | 346 | memcpy(mtod(m, char *), buf, buflen); | |
347 | 347 | |||
348 | /* push the packet up */ | 348 | /* push the packet up */ | |
349 | if_input(ifp, m); | 349 | if_input(ifp, m); | |
350 | } | 350 | } | |
351 | 351 | |||
352 | /* | 352 | /* | |
353 | * A frame has been uploaded: pass the resulting mbuf chain up to | 353 | * A frame has been uploaded: pass the resulting mbuf chain up to | |
354 | * the higher level protocols. | 354 | * the higher level protocols. | |
355 | */ | 355 | */ | |
356 | static void | 356 | static void | |
357 | usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | 357 | usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | |
358 | { | 358 | { | |
359 | USBNETHIST_FUNC(); | 359 | USBNETHIST_FUNC(); | |
360 | struct usbnet_chain * const c = priv; | 360 | struct usbnet_chain * const c = priv; | |
361 | struct usbnet * const un = c->unc_un; | 361 | struct usbnet * const un = c->unc_un; | |
362 | struct usbnet_private * const unp = un->un_pri; | 362 | struct usbnet_private * const unp = un->un_pri; | |
363 | uint32_t total_len; | 363 | uint32_t total_len; | |
364 | 364 | |||
365 | USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", | 365 | USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", | |
366 | unp->unp_number, status, (uintptr_t)xfer, 0); | 366 | unp->unp_number, status, (uintptr_t)xfer, 0); | |
367 | 367 | |||
368 | mutex_enter(&unp->unp_rxlock); | 368 | mutex_enter(&unp->unp_rxlock); | |
369 | 369 | |||
370 | if (usbnet_isdying(un) || unp->unp_stopping || | 370 | if (usbnet_isdying(un) || unp->unp_stopping || | |
371 | status == USBD_INVAL || status == USBD_NOT_STARTED || | 371 | status == USBD_INVAL || status == USBD_NOT_STARTED || | |
372 | status == USBD_CANCELLED) | 372 | status == USBD_CANCELLED) | |
373 | goto out; | 373 | goto out; | |
374 | 374 | |||
375 | if (status != USBD_NORMAL_COMPLETION) { | 375 | if (status != USBD_NORMAL_COMPLETION) { | |
376 | if (usbd_ratecheck(&unp->unp_rx_notice)) | 376 | if (usbd_ratecheck(&unp->unp_rx_notice)) | |
377 | device_printf(un->un_dev, "usb errors on rx: %s\n", | 377 | device_printf(un->un_dev, "usb errors on rx: %s\n", | |
378 | usbd_errstr(status)); | 378 | usbd_errstr(status)); | |
379 | if (status == USBD_STALLED) | 379 | if (status == USBD_STALLED) | |
380 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_RX]); | 380 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_RX]); | |
381 | goto done; | 381 | goto done; | |
382 | } | 382 | } | |
383 | 383 | |||
384 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); | 384 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); | |
385 | 385 | |||
386 | if (total_len > un->un_rx_bufsz) { | 386 | if (total_len > un->un_rx_bufsz) { | |
387 | aprint_error_dev(un->un_dev, | 387 | aprint_error_dev(un->un_dev, | |
388 | "rxeof: too large transfer (%u > %u)\n", | 388 | "rxeof: too large transfer (%u > %u)\n", | |
389 | total_len, un->un_rx_bufsz); | 389 | total_len, un->un_rx_bufsz); | |
390 | goto done; | 390 | goto done; | |
391 | } | 391 | } | |
392 | 392 | |||
393 | uno_rx_loop(un, c, total_len); | 393 | uno_rx_loop(un, c, total_len); | |
394 | usbnet_isowned_rx(un); | 394 | usbnet_isowned_rx(un); | |
395 | 395 | |||
396 | done: | 396 | done: | |
397 | if (usbnet_isdying(un) || unp->unp_stopping) | 397 | if (usbnet_isdying(un) || unp->unp_stopping) | |
398 | goto out; | 398 | goto out; | |
399 | 399 | |||
400 | mutex_exit(&unp->unp_rxlock); | 400 | mutex_exit(&unp->unp_rxlock); | |
401 | 401 | |||
402 | /* Setup new transfer. */ | 402 | /* Setup new transfer. */ | |
403 | usbd_setup_xfer(xfer, c, c->unc_buf, un->un_rx_bufsz, | 403 | usbd_setup_xfer(xfer, c, c->unc_buf, un->un_rx_bufsz, | |
404 | un->un_rx_xfer_flags, USBD_NO_TIMEOUT, usbnet_rxeof); | 404 | un->un_rx_xfer_flags, USBD_NO_TIMEOUT, usbnet_rxeof); | |
405 | usbd_transfer(xfer); | 405 | usbd_transfer(xfer); | |
406 | return; | 406 | return; | |
407 | 407 | |||
408 | out: | 408 | out: | |
409 | mutex_exit(&unp->unp_rxlock); | 409 | mutex_exit(&unp->unp_rxlock); | |
410 | } | 410 | } | |
411 | 411 | |||
412 | static void | 412 | static void | |
413 | usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | 413 | usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | |
414 | { | 414 | { | |
415 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 415 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
416 | struct usbnet_chain * const c = priv; | 416 | struct usbnet_chain * const c = priv; | |
417 | struct usbnet * const un = c->unc_un; | 417 | struct usbnet * const un = c->unc_un; | |
418 | struct usbnet_cdata * const cd = un_cdata(un); | 418 | struct usbnet_cdata * const cd = un_cdata(un); | |
419 | struct usbnet_private * const unp = un->un_pri; | 419 | struct usbnet_private * const unp = un->un_pri; | |
420 | struct ifnet * const ifp = usbnet_ifp(un); | 420 | struct ifnet * const ifp = usbnet_ifp(un); | |
421 | 421 | |||
422 | USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", | 422 | USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", | |
423 | unp->unp_number, status, (uintptr_t)xfer, 0); | 423 | unp->unp_number, status, (uintptr_t)xfer, 0); | |
424 | 424 | |||
425 | mutex_enter(&unp->unp_txlock); | 425 | mutex_enter(&unp->unp_txlock); | |
426 | if (unp->unp_stopping || usbnet_isdying(un)) { | 426 | if (unp->unp_stopping || usbnet_isdying(un)) { | |
427 | mutex_exit(&unp->unp_txlock); | 427 | mutex_exit(&unp->unp_txlock); | |
428 | return; | 428 | return; | |
429 | } | 429 | } | |
430 | 430 | |||
431 | KASSERT(cd->uncd_tx_cnt > 0); | 431 | KASSERT(cd->uncd_tx_cnt > 0); | |
432 | cd->uncd_tx_cnt--; | 432 | cd->uncd_tx_cnt--; | |
433 | 433 | |||
434 | unp->unp_timer = 0; | 434 | unp->unp_timer = 0; | |
435 | 435 | |||
436 | switch (status) { | 436 | switch (status) { | |
437 | case USBD_NOT_STARTED: | 437 | case USBD_NOT_STARTED: | |
438 | case USBD_CANCELLED: | 438 | case USBD_CANCELLED: | |
439 | break; | 439 | break; | |
440 | 440 | |||
441 | case USBD_NORMAL_COMPLETION: | 441 | case USBD_NORMAL_COMPLETION: | |
442 | if_statinc(ifp, if_opackets); | 442 | if_statinc(ifp, if_opackets); | |
443 | break; | 443 | break; | |
444 | 444 | |||
445 | default: | 445 | default: | |
446 | 446 | |||
447 | if_statinc(ifp, if_oerrors); | 447 | if_statinc(ifp, if_oerrors); | |
448 | if (usbd_ratecheck(&unp->unp_tx_notice)) | 448 | if (usbd_ratecheck(&unp->unp_tx_notice)) | |
449 | device_printf(un->un_dev, "usb error on tx: %s\n", | 449 | device_printf(un->un_dev, "usb error on tx: %s\n", | |
450 | usbd_errstr(status)); | 450 | usbd_errstr(status)); | |
451 | if (status == USBD_STALLED) | 451 | if (status == USBD_STALLED) | |
452 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_TX]); | 452 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_TX]); | |
453 | break; | 453 | break; | |
454 | } | 454 | } | |
455 | 455 | |||
456 | mutex_exit(&unp->unp_txlock); | 456 | mutex_exit(&unp->unp_txlock); | |
457 | 457 | |||
458 | if (status == USBD_NORMAL_COMPLETION && !IFQ_IS_EMPTY(&ifp->if_snd)) | 458 | if (status == USBD_NORMAL_COMPLETION && !IFQ_IS_EMPTY(&ifp->if_snd)) | |
459 | (*ifp->if_start)(ifp); | 459 | (*ifp->if_start)(ifp); | |
460 | } | 460 | } | |
461 | 461 | |||
462 | static void | 462 | static void | |
463 | usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) | 463 | usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) | |
464 | { | 464 | { | |
465 | USBNETHIST_FUNC(); | 465 | USBNETHIST_FUNC(); | |
466 | struct usbnet * const un = priv; | 466 | struct usbnet * const un = priv; | |
467 | struct usbnet_private * const unp = un->un_pri; | 467 | struct usbnet_private * const unp = un->un_pri; | |
468 | struct usbnet_intr * const uni = un->un_intr; | 468 | struct usbnet_intr * const uni = un->un_intr; | |
469 | 469 | |||
470 | if (uni == NULL || usbnet_isdying(un) || unp->unp_stopping || | 470 | if (uni == NULL || usbnet_isdying(un) || unp->unp_stopping || | |
471 | status == USBD_INVAL || status == USBD_NOT_STARTED || | 471 | status == USBD_INVAL || status == USBD_NOT_STARTED || | |
472 | status == USBD_CANCELLED) { | 472 | status == USBD_CANCELLED) { | |
473 | USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx", | 473 | USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx", | |
474 | unp->unp_number, (uintptr_t)uni, | 474 | unp->unp_number, (uintptr_t)uni, | |
475 | (usbnet_isdying(un) << 8) | unp->unp_stopping, status); | 475 | (usbnet_isdying(un) << 8) | unp->unp_stopping, status); | |
476 | return; | 476 | return; | |
477 | } | 477 | } | |
478 | 478 | |||
479 | if (status != USBD_NORMAL_COMPLETION) { | 479 | if (status != USBD_NORMAL_COMPLETION) { | |
480 | if (usbd_ratecheck(&unp->unp_intr_notice)) { | 480 | if (usbd_ratecheck(&unp->unp_intr_notice)) { | |
481 | aprint_error_dev(un->un_dev, "usb error on intr: %s\n", | 481 | aprint_error_dev(un->un_dev, "usb error on intr: %s\n", | |
482 | usbd_errstr(status)); | 482 | usbd_errstr(status)); | |
483 | } | 483 | } | |
484 | if (status == USBD_STALLED) | 484 | if (status == USBD_STALLED) | |
485 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_INTR]); | 485 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_INTR]); | |
486 | USBNETHIST_CALLARGS("%jd: not normal status %#jx", | 486 | USBNETHIST_CALLARGS("%jd: not normal status %#jx", | |
487 | unp->unp_number, status, 0, 0); | 487 | unp->unp_number, status, 0, 0); | |
488 | return; | 488 | return; | |
489 | } | 489 | } | |
490 | 490 | |||
491 | uno_intr(un, status); | 491 | uno_intr(un, status); | |
492 | } | 492 | } | |
493 | 493 | |||
494 | static void | 494 | static void | |
495 | usbnet_start_locked(struct ifnet *ifp) | 495 | usbnet_start_locked(struct ifnet *ifp) | |
496 | { | 496 | { | |
497 | USBNETHIST_FUNC(); | 497 | USBNETHIST_FUNC(); | |
498 | struct usbnet * const un = ifp->if_softc; | 498 | struct usbnet * const un = ifp->if_softc; | |
499 | struct usbnet_cdata * const cd = un_cdata(un); | 499 | struct usbnet_cdata * const cd = un_cdata(un); | |
500 | struct usbnet_private * const unp = un->un_pri; | 500 | struct usbnet_private * const unp = un->un_pri; | |
501 | struct mbuf *m; | 501 | struct mbuf *m; | |
502 | unsigned length; | 502 | unsigned length; | |
503 | bool done_transmit = false; | 503 | bool done_transmit = false; | |
504 | int idx, count; | 504 | int idx, count; | |
505 | 505 | |||
506 | USBNETHIST_CALLARGS("%jd: tx_cnt %jd list_cnt %jd link %jd", | 506 | USBNETHIST_CALLARGS("%jd: tx_cnt %jd list_cnt %jd link %jd", | |
507 | unp->unp_number, cd->uncd_tx_cnt, un->un_tx_list_cnt, | 507 | unp->unp_number, cd->uncd_tx_cnt, un->un_tx_list_cnt, | |
508 | unp->unp_link); | 508 | unp->unp_link); | |
509 | 509 | |||
510 | usbnet_isowned_tx(un); | 510 | usbnet_isowned_tx(un); | |
511 | KASSERT(cd->uncd_tx_cnt <= un->un_tx_list_cnt); | 511 | KASSERT(cd->uncd_tx_cnt <= un->un_tx_list_cnt); | |
512 | 512 | |||
513 | if (!unp->unp_link || (ifp->if_flags & IFF_RUNNING) == 0) { | 513 | if (!unp->unp_link || (ifp->if_flags & IFF_RUNNING) == 0) { | |
514 | DPRINTF("start called no link (%jx) or running (flags %jx)", | 514 | DPRINTF("start called no link (%jx) or running (flags %jx)", | |
515 | unp->unp_link, ifp->if_flags, 0, 0); | 515 | unp->unp_link, ifp->if_flags, 0, 0); | |
516 | return; | 516 | return; | |
517 | } | 517 | } | |
518 | 518 | |||
519 | if (cd->uncd_tx_cnt == un->un_tx_list_cnt) { | 519 | if (cd->uncd_tx_cnt == un->un_tx_list_cnt) { | |
520 | DPRINTF("start called, tx busy (%#jx == %#jx)", | 520 | DPRINTF("start called, tx busy (%#jx == %#jx)", | |
521 | cd->uncd_tx_cnt, un->un_tx_list_cnt, 0, 0); | 521 | cd->uncd_tx_cnt, un->un_tx_list_cnt, 0, 0); | |
522 | return; | 522 | return; | |
523 | } | 523 | } | |
524 | 524 | |||
525 | idx = cd->uncd_tx_prod; | 525 | idx = cd->uncd_tx_prod; | |
526 | count = 0; | 526 | count = 0; | |
527 | while (cd->uncd_tx_cnt < un->un_tx_list_cnt) { | 527 | while (cd->uncd_tx_cnt < un->un_tx_list_cnt) { | |
528 | IFQ_POLL(&ifp->if_snd, m); | 528 | IFQ_POLL(&ifp->if_snd, m); | |
529 | if (m == NULL) { | 529 | if (m == NULL) { | |
530 | DPRINTF("start called, queue empty", 0, 0, 0, 0); | 530 | DPRINTF("start called, queue empty", 0, 0, 0, 0); | |
531 | break; | 531 | break; | |
532 | } | 532 | } | |
533 | KASSERT(m->m_pkthdr.len <= un->un_tx_bufsz); | 533 | KASSERT(m->m_pkthdr.len <= un->un_tx_bufsz); | |
534 | 534 | |||
535 | struct usbnet_chain *c = &cd->uncd_tx_chain[idx]; | 535 | struct usbnet_chain *c = &cd->uncd_tx_chain[idx]; | |
536 | 536 | |||
537 | length = uno_tx_prepare(un, m, c); | 537 | length = uno_tx_prepare(un, m, c); | |
538 | if (length == 0) { | 538 | if (length == 0) { | |
539 | DPRINTF("uno_tx_prepare gave zero length", 0, 0, 0, 0); | 539 | DPRINTF("uno_tx_prepare gave zero length", 0, 0, 0, 0); | |
540 | if_statinc(ifp, if_oerrors); | 540 | if_statinc(ifp, if_oerrors); | |
541 | break; | 541 | break; | |
542 | } | 542 | } | |
543 | 543 | |||
544 | if (__predict_false(c->unc_xfer == NULL)) { | 544 | if (__predict_false(c->unc_xfer == NULL)) { | |
545 | DPRINTF("unc_xfer is NULL", 0, 0, 0, 0); | 545 | DPRINTF("unc_xfer is NULL", 0, 0, 0, 0); | |
546 | if_statinc(ifp, if_oerrors); | 546 | if_statinc(ifp, if_oerrors); | |
547 | break; | 547 | break; | |
548 | } | 548 | } | |
549 | 549 | |||
550 | usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, length, | 550 | usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, length, | |
551 | un->un_tx_xfer_flags, 10000, usbnet_txeof); | 551 | un->un_tx_xfer_flags, 10000, usbnet_txeof); | |
552 | 552 | |||
553 | /* Transmit */ | 553 | /* Transmit */ | |
554 | usbd_status err = usbd_transfer(c->unc_xfer); | 554 | usbd_status err = usbd_transfer(c->unc_xfer); | |
555 | if (err != USBD_IN_PROGRESS) { | 555 | if (err != USBD_IN_PROGRESS) { | |
556 | DPRINTF("usbd_transfer on %#jx for %ju bytes: %jd", | 556 | DPRINTF("usbd_transfer on %#jx for %ju bytes: %jd", | |
557 | (uintptr_t)c->unc_buf, length, err, 0); | 557 | (uintptr_t)c->unc_buf, length, err, 0); | |
558 | if_statinc(ifp, if_oerrors); | 558 | if_statinc(ifp, if_oerrors); | |
559 | break; | 559 | break; | |
560 | } | 560 | } | |
561 | done_transmit = true; | 561 | done_transmit = true; | |
562 | 562 | |||
563 | IFQ_DEQUEUE(&ifp->if_snd, m); | 563 | IFQ_DEQUEUE(&ifp->if_snd, m); | |
564 | 564 | |||
565 | /* | 565 | /* | |
566 | * If there's a BPF listener, bounce a copy of this frame | 566 | * If there's a BPF listener, bounce a copy of this frame | |
567 | * to him. | 567 | * to him. | |
568 | */ | 568 | */ | |
569 | bpf_mtap(ifp, m, BPF_D_OUT); | 569 | bpf_mtap(ifp, m, BPF_D_OUT); | |
570 | m_freem(m); | 570 | m_freem(m); | |
571 | 571 | |||
572 | idx = (idx + 1) % un->un_tx_list_cnt; | 572 | idx = (idx + 1) % un->un_tx_list_cnt; | |
573 | cd->uncd_tx_cnt++; | 573 | cd->uncd_tx_cnt++; | |
574 | count++; | 574 | count++; | |
575 | } | 575 | } | |
576 | cd->uncd_tx_prod = idx; | 576 | cd->uncd_tx_prod = idx; | |
577 | 577 | |||
578 | DPRINTF("finished with start; tx_cnt %jd list_cnt %jd link %jd", | 578 | DPRINTF("finished with start; tx_cnt %jd list_cnt %jd link %jd", | |
579 | cd->uncd_tx_cnt, un->un_tx_list_cnt, unp->unp_link, 0); | 579 | cd->uncd_tx_cnt, un->un_tx_list_cnt, unp->unp_link, 0); | |
580 | 580 | |||
581 | /* | 581 | /* | |
582 | * Set a timeout in case the chip goes out to lunch. | 582 | * Set a timeout in case the chip goes out to lunch. | |
583 | */ | 583 | */ | |
584 | if (done_transmit) | 584 | if (done_transmit) | |
585 | unp->unp_timer = 5; | 585 | unp->unp_timer = 5; | |
586 | 586 | |||
587 | if (count != 0) | 587 | if (count != 0) | |
588 | rnd_add_uint32(&unp->unp_rndsrc, count); | 588 | rnd_add_uint32(&unp->unp_rndsrc, count); | |
589 | } | 589 | } | |
590 | 590 | |||
591 | static void | 591 | static void | |
592 | usbnet_if_start(struct ifnet *ifp) | 592 | usbnet_if_start(struct ifnet *ifp) | |
593 | { | 593 | { | |
594 | struct usbnet * const un = ifp->if_softc; | 594 | struct usbnet * const un = ifp->if_softc; | |
595 | struct usbnet_private * const unp = un->un_pri; | 595 | struct usbnet_private * const unp = un->un_pri; | |
596 | 596 | |||
597 | USBNETHIST_FUNC(); | 597 | USBNETHIST_FUNC(); | |
598 | USBNETHIST_CALLARGS("%jd: stopping %jd", | 598 | USBNETHIST_CALLARGS("%jd: stopping %jd", | |
599 | unp->unp_number, unp->unp_stopping, 0, 0); | 599 | unp->unp_number, unp->unp_stopping, 0, 0); | |
600 | 600 | |||
601 | mutex_enter(&unp->unp_txlock); | 601 | mutex_enter(&unp->unp_txlock); | |
602 | if (!unp->unp_stopping) | 602 | if (!unp->unp_stopping) | |
603 | usbnet_start_locked(ifp); | 603 | usbnet_start_locked(ifp); | |
604 | mutex_exit(&unp->unp_txlock); | 604 | mutex_exit(&unp->unp_txlock); | |
605 | } | 605 | } | |
606 | 606 | |||
607 | /* | 607 | /* | |
608 | * Chain management. | 608 | * Chain management. | |
609 | * | 609 | * | |
610 | * RX and TX are identical. Keep them that way. | 610 | * RX and TX are identical. Keep them that way. | |
611 | */ | 611 | */ | |
612 | 612 | |||
613 | /* Start of common RX functions */ | 613 | /* Start of common RX functions */ | |
614 | 614 | |||
615 | static size_t | 615 | static size_t | |
616 | usbnet_rx_list_size(struct usbnet_cdata * const cd, struct usbnet * const un) | 616 | usbnet_rx_list_size(struct usbnet_cdata * const cd, struct usbnet * const un) | |
617 | { | 617 | { | |
618 | return sizeof(*cd->uncd_rx_chain) * un->un_rx_list_cnt; | 618 | return sizeof(*cd->uncd_rx_chain) * un->un_rx_list_cnt; | |
619 | } | 619 | } | |
620 | 620 | |||
621 | static void | 621 | static void | |
622 | usbnet_rx_list_alloc(struct usbnet * const un) | 622 | usbnet_rx_list_alloc(struct usbnet * const un) | |
623 | { | 623 | { | |
624 | struct usbnet_cdata * const cd = un_cdata(un); | 624 | struct usbnet_cdata * const cd = un_cdata(un); | |
625 | 625 | |||
626 | cd->uncd_rx_chain = kmem_zalloc(usbnet_rx_list_size(cd, un), KM_SLEEP); | 626 | cd->uncd_rx_chain = kmem_zalloc(usbnet_rx_list_size(cd, un), KM_SLEEP); | |
627 | } | 627 | } | |
628 | 628 | |||
629 | static void | 629 | static void | |
630 | usbnet_rx_list_free(struct usbnet * const un) | 630 | usbnet_rx_list_free(struct usbnet * const un) | |
631 | { | 631 | { | |
632 | struct usbnet_cdata * const cd = un_cdata(un); | 632 | struct usbnet_cdata * const cd = un_cdata(un); | |
633 | 633 | |||
634 | if (cd->uncd_rx_chain) { | 634 | if (cd->uncd_rx_chain) { | |
635 | kmem_free(cd->uncd_rx_chain, usbnet_rx_list_size(cd, un)); | 635 | kmem_free(cd->uncd_rx_chain, usbnet_rx_list_size(cd, un)); | |
636 | cd->uncd_rx_chain = NULL; | 636 | cd->uncd_rx_chain = NULL; | |
637 | } | 637 | } | |
638 | } | 638 | } | |
639 | 639 | |||
640 | static int | 640 | static int | |
641 | usbnet_rx_list_init(struct usbnet * const un) | 641 | usbnet_rx_list_init(struct usbnet * const un) | |
642 | { | 642 | { | |
643 | struct usbnet_cdata * const cd = un_cdata(un); | 643 | struct usbnet_cdata * const cd = un_cdata(un); | |
644 | struct usbnet_private * const unp = un->un_pri; | 644 | struct usbnet_private * const unp = un->un_pri; | |
645 | 645 | |||
646 | for (size_t i = 0; i < un->un_rx_list_cnt; i++) { | 646 | for (size_t i = 0; i < un->un_rx_list_cnt; i++) { | |
647 | struct usbnet_chain *c = &cd->uncd_rx_chain[i]; | 647 | struct usbnet_chain *c = &cd->uncd_rx_chain[i]; | |
648 | 648 | |||
649 | c->unc_un = un; | 649 | c->unc_un = un; | |
650 | if (c->unc_xfer == NULL) { | 650 | if (c->unc_xfer == NULL) { | |
651 | int err = usbd_create_xfer(unp->unp_ep[USBNET_ENDPT_RX], | 651 | int err = usbd_create_xfer(unp->unp_ep[USBNET_ENDPT_RX], | |
652 | un->un_rx_bufsz, un->un_rx_xfer_flags, 0, | 652 | un->un_rx_bufsz, un->un_rx_xfer_flags, 0, | |
653 | &c->unc_xfer); | 653 | &c->unc_xfer); | |
654 | if (err) | 654 | if (err) | |
655 | return err; | 655 | return err; | |
656 | c->unc_buf = usbd_get_buffer(c->unc_xfer); | 656 | c->unc_buf = usbd_get_buffer(c->unc_xfer); | |
657 | } | 657 | } | |
658 | } | 658 | } | |
659 | 659 | |||
660 | return 0; | 660 | return 0; | |
661 | } | 661 | } | |
662 | 662 | |||
663 | static void | 663 | static void | |
664 | usbnet_rx_list_fini(struct usbnet * const un) | 664 | usbnet_rx_list_fini(struct usbnet * const un) | |
665 | { | 665 | { | |
666 | struct usbnet_cdata * const cd = un_cdata(un); | 666 | struct usbnet_cdata * const cd = un_cdata(un); | |
667 | 667 | |||
668 | for (size_t i = 0; i < un->un_rx_list_cnt; i++) { | 668 | for (size_t i = 0; i < un->un_rx_list_cnt; i++) { | |
669 | struct usbnet_chain *c = &cd->uncd_rx_chain[i]; | 669 | struct usbnet_chain *c = &cd->uncd_rx_chain[i]; | |
670 | 670 | |||
671 | if (c->unc_xfer != NULL) { | 671 | if (c->unc_xfer != NULL) { | |
672 | usbd_destroy_xfer(c->unc_xfer); | 672 | usbd_destroy_xfer(c->unc_xfer); | |
673 | c->unc_xfer = NULL; | 673 | c->unc_xfer = NULL; | |
674 | c->unc_buf = NULL; | 674 | c->unc_buf = NULL; | |
675 | } | 675 | } | |
676 | } | 676 | } | |
677 | } | 677 | } | |
678 | 678 | |||
679 | /* End of common RX functions */ | 679 | /* End of common RX functions */ | |
680 | 680 | |||
681 | static void | 681 | static void | |
682 | usbnet_rx_start_pipes(struct usbnet * const un) | 682 | usbnet_rx_start_pipes(struct usbnet * const un) | |
683 | { | 683 | { | |
684 | struct usbnet_cdata * const cd = un_cdata(un); | 684 | struct usbnet_cdata * const cd = un_cdata(un); | |
685 | struct usbnet_private * const unp = un->un_pri; | 685 | struct usbnet_private * const unp = un->un_pri; | |
686 | 686 | |||
687 | mutex_enter(&unp->unp_rxlock); | 687 | mutex_enter(&unp->unp_rxlock); | |
688 | mutex_enter(&unp->unp_txlock); | 688 | mutex_enter(&unp->unp_txlock); | |
689 | unp->unp_stopping = false; | 689 | unp->unp_stopping = false; | |
690 | 690 | |||
691 | for (size_t i = 0; i < un->un_rx_list_cnt; i++) { | 691 | for (size_t i = 0; i < un->un_rx_list_cnt; i++) { | |
692 | struct usbnet_chain *c = &cd->uncd_rx_chain[i]; | 692 | struct usbnet_chain *c = &cd->uncd_rx_chain[i]; | |
693 | 693 | |||
694 | usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, un->un_rx_bufsz, | 694 | usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, un->un_rx_bufsz, | |
695 | un->un_rx_xfer_flags, USBD_NO_TIMEOUT, usbnet_rxeof); | 695 | un->un_rx_xfer_flags, USBD_NO_TIMEOUT, usbnet_rxeof); | |
696 | usbd_transfer(c->unc_xfer); | 696 | usbd_transfer(c->unc_xfer); | |
697 | } | 697 | } | |
698 | 698 | |||
699 | mutex_exit(&unp->unp_txlock); | 699 | mutex_exit(&unp->unp_txlock); | |
700 | mutex_exit(&unp->unp_rxlock); | 700 | mutex_exit(&unp->unp_rxlock); | |
701 | } | 701 | } | |
702 | 702 | |||
703 | /* Start of common TX functions */ | 703 | /* Start of common TX functions */ | |
704 | 704 | |||
705 | static size_t | 705 | static size_t | |
706 | usbnet_tx_list_size(struct usbnet_cdata * const cd, struct usbnet * const un) | 706 | usbnet_tx_list_size(struct usbnet_cdata * const cd, struct usbnet * const un) | |
707 | { | 707 | { | |
708 | return sizeof(*cd->uncd_tx_chain) * un->un_tx_list_cnt; | 708 | return sizeof(*cd->uncd_tx_chain) * un->un_tx_list_cnt; | |
709 | } | 709 | } | |
710 | 710 | |||
711 | static void | 711 | static void | |
712 | usbnet_tx_list_alloc(struct usbnet * const un) | 712 | usbnet_tx_list_alloc(struct usbnet * const un) | |
713 | { | 713 | { | |
714 | struct usbnet_cdata * const cd = un_cdata(un); | 714 | struct usbnet_cdata * const cd = un_cdata(un); | |
715 | 715 | |||
716 | cd->uncd_tx_chain = kmem_zalloc(usbnet_tx_list_size(cd, un), KM_SLEEP); | 716 | cd->uncd_tx_chain = kmem_zalloc(usbnet_tx_list_size(cd, un), KM_SLEEP); | |
717 | } | 717 | } | |
718 | 718 | |||
719 | static void | 719 | static void | |
720 | usbnet_tx_list_free(struct usbnet * const un) | 720 | usbnet_tx_list_free(struct usbnet * const un) | |
721 | { | 721 | { | |
722 | struct usbnet_cdata * const cd = un_cdata(un); | 722 | struct usbnet_cdata * const cd = un_cdata(un); | |
723 | 723 | |||
724 | if (cd->uncd_tx_chain) { | 724 | if (cd->uncd_tx_chain) { | |
725 | kmem_free(cd->uncd_tx_chain, usbnet_tx_list_size(cd, un)); | 725 | kmem_free(cd->uncd_tx_chain, usbnet_tx_list_size(cd, un)); | |
726 | cd->uncd_tx_chain = NULL; | 726 | cd->uncd_tx_chain = NULL; | |
727 | } | 727 | } | |
728 | } | 728 | } | |
729 | 729 | |||
730 | static int | 730 | static int | |
731 | usbnet_tx_list_init(struct usbnet * const un) | 731 | usbnet_tx_list_init(struct usbnet * const un) | |
732 | { | 732 | { | |
733 | struct usbnet_cdata * const cd = un_cdata(un); | 733 | struct usbnet_cdata * const cd = un_cdata(un); | |
734 | struct usbnet_private * const unp = un->un_pri; | 734 | struct usbnet_private * const unp = un->un_pri; | |
735 | 735 | |||
736 | for (size_t i = 0; i < un->un_tx_list_cnt; i++) { | 736 | for (size_t i = 0; i < un->un_tx_list_cnt; i++) { | |
737 | struct usbnet_chain *c = &cd->uncd_tx_chain[i]; | 737 | struct usbnet_chain *c = &cd->uncd_tx_chain[i]; | |
738 | 738 | |||
739 | c->unc_un = un; | 739 | c->unc_un = un; | |
740 | if (c->unc_xfer == NULL) { | 740 | if (c->unc_xfer == NULL) { | |
741 | int err = usbd_create_xfer(unp->unp_ep[USBNET_ENDPT_TX], | 741 | int err = usbd_create_xfer(unp->unp_ep[USBNET_ENDPT_TX], | |
742 | un->un_tx_bufsz, un->un_tx_xfer_flags, 0, | 742 | un->un_tx_bufsz, un->un_tx_xfer_flags, 0, | |
743 | &c->unc_xfer); | 743 | &c->unc_xfer); | |
744 | if (err) | 744 | if (err) | |
745 | return err; | 745 | return err; | |
746 | c->unc_buf = usbd_get_buffer(c->unc_xfer); | 746 | c->unc_buf = usbd_get_buffer(c->unc_xfer); | |
747 | } | 747 | } | |
748 | } | 748 | } | |
749 | 749 | |||
750 | return 0; | 750 | return 0; | |
751 | } | 751 | } | |
752 | 752 | |||
753 | static void | 753 | static void | |
754 | usbnet_tx_list_fini(struct usbnet * const un) | 754 | usbnet_tx_list_fini(struct usbnet * const un) | |
755 | { | 755 | { | |
756 | struct usbnet_cdata * const cd = un_cdata(un); | 756 | struct usbnet_cdata * const cd = un_cdata(un); | |
757 | 757 | |||
758 | for (size_t i = 0; i < un->un_tx_list_cnt; i++) { | 758 | for (size_t i = 0; i < un->un_tx_list_cnt; i++) { | |
759 | struct usbnet_chain *c = &cd->uncd_tx_chain[i]; | 759 | struct usbnet_chain *c = &cd->uncd_tx_chain[i]; | |
760 | 760 | |||
761 | if (c->unc_xfer != NULL) { | 761 | if (c->unc_xfer != NULL) { | |
762 | usbd_destroy_xfer(c->unc_xfer); | 762 | usbd_destroy_xfer(c->unc_xfer); | |
763 | c->unc_xfer = NULL; | 763 | c->unc_xfer = NULL; | |
764 | c->unc_buf = NULL; | 764 | c->unc_buf = NULL; | |
765 | } | 765 | } | |
766 | } | 766 | } | |
767 | cd->uncd_tx_prod = cd->uncd_tx_cnt = 0; | 767 | cd->uncd_tx_prod = cd->uncd_tx_cnt = 0; | |
768 | } | 768 | } | |
769 | 769 | |||
770 | /* End of common TX functions */ | 770 | /* End of common TX functions */ | |
771 | 771 | |||
772 | /* Endpoint pipe management. */ | 772 | /* Endpoint pipe management. */ | |
773 | 773 | |||
774 | static void | 774 | static void | |
775 | usbnet_ep_close_pipes(struct usbnet * const un) | 775 | usbnet_ep_close_pipes(struct usbnet * const un) | |
776 | { | 776 | { | |
777 | struct usbnet_private * const unp = un->un_pri; | 777 | struct usbnet_private * const unp = un->un_pri; | |
778 | 778 | |||
779 | for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) { | 779 | for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) { | |
780 | if (unp->unp_ep[i] == NULL) | 780 | if (unp->unp_ep[i] == NULL) | |
781 | continue; | 781 | continue; | |
782 | usbd_status err = usbd_close_pipe(unp->unp_ep[i]); | 782 | usbd_status err = usbd_close_pipe(unp->unp_ep[i]); | |
783 | if (err) | 783 | if (err) | |
784 | aprint_error_dev(un->un_dev, "close pipe %zu: %s\n", i, | 784 | aprint_error_dev(un->un_dev, "close pipe %zu: %s\n", i, | |
785 | usbd_errstr(err)); | 785 | usbd_errstr(err)); | |
786 | unp->unp_ep[i] = NULL; | 786 | unp->unp_ep[i] = NULL; | |
787 | } | 787 | } | |
788 | } | 788 | } | |
789 | 789 | |||
790 | static usbd_status | 790 | static usbd_status | |
791 | usbnet_ep_open_pipes(struct usbnet * const un) | 791 | usbnet_ep_open_pipes(struct usbnet * const un) | |
792 | { | 792 | { | |
793 | struct usbnet_intr * const uni = un->un_intr; | 793 | struct usbnet_intr * const uni = un->un_intr; | |
794 | struct usbnet_private * const unp = un->un_pri; | 794 | struct usbnet_private * const unp = un->un_pri; | |
795 | 795 | |||
796 | for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) { | 796 | for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) { | |
797 | usbd_status err; | 797 | usbd_status err; | |
798 | 798 | |||
799 | if (un->un_ed[i] == 0) | 799 | if (un->un_ed[i] == 0) | |
800 | continue; | 800 | continue; | |
801 | 801 | |||
802 | if (i == USBNET_ENDPT_INTR && uni) { | 802 | if (i == USBNET_ENDPT_INTR && uni) { | |
803 | err = usbd_open_pipe_intr(un->un_iface, un->un_ed[i], | 803 | err = usbd_open_pipe_intr(un->un_iface, un->un_ed[i], | |
804 | USBD_EXCLUSIVE_USE | USBD_MPSAFE, &unp->unp_ep[i], un, | 804 | USBD_EXCLUSIVE_USE | USBD_MPSAFE, &unp->unp_ep[i], un, | |
805 | uni->uni_buf, uni->uni_bufsz, usbnet_pipe_intr, | 805 | uni->uni_buf, uni->uni_bufsz, usbnet_pipe_intr, | |
806 | uni->uni_interval); | 806 | uni->uni_interval); | |
807 | } else { | 807 | } else { | |
808 | err = usbd_open_pipe(un->un_iface, un->un_ed[i], | 808 | err = usbd_open_pipe(un->un_iface, un->un_ed[i], | |
809 | USBD_EXCLUSIVE_USE | USBD_MPSAFE, &unp->unp_ep[i]); | 809 | USBD_EXCLUSIVE_USE | USBD_MPSAFE, &unp->unp_ep[i]); | |
810 | } | 810 | } | |
811 | if (err) { | 811 | if (err) { | |
812 | usbnet_ep_close_pipes(un); | 812 | usbnet_ep_close_pipes(un); | |
813 | return err; | 813 | return err; | |
814 | } | 814 | } | |
815 | } | 815 | } | |
816 | 816 | |||
817 | return USBD_NORMAL_COMPLETION; | 817 | return USBD_NORMAL_COMPLETION; | |
818 | } | 818 | } | |
819 | 819 | |||
820 | static usbd_status | 820 | static void | |
821 | usbnet_ep_stop_pipes(struct usbnet * const un) | 821 | usbnet_ep_stop_pipes(struct usbnet * const un) | |
822 | { | 822 | { | |
823 | struct usbnet_private * const unp = un->un_pri; | 823 | struct usbnet_private * const unp = un->un_pri; | |
824 | usbd_status err = USBD_NORMAL_COMPLETION; | |||
825 | 824 | |||
826 | for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) { | 825 | for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) { | |
827 | if (unp->unp_ep[i] == NULL) | 826 | if (unp->unp_ep[i] == NULL) | |
828 | continue; | 827 | continue; | |
829 | usbd_status err2 = usbd_abort_pipe(unp->unp_ep[i]); | 828 | usbd_abort_pipe(unp->unp_ep[i]); | |
830 | if (err == USBD_NORMAL_COMPLETION && err2) | |||
831 | err = err2; | |||
832 | } | 829 | } | |
833 | ||||
834 | return err; | |||
835 | } | 830 | } | |
836 | 831 | |||
837 | static int | 832 | static int | |
838 | usbnet_init_rx_tx(struct usbnet * const un) | 833 | usbnet_init_rx_tx(struct usbnet * const un) | |
839 | { | 834 | { | |
840 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 835 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
841 | struct usbnet_private * const unp = un->un_pri; | 836 | struct usbnet_private * const unp = un->un_pri; | |
842 | struct ifnet * const ifp = usbnet_ifp(un); | 837 | struct ifnet * const ifp = usbnet_ifp(un); | |
843 | usbd_status err; | 838 | usbd_status err; | |
844 | int error = 0; | 839 | int error = 0; | |
845 | 840 | |||
846 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), | 841 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), | |
847 | "%s", ifp->if_xname); | 842 | "%s", ifp->if_xname); | |
848 | 843 | |||
849 | usbnet_isowned_core(un); | 844 | usbnet_isowned_core(un); | |
850 | 845 | |||
851 | if (usbnet_isdying(un)) { | 846 | if (usbnet_isdying(un)) { | |
852 | return EIO; | 847 | return EIO; | |
853 | } | 848 | } | |
854 | 849 | |||
855 | /* Open RX and TX pipes. */ | 850 | /* Open RX and TX pipes. */ | |
856 | err = usbnet_ep_open_pipes(un); | 851 | err = usbnet_ep_open_pipes(un); | |
857 | if (err) { | 852 | if (err) { | |
858 | aprint_error_dev(un->un_dev, "open rx/tx pipes failed: %s\n", | 853 | aprint_error_dev(un->un_dev, "open rx/tx pipes failed: %s\n", | |
859 | usbd_errstr(err)); | 854 | usbd_errstr(err)); | |
860 | error = EIO; | 855 | error = EIO; | |
861 | goto out; | 856 | goto out; | |
862 | } | 857 | } | |
863 | 858 | |||
864 | /* Init RX ring. */ | 859 | /* Init RX ring. */ | |
865 | if (usbnet_rx_list_init(un)) { | 860 | if (usbnet_rx_list_init(un)) { | |
866 | aprint_error_dev(un->un_dev, "rx list init failed\n"); | 861 | aprint_error_dev(un->un_dev, "rx list init failed\n"); | |
867 | error = ENOBUFS; | 862 | error = ENOBUFS; | |
868 | goto out; | 863 | goto out; | |
869 | } | 864 | } | |
870 | 865 | |||
871 | /* Init TX ring. */ | 866 | /* Init TX ring. */ | |
872 | if (usbnet_tx_list_init(un)) { | 867 | if (usbnet_tx_list_init(un)) { | |
873 | aprint_error_dev(un->un_dev, "tx list init failed\n"); | 868 | aprint_error_dev(un->un_dev, "tx list init failed\n"); | |
874 | error = ENOBUFS; | 869 | error = ENOBUFS; | |
875 | goto out; | 870 | goto out; | |
876 | } | 871 | } | |
877 | 872 | |||
878 | /* Indicate we are up and running. */ | 873 | /* Indicate we are up and running. */ | |
879 | /* XXX urndis calls usbnet_init_rx_tx before usbnet_attach_ifp. */ | 874 | /* XXX urndis calls usbnet_init_rx_tx before usbnet_attach_ifp. */ | |
880 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), | 875 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), | |
881 | "%s", ifp->if_xname); | 876 | "%s", ifp->if_xname); | |
882 | ifp->if_flags |= IFF_RUNNING; | 877 | ifp->if_flags |= IFF_RUNNING; | |
883 | 878 | |||
884 | /* | 879 | /* | |
885 | * If the hardware has a multicast filter, program it and then | 880 | * If the hardware has a multicast filter, program it and then | |
886 | * allow updates to it while we're running. | 881 | * allow updates to it while we're running. | |
887 | */ | 882 | */ | |
888 | if (un->un_ops->uno_mcast) { | 883 | if (un->un_ops->uno_mcast) { | |
889 | mutex_enter(&unp->unp_mcastlock); | 884 | mutex_enter(&unp->unp_mcastlock); | |
890 | (*un->un_ops->uno_mcast)(ifp); | 885 | (*un->un_ops->uno_mcast)(ifp); | |
891 | unp->unp_mcastactive = true; | 886 | unp->unp_mcastactive = true; | |
892 | mutex_exit(&unp->unp_mcastlock); | 887 | mutex_exit(&unp->unp_mcastlock); | |
893 | } | 888 | } | |
894 | 889 | |||
895 | /* Start up the receive pipe(s). */ | 890 | /* Start up the receive pipe(s). */ | |
896 | usbnet_rx_start_pipes(un); | 891 | usbnet_rx_start_pipes(un); | |
897 | 892 | |||
898 | callout_schedule(&unp->unp_stat_ch, hz); | 893 | callout_schedule(&unp->unp_stat_ch, hz); | |
899 | 894 | |||
900 | out: | 895 | out: | |
901 | if (error) { | 896 | if (error) { | |
902 | usbnet_rx_list_fini(un); | 897 | usbnet_rx_list_fini(un); | |
903 | usbnet_tx_list_fini(un); | 898 | usbnet_tx_list_fini(un); | |
904 | usbnet_ep_close_pipes(un); | 899 | usbnet_ep_close_pipes(un); | |
905 | } | 900 | } | |
906 | 901 | |||
907 | /* | 902 | /* | |
908 | * For devices without any media autodetection, treat success | 903 | * For devices without any media autodetection, treat success | |
909 | * here as an active link. | 904 | * here as an active link. | |
910 | */ | 905 | */ | |
911 | if (un->un_ops->uno_statchg == NULL) | 906 | if (un->un_ops->uno_statchg == NULL) | |
912 | usbnet_set_link(un, error == 0); | 907 | usbnet_set_link(un, error == 0); | |
913 | 908 | |||
914 | usbnet_isowned_core(un); | 909 | usbnet_isowned_core(un); | |
915 | 910 | |||
916 | return error; | 911 | return error; | |
917 | } | 912 | } | |
918 | 913 | |||
919 | /* MII management. */ | 914 | /* MII management. */ | |
920 | 915 | |||
921 | static int | 916 | static int | |
922 | usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val) | 917 | usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val) | |
923 | { | 918 | { | |
924 | USBNETHIST_FUNC(); | 919 | USBNETHIST_FUNC(); | |
925 | struct usbnet * const un = device_private(dev); | 920 | struct usbnet * const un = device_private(dev); | |
926 | int err; | 921 | int err; | |
927 | 922 | |||
928 | /* MII layer ensures core_lock is held. */ | 923 | /* MII layer ensures core_lock is held. */ | |
929 | usbnet_isowned_core(un); | 924 | usbnet_isowned_core(un); | |
930 | 925 | |||
931 | if (usbnet_isdying(un)) { | 926 | if (usbnet_isdying(un)) { | |
932 | return EIO; | 927 | return EIO; | |
933 | } | 928 | } | |
934 | 929 | |||
935 | err = uno_read_reg(un, phy, reg, val); | 930 | err = uno_read_reg(un, phy, reg, val); | |
936 | if (err) { | 931 | if (err) { | |
937 | USBNETHIST_CALLARGS("%jd: read PHY failed: %jd", | 932 | USBNETHIST_CALLARGS("%jd: read PHY failed: %jd", | |
938 | un->un_pri->unp_number, err, 0, 0); | 933 | un->un_pri->unp_number, err, 0, 0); | |
939 | return err; | 934 | return err; | |
940 | } | 935 | } | |
941 | 936 | |||
942 | return 0; | 937 | return 0; | |
943 | } | 938 | } | |
944 | 939 | |||
945 | static int | 940 | static int | |
946 | usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val) | 941 | usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val) | |
947 | { | 942 | { | |
948 | USBNETHIST_FUNC(); | 943 | USBNETHIST_FUNC(); | |
949 | struct usbnet * const un = device_private(dev); | 944 | struct usbnet * const un = device_private(dev); | |
950 | int err; | 945 | int err; | |
951 | 946 | |||
952 | /* MII layer ensures core_lock is held. */ | 947 | /* MII layer ensures core_lock is held. */ | |
953 | usbnet_isowned_core(un); | 948 | usbnet_isowned_core(un); | |
954 | 949 | |||
955 | if (usbnet_isdying(un)) { | 950 | if (usbnet_isdying(un)) { | |
956 | return EIO; | 951 | return EIO; | |
957 | } | 952 | } | |
958 | 953 | |||
959 | err = uno_write_reg(un, phy, reg, val); | 954 | err = uno_write_reg(un, phy, reg, val); | |
960 | if (err) { | 955 | if (err) { | |
961 | USBNETHIST_CALLARGS("%jd: write PHY failed: %jd", | 956 | USBNETHIST_CALLARGS("%jd: write PHY failed: %jd", | |
962 | un->un_pri->unp_number, err, 0, 0); | 957 | un->un_pri->unp_number, err, 0, 0); | |
963 | return err; | 958 | return err; | |
964 | } | 959 | } | |
965 | 960 | |||
966 | return 0; | 961 | return 0; | |
967 | } | 962 | } | |
968 | 963 | |||
969 | static void | 964 | static void | |
970 | usbnet_mii_statchg(struct ifnet *ifp) | 965 | usbnet_mii_statchg(struct ifnet *ifp) | |
971 | { | 966 | { | |
972 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 967 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
973 | struct usbnet * const un = ifp->if_softc; | 968 | struct usbnet * const un = ifp->if_softc; | |
974 | 969 | |||
975 | /* MII layer ensures core_lock is held. */ | 970 | /* MII layer ensures core_lock is held. */ | |
976 | usbnet_isowned_core(un); | 971 | usbnet_isowned_core(un); | |
977 | 972 | |||
978 | uno_mii_statchg(un, ifp); | 973 | uno_mii_statchg(un, ifp); | |
979 | } | 974 | } | |
980 | 975 | |||
981 | static int | 976 | static int | |
982 | usbnet_media_upd(struct ifnet *ifp) | 977 | usbnet_media_upd(struct ifnet *ifp) | |
983 | { | 978 | { | |
984 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 979 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
985 | struct usbnet * const un = ifp->if_softc; | 980 | struct usbnet * const un = ifp->if_softc; | |
986 | struct usbnet_private * const unp = un->un_pri; | 981 | struct usbnet_private * const unp = un->un_pri; | |
987 | struct mii_data * const mii = usbnet_mii(un); | 982 | struct mii_data * const mii = usbnet_mii(un); | |
988 | 983 | |||
989 | /* ifmedia layer ensures core_lock is held. */ | 984 | /* ifmedia layer ensures core_lock is held. */ | |
990 | usbnet_isowned_core(un); | 985 | usbnet_isowned_core(un); | |
991 | 986 | |||
992 | /* ifmedia changes only with IFNET_LOCK held. */ | 987 | /* ifmedia changes only with IFNET_LOCK held. */ | |
993 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | 988 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | |
994 | 989 | |||
995 | if (usbnet_isdying(un)) | 990 | if (usbnet_isdying(un)) | |
996 | return EIO; | 991 | return EIO; | |
997 | 992 | |||
998 | unp->unp_link = false; | 993 | unp->unp_link = false; | |
999 | 994 | |||
1000 | if (mii->mii_instance) { | 995 | if (mii->mii_instance) { | |
1001 | struct mii_softc *miisc; | 996 | struct mii_softc *miisc; | |
1002 | 997 | |||
1003 | LIST_FOREACH(miisc, &mii->mii_phys, mii_list) | 998 | LIST_FOREACH(miisc, &mii->mii_phys, mii_list) | |
1004 | mii_phy_reset(miisc); | 999 | mii_phy_reset(miisc); | |
1005 | } | 1000 | } | |
1006 | 1001 | |||
1007 | return ether_mediachange(ifp); | 1002 | return ether_mediachange(ifp); | |
1008 | } | 1003 | } | |
1009 | 1004 | |||
1010 | /* ioctl */ | 1005 | /* ioctl */ | |
1011 | 1006 | |||
1012 | static int | 1007 | static int | |
1013 | usbnet_ifflags_cb(struct ethercom *ec) | 1008 | usbnet_ifflags_cb(struct ethercom *ec) | |
1014 | { | 1009 | { | |
1015 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 1010 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
1016 | struct ifnet *ifp = &ec->ec_if; | 1011 | struct ifnet *ifp = &ec->ec_if; | |
1017 | struct usbnet *un = ifp->if_softc; | 1012 | struct usbnet *un = ifp->if_softc; | |
1018 | struct usbnet_private * const unp = un->un_pri; | 1013 | struct usbnet_private * const unp = un->un_pri; | |
1019 | int rv = 0; | 1014 | int rv = 0; | |
1020 | 1015 | |||
1021 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | 1016 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | |
1022 | 1017 | |||
1023 | const u_short changed = ifp->if_flags ^ unp->unp_if_flags; | 1018 | const u_short changed = ifp->if_flags ^ unp->unp_if_flags; | |
1024 | if ((changed & ~(IFF_CANTCHANGE | IFF_DEBUG)) == 0) { | 1019 | if ((changed & ~(IFF_CANTCHANGE | IFF_DEBUG)) == 0) { | |
1025 | unp->unp_if_flags = ifp->if_flags; | 1020 | unp->unp_if_flags = ifp->if_flags; | |
1026 | if ((changed & IFF_PROMISC) != 0) | 1021 | if ((changed & IFF_PROMISC) != 0) | |
1027 | rv = ENETRESET; | 1022 | rv = ENETRESET; | |
1028 | } else { | 1023 | } else { | |
1029 | rv = ENETRESET; | 1024 | rv = ENETRESET; | |
1030 | } | 1025 | } | |
1031 | 1026 | |||
1032 | return rv; | 1027 | return rv; | |
1033 | } | 1028 | } | |
1034 | 1029 | |||
1035 | static int | 1030 | static int | |
1036 | usbnet_if_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 1031 | usbnet_if_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
1037 | { | 1032 | { | |
1038 | USBNETHIST_FUNC(); | 1033 | USBNETHIST_FUNC(); | |
1039 | struct usbnet * const un = ifp->if_softc; | 1034 | struct usbnet * const un = ifp->if_softc; | |
1040 | struct usbnet_private * const unp __unused = un->un_pri; | 1035 | struct usbnet_private * const unp __unused = un->un_pri; | |
1041 | int error; | 1036 | int error; | |
1042 | 1037 | |||
1043 | USBNETHIST_CALLARGSN(11, "%jd: enter %#jx data %#jx", | 1038 | USBNETHIST_CALLARGSN(11, "%jd: enter %#jx data %#jx", | |
1044 | unp->unp_number, cmd, (uintptr_t)data, 0); | 1039 | unp->unp_number, cmd, (uintptr_t)data, 0); | |
1045 | 1040 | |||
1046 | if (un->un_ops->uno_override_ioctl) | 1041 | if (un->un_ops->uno_override_ioctl) | |
1047 | return uno_override_ioctl(un, ifp, cmd, data); | 1042 | return uno_override_ioctl(un, ifp, cmd, data); | |
1048 | 1043 | |||
1049 | error = ether_ioctl(ifp, cmd, data); | 1044 | error = ether_ioctl(ifp, cmd, data); | |
1050 | if (error == ENETRESET) { | 1045 | if (error == ENETRESET) { | |
1051 | switch (cmd) { | 1046 | switch (cmd) { | |
1052 | case SIOCADDMULTI: | 1047 | case SIOCADDMULTI: | |
1053 | case SIOCDELMULTI: | 1048 | case SIOCDELMULTI: | |
1054 | /* | 1049 | /* | |
1055 | * If there's a hardware multicast filter, and | 1050 | * If there's a hardware multicast filter, and | |
1056 | * it has been programmed by usbnet_init_rx_tx | 1051 | * it has been programmed by usbnet_init_rx_tx | |
1057 | * and is active, update it now. Otherwise, | 1052 | * and is active, update it now. Otherwise, | |
1058 | * drop the update on the floor -- it will be | 1053 | * drop the update on the floor -- it will be | |
1059 | * observed by usbnet_init_rx_tx next time we | 1054 | * observed by usbnet_init_rx_tx next time we | |
1060 | * bring the interface up. | 1055 | * bring the interface up. | |
1061 | */ | 1056 | */ | |
1062 | if (un->un_ops->uno_mcast) { | 1057 | if (un->un_ops->uno_mcast) { | |
1063 | mutex_enter(&unp->unp_mcastlock); | 1058 | mutex_enter(&unp->unp_mcastlock); | |
1064 | if (unp->unp_mcastactive) | 1059 | if (unp->unp_mcastactive) | |
1065 | (*un->un_ops->uno_mcast)(ifp); | 1060 | (*un->un_ops->uno_mcast)(ifp); | |
1066 | mutex_exit(&unp->unp_mcastlock); | 1061 | mutex_exit(&unp->unp_mcastlock); | |
1067 | } | 1062 | } | |
1068 | error = 0; | 1063 | error = 0; | |
1069 | break; | 1064 | break; | |
1070 | default: | 1065 | default: | |
1071 | error = uno_ioctl(un, ifp, cmd, data); | 1066 | error = uno_ioctl(un, ifp, cmd, data); | |
1072 | } | 1067 | } | |
1073 | } | 1068 | } | |
1074 | 1069 | |||
1075 | return error; | 1070 | return error; | |
1076 | } | 1071 | } | |
1077 | 1072 | |||
1078 | /* | 1073 | /* | |
1079 | * Generic stop network function: | 1074 | * Generic stop network function: | |
1080 | * - mark as stopping | 1075 | * - mark as stopping | |
1081 | * - call DD routine to stop the device | 1076 | * - call DD routine to stop the device | |
1082 | * - turn off running, timer, statchg callout, link | 1077 | * - turn off running, timer, statchg callout, link | |
1083 | * - stop transfers | 1078 | * - stop transfers | |
1084 | * - free RX and TX resources | 1079 | * - free RX and TX resources | |
1085 | * - close pipes | 1080 | * - close pipes | |
1086 | * | 1081 | * | |
1087 | * usbnet_if_stop() is for the if_stop handler. | 1082 | * usbnet_if_stop() is for the if_stop handler. | |
1088 | */ | 1083 | */ | |
1089 | static void | 1084 | static void | |
1090 | usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable) | 1085 | usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable) | |
1091 | { | 1086 | { | |
1092 | struct usbnet_private * const unp = un->un_pri; | 1087 | struct usbnet_private * const unp = un->un_pri; | |
1093 | 1088 | |||
1094 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 1089 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
1095 | 1090 | |||
1096 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), | 1091 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), | |
1097 | "%s", ifp->if_xname); | 1092 | "%s", ifp->if_xname); | |
1098 | usbnet_isowned_core(un); | 1093 | usbnet_isowned_core(un); | |
1099 | 1094 | |||
1100 | /* | 1095 | /* | |
1101 | * For drivers with hardware multicast filter update callbacks: | 1096 | * For drivers with hardware multicast filter update callbacks: | |
1102 | * Prevent concurrent access to the hardware registers by | 1097 | * Prevent concurrent access to the hardware registers by | |
1103 | * multicast filter updates, which happens without IFNET_LOCK | 1098 | * multicast filter updates, which happens without IFNET_LOCK | |
1104 | * or the usbnet core lock. | 1099 | * or the usbnet core lock. | |
1105 | */ | 1100 | */ | |
1106 | if (un->un_ops->uno_mcast) { | 1101 | if (un->un_ops->uno_mcast) { | |
1107 | mutex_enter(&unp->unp_mcastlock); | 1102 | mutex_enter(&unp->unp_mcastlock); | |
1108 | unp->unp_mcastactive = false; | 1103 | unp->unp_mcastactive = false; | |
1109 | mutex_exit(&unp->unp_mcastlock); | 1104 | mutex_exit(&unp->unp_mcastlock); | |
1110 | } | 1105 | } | |
1111 | 1106 | |||
1112 | /* | 1107 | /* | |
1113 | * Prevent new activity (rescheduling ticks, xfers, &c.) and | 1108 | * Prevent new activity (rescheduling ticks, xfers, &c.) and | |
1114 | * clear the watchdog timer. | 1109 | * clear the watchdog timer. | |
1115 | */ | 1110 | */ | |
1116 | mutex_enter(&unp->unp_rxlock); | 1111 | mutex_enter(&unp->unp_rxlock); | |
1117 | mutex_enter(&unp->unp_txlock); | 1112 | mutex_enter(&unp->unp_txlock); | |
1118 | unp->unp_stopping = true; | 1113 | unp->unp_stopping = true; | |
1119 | unp->unp_timer = 0; | 1114 | unp->unp_timer = 0; | |
1120 | mutex_exit(&unp->unp_txlock); | 1115 | mutex_exit(&unp->unp_txlock); | |
1121 | mutex_exit(&unp->unp_rxlock); | 1116 | mutex_exit(&unp->unp_rxlock); | |
1122 | 1117 | |||
1123 | /* | 1118 | /* | |
1124 | * Stop the timer first, then the task -- if the timer was | 1119 | * Stop the timer first, then the task -- if the timer was | |
1125 | * already firing, we stop the task or wait for it complete | 1120 | * already firing, we stop the task or wait for it complete | |
1126 | * only after if last fired. Setting unp_stopping prevents the | 1121 | * only after if last fired. Setting unp_stopping prevents the | |
1127 | * timer task from being scheduled again. | 1122 | * timer task from being scheduled again. | |
1128 | */ | 1123 | */ | |
1129 | callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock); | 1124 | callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock); | |
1130 | usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, | 1125 | usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, | |
1131 | &unp->unp_core_lock); | 1126 | &unp->unp_core_lock); | |
1132 | 1127 | |||
1133 | /* Stop transfers. */ | 1128 | /* Stop transfers. */ | |
1134 | usbnet_ep_stop_pipes(un); | 1129 | usbnet_ep_stop_pipes(un); | |
1135 | 1130 | |||
1136 | /* | 1131 | /* | |
1137 | * Now that the software is quiescent, ask the driver to stop | 1132 | * Now that the software is quiescent, ask the driver to stop | |
1138 | * the hardware. The driver's uno_stop routine now has | 1133 | * the hardware. The driver's uno_stop routine now has | |
1139 | * exclusive access to any registers that might previously have | 1134 | * exclusive access to any registers that might previously have | |
1140 | * been used by to ifmedia, mii, or ioctl callbacks. | 1135 | * been used by to ifmedia, mii, or ioctl callbacks. | |
1141 | * | 1136 | * | |
1142 | * Don't bother if the device is being detached, though -- if | 1137 | * Don't bother if the device is being detached, though -- if | |
1143 | * it's been unplugged then there's no point in trying to touch | 1138 | * it's been unplugged then there's no point in trying to touch | |
1144 | * the registers. | 1139 | * the registers. | |
1145 | */ | 1140 | */ | |
1146 | if (!usbnet_isdying(un)) | 1141 | if (!usbnet_isdying(un)) | |
1147 | uno_stop(un, ifp, disable); | 1142 | uno_stop(un, ifp, disable); | |
1148 | 1143 | |||
1149 | /* Free RX/TX resources. */ | 1144 | /* Free RX/TX resources. */ | |
1150 | usbnet_rx_list_fini(un); | 1145 | usbnet_rx_list_fini(un); | |
1151 | usbnet_tx_list_fini(un); | 1146 | usbnet_tx_list_fini(un); | |
1152 | 1147 | |||
1153 | /* Close pipes. */ | 1148 | /* Close pipes. */ | |
1154 | usbnet_ep_close_pipes(un); | 1149 | usbnet_ep_close_pipes(un); | |
1155 | 1150 | |||
1156 | /* Everything is quesced now. */ | 1151 | /* Everything is quesced now. */ | |
1157 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), | 1152 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), | |
1158 | "%s", ifp->if_xname); | 1153 | "%s", ifp->if_xname); | |
1159 | ifp->if_flags &= ~IFF_RUNNING; | 1154 | ifp->if_flags &= ~IFF_RUNNING; | |
1160 | } | 1155 | } | |
1161 | 1156 | |||
1162 | static void | 1157 | static void | |
1163 | usbnet_if_stop(struct ifnet *ifp, int disable) | 1158 | usbnet_if_stop(struct ifnet *ifp, int disable) | |
1164 | { | 1159 | { | |
1165 | struct usbnet * const un = ifp->if_softc; | 1160 | struct usbnet * const un = ifp->if_softc; | |
1166 | struct usbnet_private * const unp = un->un_pri; | 1161 | struct usbnet_private * const unp = un->un_pri; | |
1167 | 1162 | |||
1168 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | 1163 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | |
1169 | 1164 | |||
1170 | /* | 1165 | /* | |
1171 | * If we're already stopped, nothing to do. | 1166 | * If we're already stopped, nothing to do. | |
1172 | * | 1167 | * | |
1173 | * XXX This should be an assertion, but it may require some | 1168 | * XXX This should be an assertion, but it may require some | |
1174 | * analysis -- and possibly some tweaking -- of sys/net to | 1169 | * analysis -- and possibly some tweaking -- of sys/net to | |
1175 | * ensure. | 1170 | * ensure. | |
1176 | */ | 1171 | */ | |
1177 | if ((ifp->if_flags & IFF_RUNNING) == 0) | 1172 | if ((ifp->if_flags & IFF_RUNNING) == 0) | |
1178 | return; | 1173 | return; | |
1179 | 1174 | |||
1180 | mutex_enter(&unp->unp_core_lock); | 1175 | mutex_enter(&unp->unp_core_lock); | |
1181 | usbnet_stop(un, ifp, disable); | 1176 | usbnet_stop(un, ifp, disable); | |
1182 | mutex_exit(&unp->unp_core_lock); | 1177 | mutex_exit(&unp->unp_core_lock); | |
1183 | } | 1178 | } | |
1184 | 1179 | |||
1185 | /* | 1180 | /* | |
1186 | * Generic tick task function. | 1181 | * Generic tick task function. | |
1187 | * | 1182 | * | |
1188 | * usbnet_tick() is triggered from a callout, and triggers a call to | 1183 | * usbnet_tick() is triggered from a callout, and triggers a call to | |
1189 | * usbnet_tick_task() from the usb_task subsystem. | 1184 | * usbnet_tick_task() from the usb_task subsystem. | |
1190 | */ | 1185 | */ | |
1191 | static void | 1186 | static void | |
1192 | usbnet_tick(void *arg) | 1187 | usbnet_tick(void *arg) | |
1193 | { | 1188 | { | |
1194 | USBNETHIST_FUNC(); | 1189 | USBNETHIST_FUNC(); | |
1195 | struct usbnet * const un = arg; | 1190 | struct usbnet * const un = arg; | |
1196 | struct usbnet_private * const unp = un->un_pri; | 1191 | struct usbnet_private * const unp = un->un_pri; | |
1197 | 1192 | |||
1198 | USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0); | 1193 | USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0); | |
1199 | 1194 | |||
1200 | /* Perform periodic stuff in process context */ | 1195 | /* Perform periodic stuff in process context */ | |
1201 | usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER); | 1196 | usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER); | |
1202 | } | 1197 | } | |
1203 | 1198 | |||
1204 | static void | 1199 | static void | |
1205 | usbnet_watchdog(struct ifnet *ifp) | 1200 | usbnet_watchdog(struct ifnet *ifp) | |
1206 | { | 1201 | { | |
1207 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 1202 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
1208 | struct usbnet * const un = ifp->if_softc; | 1203 | struct usbnet * const un = ifp->if_softc; | |
1209 | struct usbnet_private * const unp = un->un_pri; | 1204 | struct usbnet_private * const unp = un->un_pri; | |
1210 | struct usbnet_cdata * const cd = un_cdata(un); | 1205 | struct usbnet_cdata * const cd = un_cdata(un); | |
1211 | usbd_status err; | |||
1212 | 1206 | |||
1213 | if_statinc(ifp, if_oerrors); | 1207 | if_statinc(ifp, if_oerrors); | |
1214 | device_printf(un->un_dev, "watchdog timeout\n"); | 1208 | device_printf(un->un_dev, "watchdog timeout\n"); | |
1215 | 1209 | |||
1216 | if (cd->uncd_tx_cnt > 0) { | 1210 | if (cd->uncd_tx_cnt > 0) { | |
1217 | DPRINTF("uncd_tx_cnt=%ju non zero, aborting pipe", 0, 0, 0, 0); | 1211 | DPRINTF("uncd_tx_cnt=%ju non zero, aborting pipe", 0, 0, 0, 0); | |
1218 | err = usbd_abort_pipe(unp->unp_ep[USBNET_ENDPT_TX]); | 1212 | usbd_abort_pipe(unp->unp_ep[USBNET_ENDPT_TX]); | |
1219 | if (err) | |||
1220 | device_printf(un->un_dev, "pipe abort failed: %s\n", | |||
1221 | usbd_errstr(err)); | |||
1222 | if (cd->uncd_tx_cnt != 0) | 1213 | if (cd->uncd_tx_cnt != 0) | |
1223 | DPRINTF("uncd_tx_cnt now %ju", cd->uncd_tx_cnt, 0, 0, 0); | 1214 | DPRINTF("uncd_tx_cnt now %ju", cd->uncd_tx_cnt, 0, 0, 0); | |
1224 | } | 1215 | } | |
1225 | 1216 | |||
1226 | if (!IFQ_IS_EMPTY(&ifp->if_snd)) | 1217 | if (!IFQ_IS_EMPTY(&ifp->if_snd)) | |
1227 | (*ifp->if_start)(ifp); | 1218 | (*ifp->if_start)(ifp); | |
1228 | } | 1219 | } | |
1229 | 1220 | |||
1230 | static void | 1221 | static void | |
1231 | usbnet_tick_task(void *arg) | 1222 | usbnet_tick_task(void *arg) | |
1232 | { | 1223 | { | |
1233 | USBNETHIST_FUNC(); | 1224 | USBNETHIST_FUNC(); | |
1234 | struct usbnet * const un = arg; | 1225 | struct usbnet * const un = arg; | |
1235 | struct usbnet_private * const unp = un->un_pri; | 1226 | struct usbnet_private * const unp = un->un_pri; | |
1236 | struct ifnet * const ifp = usbnet_ifp(un); | 1227 | struct ifnet * const ifp = usbnet_ifp(un); | |
1237 | struct mii_data * const mii = usbnet_mii(un); | 1228 | struct mii_data * const mii = usbnet_mii(un); | |
1238 | 1229 | |||
1239 | USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0); | 1230 | USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0); | |
1240 | 1231 | |||
1241 | mutex_enter(&unp->unp_txlock); | 1232 | mutex_enter(&unp->unp_txlock); | |
1242 | const bool timeout = unp->unp_timer != 0 && --unp->unp_timer == 0; | 1233 | const bool timeout = unp->unp_timer != 0 && --unp->unp_timer == 0; | |
1243 | mutex_exit(&unp->unp_txlock); | 1234 | mutex_exit(&unp->unp_txlock); | |
1244 | if (timeout) | 1235 | if (timeout) | |
1245 | usbnet_watchdog(ifp); | 1236 | usbnet_watchdog(ifp); | |
1246 | 1237 | |||
1247 | DPRINTFN(8, "mii %#jx ifp %#jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0); | 1238 | DPRINTFN(8, "mii %#jx ifp %#jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0); | |
1248 | if (mii) { | 1239 | if (mii) { | |
1249 | mutex_enter(&unp->unp_core_lock); | 1240 | mutex_enter(&unp->unp_core_lock); | |
1250 | mii_tick(mii); | 1241 | mii_tick(mii); | |
1251 | if (!unp->unp_link) | 1242 | if (!unp->unp_link) | |
1252 | (*mii->mii_statchg)(ifp); | 1243 | (*mii->mii_statchg)(ifp); | |
1253 | mutex_exit(&unp->unp_core_lock); | 1244 | mutex_exit(&unp->unp_core_lock); | |
1254 | } | 1245 | } | |
1255 | 1246 | |||
1256 | /* Call driver if requested. */ | 1247 | /* Call driver if requested. */ | |
1257 | uno_tick(un); | 1248 | uno_tick(un); | |
1258 | 1249 | |||
1259 | mutex_enter(&unp->unp_core_lock); | 1250 | mutex_enter(&unp->unp_core_lock); | |
1260 | if (!unp->unp_stopping && !usbnet_isdying(un)) | 1251 | if (!unp->unp_stopping && !usbnet_isdying(un)) | |
1261 | callout_schedule(&unp->unp_stat_ch, hz); | 1252 | callout_schedule(&unp->unp_stat_ch, hz); | |
1262 | mutex_exit(&unp->unp_core_lock); | 1253 | mutex_exit(&unp->unp_core_lock); | |
1263 | } | 1254 | } | |
1264 | 1255 | |||
1265 | static int | 1256 | static int | |
1266 | usbnet_if_init(struct ifnet *ifp) | 1257 | usbnet_if_init(struct ifnet *ifp) | |
1267 | { | 1258 | { | |
1268 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 1259 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
1269 | struct usbnet * const un = ifp->if_softc; | 1260 | struct usbnet * const un = ifp->if_softc; | |
1270 | int error; | 1261 | int error; | |
1271 | 1262 | |||
1272 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | 1263 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | |
1273 | 1264 | |||
1274 | /* | 1265 | /* | |
1275 | * Prevent anyone from bringing the interface back up once | 1266 | * Prevent anyone from bringing the interface back up once | |
1276 | * we're detaching. | 1267 | * we're detaching. | |
1277 | */ | 1268 | */ | |
1278 | if (usbnet_isdying(un)) | 1269 | if (usbnet_isdying(un)) | |
1279 | return EIO; | 1270 | return EIO; | |
1280 | 1271 | |||
1281 | /* | 1272 | /* | |
1282 | * If we're already running, nothing to do. | 1273 | * If we're already running, nothing to do. | |
1283 | * | 1274 | * | |
1284 | * XXX This should be an assertion, but it may require some | 1275 | * XXX This should be an assertion, but it may require some | |
1285 | * analysis -- and possibly some tweaking -- of sys/net to | 1276 | * analysis -- and possibly some tweaking -- of sys/net to | |
1286 | * ensure. | 1277 | * ensure. | |
1287 | */ | 1278 | */ | |
1288 | if (ifp->if_flags & IFF_RUNNING) | 1279 | if (ifp->if_flags & IFF_RUNNING) | |
1289 | return 0; | 1280 | return 0; | |
1290 | 1281 | |||
1291 | mutex_enter(&un->un_pri->unp_core_lock); | 1282 | mutex_enter(&un->un_pri->unp_core_lock); | |
1292 | error = uno_init(un, ifp); | 1283 | error = uno_init(un, ifp); | |
1293 | if (error) | 1284 | if (error) | |
1294 | goto out; | 1285 | goto out; | |
1295 | error = usbnet_init_rx_tx(un); | 1286 | error = usbnet_init_rx_tx(un); | |
1296 | if (error) | 1287 | if (error) | |
1297 | goto out; | 1288 | goto out; | |
1298 | out: mutex_exit(&un->un_pri->unp_core_lock); | 1289 | out: mutex_exit(&un->un_pri->unp_core_lock); | |
1299 | 1290 | |||
1300 | return error; | 1291 | return error; | |
1301 | } | 1292 | } | |
1302 | 1293 | |||
1303 | 1294 | |||
1304 | /* Various accessors. */ | 1295 | /* Various accessors. */ | |
1305 | 1296 | |||
1306 | void | 1297 | void | |
1307 | usbnet_set_link(struct usbnet *un, bool link) | 1298 | usbnet_set_link(struct usbnet *un, bool link) | |
1308 | { | 1299 | { | |
1309 | un->un_pri->unp_link = link; | 1300 | un->un_pri->unp_link = link; | |
1310 | } | 1301 | } | |
1311 | 1302 | |||
1312 | struct ifnet * | 1303 | struct ifnet * | |
1313 | usbnet_ifp(struct usbnet *un) | 1304 | usbnet_ifp(struct usbnet *un) | |
1314 | { | 1305 | { | |
1315 | return &un->un_pri->unp_ec.ec_if; | 1306 | return &un->un_pri->unp_ec.ec_if; | |
1316 | } | 1307 | } | |
1317 | 1308 | |||
1318 | struct ethercom * | 1309 | struct ethercom * | |
1319 | usbnet_ec(struct usbnet *un) | 1310 | usbnet_ec(struct usbnet *un) | |
1320 | { | 1311 | { | |
1321 | return &un->un_pri->unp_ec; | 1312 | return &un->un_pri->unp_ec; | |
1322 | } | 1313 | } | |
1323 | 1314 | |||
1324 | struct mii_data * | 1315 | struct mii_data * | |
1325 | usbnet_mii(struct usbnet *un) | 1316 | usbnet_mii(struct usbnet *un) | |
1326 | { | 1317 | { | |
1327 | return un->un_pri->unp_ec.ec_mii; | 1318 | return un->un_pri->unp_ec.ec_mii; | |
1328 | } | 1319 | } | |
1329 | 1320 | |||
1330 | krndsource_t * | 1321 | krndsource_t * | |
1331 | usbnet_rndsrc(struct usbnet *un) | 1322 | usbnet_rndsrc(struct usbnet *un) | |
1332 | { | 1323 | { | |
1333 | return &un->un_pri->unp_rndsrc; | 1324 | return &un->un_pri->unp_rndsrc; | |
1334 | } | 1325 | } | |
1335 | 1326 | |||
1336 | void * | 1327 | void * | |
1337 | usbnet_softc(struct usbnet *un) | 1328 | usbnet_softc(struct usbnet *un) | |
1338 | { | 1329 | { | |
1339 | return un->un_sc; | 1330 | return un->un_sc; | |
1340 | } | 1331 | } | |
1341 | 1332 | |||
1342 | bool | 1333 | bool | |
1343 | usbnet_havelink(struct usbnet *un) | 1334 | usbnet_havelink(struct usbnet *un) | |
1344 | { | 1335 | { | |
1345 | return un->un_pri->unp_link; | 1336 | return un->un_pri->unp_link; | |
1346 | } | 1337 | } | |
1347 | 1338 | |||
1348 | bool | 1339 | bool | |
1349 | usbnet_isdying(struct usbnet *un) | 1340 | usbnet_isdying(struct usbnet *un) | |
1350 | { | 1341 | { | |
1351 | return atomic_load_relaxed(&un->un_pri->unp_dying); | 1342 | return atomic_load_relaxed(&un->un_pri->unp_dying); | |
1352 | } | 1343 | } | |
1353 | 1344 | |||
1354 | 1345 | |||
1355 | /* Locking. */ | 1346 | /* Locking. */ | |
1356 | 1347 | |||
1357 | static void | 1348 | static void | |
1358 | usbnet_isowned_rx(struct usbnet *un) | 1349 | usbnet_isowned_rx(struct usbnet *un) | |
1359 | { | 1350 | { | |
1360 | KASSERT(mutex_owned(&un->un_pri->unp_rxlock)); | 1351 | KASSERT(mutex_owned(&un->un_pri->unp_rxlock)); | |
1361 | } | 1352 | } | |
1362 | 1353 | |||
1363 | static void | 1354 | static void | |
1364 | usbnet_isowned_tx(struct usbnet *un) | 1355 | usbnet_isowned_tx(struct usbnet *un) | |
1365 | { | 1356 | { | |
1366 | KASSERT(mutex_owned(&un->un_pri->unp_txlock)); | 1357 | KASSERT(mutex_owned(&un->un_pri->unp_txlock)); | |
1367 | } | 1358 | } | |
1368 | 1359 | |||
1369 | /* Autoconf management. */ | 1360 | /* Autoconf management. */ | |
1370 | 1361 | |||
1371 | static bool | 1362 | static bool | |
1372 | usbnet_empty_eaddr(struct usbnet * const un) | 1363 | usbnet_empty_eaddr(struct usbnet * const un) | |
1373 | { | 1364 | { | |
1374 | return (un->un_eaddr[0] == 0 && un->un_eaddr[1] == 0 && | 1365 | return (un->un_eaddr[0] == 0 && un->un_eaddr[1] == 0 && | |
1375 | un->un_eaddr[2] == 0 && un->un_eaddr[3] == 0 && | 1366 | un->un_eaddr[2] == 0 && un->un_eaddr[3] == 0 && | |
1376 | un->un_eaddr[4] == 0 && un->un_eaddr[5] == 0); | 1367 | un->un_eaddr[4] == 0 && un->un_eaddr[5] == 0); | |
1377 | } | 1368 | } | |
1378 | 1369 | |||
1379 | /* | 1370 | /* | |
1380 | * usbnet_attach() and usbnet_attach_ifp() perform setup of the relevant | 1371 | * usbnet_attach() and usbnet_attach_ifp() perform setup of the relevant | |
1381 | * 'usbnet'. The first is enough to enable device access (eg, endpoints | 1372 | * 'usbnet'. The first is enough to enable device access (eg, endpoints | |
1382 | * are connected and commands can be sent), and the second connects the | 1373 | * are connected and commands can be sent), and the second connects the | |
1383 | * device to the system networking. | 1374 | * device to the system networking. | |
1384 | * | 1375 | * | |
1385 | * Always call usbnet_detach(), even if usbnet_attach_ifp() is skippped. | 1376 | * Always call usbnet_detach(), even if usbnet_attach_ifp() is skippped. | |
1386 | * Also usable as driver detach directly. | 1377 | * Also usable as driver detach directly. | |
1387 | * | 1378 | * | |
1388 | * To skip ethernet configuration (eg, point-to-point), make sure that | 1379 | * To skip ethernet configuration (eg, point-to-point), make sure that | |
1389 | * the un_eaddr[] is fully zero. | 1380 | * the un_eaddr[] is fully zero. | |
1390 | */ | 1381 | */ | |
1391 | 1382 | |||
1392 | void | 1383 | void | |
1393 | usbnet_attach(struct usbnet *un) | 1384 | usbnet_attach(struct usbnet *un) | |
1394 | { | 1385 | { | |
1395 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 1386 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
1396 | 1387 | |||
1397 | /* Required inputs. */ | 1388 | /* Required inputs. */ | |
1398 | KASSERT(un->un_ops->uno_tx_prepare); | 1389 | KASSERT(un->un_ops->uno_tx_prepare); | |
1399 | KASSERT(un->un_ops->uno_rx_loop); | 1390 | KASSERT(un->un_ops->uno_rx_loop); | |
1400 | KASSERT(un->un_ops->uno_init); | 1391 | KASSERT(un->un_ops->uno_init); | |
1401 | KASSERT(un->un_rx_bufsz); | 1392 | KASSERT(un->un_rx_bufsz); | |
1402 | KASSERT(un->un_tx_bufsz); | 1393 | KASSERT(un->un_tx_bufsz); | |
1403 | KASSERT(un->un_rx_list_cnt); | 1394 | KASSERT(un->un_rx_list_cnt); | |
1404 | KASSERT(un->un_tx_list_cnt); | 1395 | KASSERT(un->un_tx_list_cnt); | |
1405 | 1396 | |||
1406 | /* Unfortunate fact. */ | 1397 | /* Unfortunate fact. */ | |
1407 | KASSERT(un == device_private(un->un_dev)); | 1398 | KASSERT(un == device_private(un->un_dev)); | |
1408 | 1399 | |||
1409 | un->un_pri = kmem_zalloc(sizeof(*un->un_pri), KM_SLEEP); | 1400 | un->un_pri = kmem_zalloc(sizeof(*un->un_pri), KM_SLEEP); | |
1410 | struct usbnet_private * const unp = un->un_pri; | 1401 | struct usbnet_private * const unp = un->un_pri; | |
1411 | 1402 | |||
1412 | usb_init_task(&unp->unp_ticktask, usbnet_tick_task, un, | 1403 | usb_init_task(&unp->unp_ticktask, usbnet_tick_task, un, | |
1413 | USB_TASKQ_MPSAFE); | 1404 | USB_TASKQ_MPSAFE); | |
1414 | callout_init(&unp->unp_stat_ch, CALLOUT_MPSAFE); | 1405 | callout_init(&unp->unp_stat_ch, CALLOUT_MPSAFE); | |
1415 | callout_setfunc(&unp->unp_stat_ch, usbnet_tick, un); | 1406 | callout_setfunc(&unp->unp_stat_ch, usbnet_tick, un); | |
1416 | 1407 | |||
1417 | mutex_init(&unp->unp_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); | 1408 | mutex_init(&unp->unp_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); | |
1418 | mutex_init(&unp->unp_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); | 1409 | mutex_init(&unp->unp_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); | |
1419 | mutex_init(&unp->unp_core_lock, MUTEX_DEFAULT, IPL_NONE); | 1410 | mutex_init(&unp->unp_core_lock, MUTEX_DEFAULT, IPL_NONE); | |
1420 | mutex_init(&unp->unp_mcastlock, MUTEX_DEFAULT, IPL_SOFTCLOCK); | 1411 | mutex_init(&unp->unp_mcastlock, MUTEX_DEFAULT, IPL_SOFTCLOCK); | |
1421 | 1412 | |||
1422 | rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev), | 1413 | rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev), | |
1423 | RND_TYPE_NET, RND_FLAG_DEFAULT); | 1414 | RND_TYPE_NET, RND_FLAG_DEFAULT); | |
1424 | 1415 | |||
1425 | usbnet_rx_list_alloc(un); | 1416 | usbnet_rx_list_alloc(un); | |
1426 | usbnet_tx_list_alloc(un); | 1417 | usbnet_tx_list_alloc(un); | |
1427 | 1418 | |||
1428 | unp->unp_number = atomic_inc_uint_nv(&usbnet_number); | 1419 | unp->unp_number = atomic_inc_uint_nv(&usbnet_number); | |
1429 | 1420 | |||
1430 | unp->unp_attached = true; | 1421 | unp->unp_attached = true; | |
1431 | } | 1422 | } | |
1432 | 1423 | |||
1433 | static void | 1424 | static void | |
1434 | usbnet_attach_mii(struct usbnet *un, const struct usbnet_mii *unm) | 1425 | usbnet_attach_mii(struct usbnet *un, const struct usbnet_mii *unm) | |
1435 | { | 1426 | { | |
1436 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 1427 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
1437 | struct usbnet_private * const unp = un->un_pri; | 1428 | struct usbnet_private * const unp = un->un_pri; | |
1438 | struct mii_data * const mii = &unp->unp_mii; | 1429 | struct mii_data * const mii = &unp->unp_mii; | |
1439 | struct ifnet * const ifp = usbnet_ifp(un); | 1430 | struct ifnet * const ifp = usbnet_ifp(un); | |
1440 | 1431 | |||
1441 | KASSERT(un->un_ops->uno_read_reg); | 1432 | KASSERT(un->un_ops->uno_read_reg); | |
1442 | KASSERT(un->un_ops->uno_write_reg); | 1433 | KASSERT(un->un_ops->uno_write_reg); | |
1443 | KASSERT(un->un_ops->uno_statchg); | 1434 | KASSERT(un->un_ops->uno_statchg); | |
1444 | 1435 | |||
1445 | mii->mii_ifp = ifp; | 1436 | mii->mii_ifp = ifp; | |
1446 | mii->mii_readreg = usbnet_mii_readreg; | 1437 | mii->mii_readreg = usbnet_mii_readreg; | |
1447 | mii->mii_writereg = usbnet_mii_writereg; | 1438 | mii->mii_writereg = usbnet_mii_writereg; | |
1448 | mii->mii_statchg = usbnet_mii_statchg; | 1439 | mii->mii_statchg = usbnet_mii_statchg; | |
1449 | mii->mii_flags = MIIF_AUTOTSLEEP; | 1440 | mii->mii_flags = MIIF_AUTOTSLEEP; | |
1450 | 1441 | |||
1451 | usbnet_ec(un)->ec_mii = mii; | 1442 | usbnet_ec(un)->ec_mii = mii; | |
1452 | ifmedia_init_with_lock(&mii->mii_media, 0, | 1443 | ifmedia_init_with_lock(&mii->mii_media, 0, | |
1453 | usbnet_media_upd, ether_mediastatus, usbnet_mutex_core(un)); | 1444 | usbnet_media_upd, ether_mediastatus, usbnet_mutex_core(un)); | |
1454 | mii_attach(un->un_dev, mii, unm->un_mii_capmask, unm->un_mii_phyloc, | 1445 | mii_attach(un->un_dev, mii, unm->un_mii_capmask, unm->un_mii_phyloc, | |
1455 | unm->un_mii_offset, unm->un_mii_flags); | 1446 | unm->un_mii_offset, unm->un_mii_flags); | |
1456 | 1447 | |||
1457 | if (LIST_FIRST(&mii->mii_phys) == NULL) { | 1448 | if (LIST_FIRST(&mii->mii_phys) == NULL) { | |
1458 | ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL); | 1449 | ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL); | |
1459 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); | 1450 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); | |
1460 | } else | 1451 | } else | |
1461 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); | 1452 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); | |
1462 | } | 1453 | } | |
1463 | 1454 | |||
1464 | void | 1455 | void | |
1465 | usbnet_attach_ifp(struct usbnet *un, | 1456 | usbnet_attach_ifp(struct usbnet *un, | |
1466 | unsigned if_flags, /* additional if_flags */ | 1457 | unsigned if_flags, /* additional if_flags */ | |
1467 | unsigned if_extflags, /* additional if_extflags */ | 1458 | unsigned if_extflags, /* additional if_extflags */ | |
1468 | const struct usbnet_mii *unm) /* additional mii_attach flags */ | 1459 | const struct usbnet_mii *unm) /* additional mii_attach flags */ | |
1469 | { | 1460 | { | |
1470 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 1461 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
1471 | struct usbnet_private * const unp = un->un_pri; | 1462 | struct usbnet_private * const unp = un->un_pri; | |
1472 | struct ifnet * const ifp = usbnet_ifp(un); | 1463 | struct ifnet * const ifp = usbnet_ifp(un); | |
1473 | 1464 | |||
1474 | KASSERT(unp->unp_attached); | 1465 | KASSERT(unp->unp_attached); | |
1475 | KASSERT(!unp->unp_ifp_attached); | 1466 | KASSERT(!unp->unp_ifp_attached); | |
1476 | 1467 | |||
1477 | ifp->if_softc = un; | 1468 | ifp->if_softc = un; | |
1478 | strlcpy(ifp->if_xname, device_xname(un->un_dev), IFNAMSIZ); | 1469 | strlcpy(ifp->if_xname, device_xname(un->un_dev), IFNAMSIZ); | |
1479 | ifp->if_flags = if_flags; | 1470 | ifp->if_flags = if_flags; | |
1480 | ifp->if_extflags = IFEF_MPSAFE | if_extflags; | 1471 | ifp->if_extflags = IFEF_MPSAFE | if_extflags; | |
1481 | ifp->if_ioctl = usbnet_if_ioctl; | 1472 | ifp->if_ioctl = usbnet_if_ioctl; | |
1482 | ifp->if_start = usbnet_if_start; | 1473 | ifp->if_start = usbnet_if_start; | |
1483 | ifp->if_init = usbnet_if_init; | 1474 | ifp->if_init = usbnet_if_init; | |
1484 | ifp->if_stop = usbnet_if_stop; | 1475 | ifp->if_stop = usbnet_if_stop; | |
1485 | 1476 | |||
1486 | if (unm) | 1477 | if (unm) | |
1487 | usbnet_attach_mii(un, unm); | 1478 | usbnet_attach_mii(un, unm); | |
1488 | else | 1479 | else | |
1489 | unp->unp_link = true; | 1480 | unp->unp_link = true; | |
1490 | 1481 | |||
1491 | /* Attach the interface. */ | 1482 | /* Attach the interface. */ | |
1492 | if_initialize(ifp); | 1483 | if_initialize(ifp); | |
1493 | if (ifp->_if_input == NULL) | 1484 | if (ifp->_if_input == NULL) | |
1494 | ifp->if_percpuq = if_percpuq_create(ifp); | 1485 | ifp->if_percpuq = if_percpuq_create(ifp); | |
1495 | if_register(ifp); | 1486 | if_register(ifp); | |
1496 | unp->unp_ifp_attached = true; | 1487 | unp->unp_ifp_attached = true; | |
1497 | 1488 | |||
1498 | /* | 1489 | /* | |
1499 | * If ethernet address is all zero, skip ether_ifattach() and | 1490 | * If ethernet address is all zero, skip ether_ifattach() and | |
1500 | * instead attach bpf here.. | 1491 | * instead attach bpf here.. | |
1501 | */ | 1492 | */ | |
1502 | if (!usbnet_empty_eaddr(un)) { | 1493 | if (!usbnet_empty_eaddr(un)) { | |
1503 | ether_set_ifflags_cb(&unp->unp_ec, usbnet_ifflags_cb); | 1494 | ether_set_ifflags_cb(&unp->unp_ec, usbnet_ifflags_cb); | |
1504 | aprint_normal_dev(un->un_dev, "Ethernet address %s\n", | 1495 | aprint_normal_dev(un->un_dev, "Ethernet address %s\n", | |
1505 | ether_sprintf(un->un_eaddr)); | 1496 | ether_sprintf(un->un_eaddr)); | |
1506 | ether_ifattach(ifp, un->un_eaddr); | 1497 | ether_ifattach(ifp, un->un_eaddr); | |
1507 | } else { | 1498 | } else { | |
1508 | if_alloc_sadl(ifp); | 1499 | if_alloc_sadl(ifp); | |
1509 | bpf_attach(ifp, DLT_RAW, 0); | 1500 | bpf_attach(ifp, DLT_RAW, 0); | |
1510 | } | 1501 | } | |
1511 | 1502 | |||
1512 | /* Now ready, and attached. */ | 1503 | /* Now ready, and attached. */ | |
1513 | IFQ_SET_READY(&ifp->if_snd); | 1504 | IFQ_SET_READY(&ifp->if_snd); | |
1514 | 1505 | |||
1515 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, un->un_udev, un->un_dev); | 1506 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, un->un_udev, un->un_dev); | |
1516 | 1507 | |||
1517 | if (!pmf_device_register(un->un_dev, NULL, NULL)) | 1508 | if (!pmf_device_register(un->un_dev, NULL, NULL)) | |
1518 | aprint_error_dev(un->un_dev, "couldn't establish power handler\n"); | 1509 | aprint_error_dev(un->un_dev, "couldn't establish power handler\n"); | |
1519 | } | 1510 | } | |
1520 | 1511 | |||
1521 | int | 1512 | int | |
1522 | usbnet_detach(device_t self, int flags) | 1513 | usbnet_detach(device_t self, int flags) | |
1523 | { | 1514 | { | |
1524 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 1515 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
1525 | struct usbnet * const un = device_private(self); | 1516 | struct usbnet * const un = device_private(self); | |
1526 | struct usbnet_private * const unp = un->un_pri; | 1517 | struct usbnet_private * const unp = un->un_pri; | |
1527 | 1518 | |||
1528 | /* Detached before attached finished, so just bail out. */ | 1519 | /* Detached before attached finished, so just bail out. */ | |
1529 | if (unp == NULL || !unp->unp_attached) | 1520 | if (unp == NULL || !unp->unp_attached) | |
1530 | return 0; | 1521 | return 0; | |
1531 | 1522 | |||
1532 | struct ifnet * const ifp = usbnet_ifp(un); | 1523 | struct ifnet * const ifp = usbnet_ifp(un); | |
1533 | struct mii_data * const mii = usbnet_mii(un); | 1524 | struct mii_data * const mii = usbnet_mii(un); | |
1534 | 1525 | |||
1535 | /* | 1526 | /* | |
1536 | * Prevent new activity. After we stop the interface, it | 1527 | * Prevent new activity. After we stop the interface, it | |
1537 | * cannot be brought back up. | 1528 | * cannot be brought back up. | |
1538 | */ | 1529 | */ | |
1539 | atomic_store_relaxed(&unp->unp_dying, true); | 1530 | atomic_store_relaxed(&unp->unp_dying, true); | |
1540 | 1531 | |||
1541 | /* | 1532 | /* | |
1542 | * If we're still running on the network, stop and wait for all | 1533 | * If we're still running on the network, stop and wait for all | |
1543 | * asynchronous activity to finish. | 1534 | * asynchronous activity to finish. | |
1544 | * | 1535 | * | |
1545 | * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but | 1536 | * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but | |
1546 | * no activity is possible, so just skip this part. | 1537 | * no activity is possible, so just skip this part. | |
1547 | */ | 1538 | */ | |
1548 | if (unp->unp_ifp_attached) { | 1539 | if (unp->unp_ifp_attached) { | |
1549 | IFNET_LOCK(ifp); | 1540 | IFNET_LOCK(ifp); | |
1550 | if (ifp->if_flags & IFF_RUNNING) { | 1541 | if (ifp->if_flags & IFF_RUNNING) { | |
1551 | usbnet_if_stop(ifp, 1); | 1542 | usbnet_if_stop(ifp, 1); | |
1552 | } | 1543 | } | |
1553 | IFNET_UNLOCK(ifp); | 1544 | IFNET_UNLOCK(ifp); | |
1554 | } | 1545 | } | |
1555 | 1546 | |||
1556 | /* | 1547 | /* | |
1557 | * The callout and tick task can't be scheduled anew at this | 1548 | * The callout and tick task can't be scheduled anew at this | |
1558 | * point, and usbnet_if_stop has waited for them to complete. | 1549 | * point, and usbnet_if_stop has waited for them to complete. | |
1559 | */ | 1550 | */ | |
1560 | KASSERT(!callout_pending(&unp->unp_stat_ch)); | 1551 | KASSERT(!callout_pending(&unp->unp_stat_ch)); | |
1561 | KASSERT(!usb_task_pending(un->un_udev, &unp->unp_ticktask)); | 1552 | KASSERT(!usb_task_pending(un->un_udev, &unp->unp_ticktask)); | |
1562 | 1553 | |||
1563 | if (mii) { | 1554 | if (mii) { | |
1564 | mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY); | 1555 | mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY); | |
1565 | ifmedia_fini(&mii->mii_media); | 1556 | ifmedia_fini(&mii->mii_media); | |
1566 | } | 1557 | } | |
1567 | if (unp->unp_ifp_attached) { | 1558 | if (unp->unp_ifp_attached) { | |
1568 | if (!usbnet_empty_eaddr(un)) | 1559 | if (!usbnet_empty_eaddr(un)) | |
1569 | ether_ifdetach(ifp); | 1560 | ether_ifdetach(ifp); | |
1570 | else | 1561 | else | |
1571 | bpf_detach(ifp); | 1562 | bpf_detach(ifp); | |
1572 | if_detach(ifp); | 1563 | if_detach(ifp); | |
1573 | } | 1564 | } | |
1574 | usbnet_ec(un)->ec_mii = NULL; | 1565 | usbnet_ec(un)->ec_mii = NULL; | |
1575 | 1566 | |||
1576 | usbnet_rx_list_free(un); | 1567 | usbnet_rx_list_free(un); | |
1577 | usbnet_tx_list_free(un); | 1568 | usbnet_tx_list_free(un); | |
1578 | 1569 | |||
1579 | rnd_detach_source(&unp->unp_rndsrc); | 1570 | rnd_detach_source(&unp->unp_rndsrc); | |
1580 | 1571 | |||
1581 | mutex_destroy(&unp->unp_mcastlock); | 1572 | mutex_destroy(&unp->unp_mcastlock); | |
1582 | mutex_destroy(&unp->unp_core_lock); | 1573 | mutex_destroy(&unp->unp_core_lock); | |
1583 | mutex_destroy(&unp->unp_rxlock); | 1574 | mutex_destroy(&unp->unp_rxlock); | |
1584 | mutex_destroy(&unp->unp_txlock); | 1575 | mutex_destroy(&unp->unp_txlock); | |
1585 | 1576 | |||
1586 | callout_destroy(&unp->unp_stat_ch); | 1577 | callout_destroy(&unp->unp_stat_ch); | |
1587 | 1578 | |||
1588 | pmf_device_deregister(un->un_dev); | 1579 | pmf_device_deregister(un->un_dev); | |
1589 | 1580 | |||
1590 | /* | 1581 | /* | |
1591 | * Notify userland that we're going away, if we arrived in the | 1582 | * Notify userland that we're going away, if we arrived in the | |
1592 | * first place. | 1583 | * first place. | |
1593 | */ | 1584 | */ | |
1594 | if (unp->unp_ifp_attached) { | 1585 | if (unp->unp_ifp_attached) { | |
1595 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, | 1586 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, | |
1596 | un->un_dev); | 1587 | un->un_dev); | |
1597 | } | 1588 | } | |
1598 | 1589 | |||
1599 | kmem_free(unp, sizeof(*unp)); | 1590 | kmem_free(unp, sizeof(*unp)); | |
1600 | un->un_pri = NULL; | 1591 | un->un_pri = NULL; | |
1601 | 1592 | |||
1602 | return 0; | 1593 | return 0; | |
1603 | } | 1594 | } | |
1604 | 1595 | |||
1605 | int | 1596 | int | |
1606 | usbnet_activate(device_t self, devact_t act) | 1597 | usbnet_activate(device_t self, devact_t act) | |
1607 | { | 1598 | { | |
1608 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | 1599 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | |
1609 | struct usbnet * const un = device_private(self); | 1600 | struct usbnet * const un = device_private(self); | |
1610 | struct usbnet_private * const unp = un->un_pri; | 1601 | struct usbnet_private * const unp = un->un_pri; | |
1611 | struct ifnet * const ifp = usbnet_ifp(un); | 1602 | struct ifnet * const ifp = usbnet_ifp(un); | |
1612 | 1603 | |||
1613 | switch (act) { | 1604 | switch (act) { | |
1614 | case DVACT_DEACTIVATE: | 1605 | case DVACT_DEACTIVATE: | |
1615 | if_deactivate(ifp); | 1606 | if_deactivate(ifp); | |
1616 | 1607 | |||
1617 | atomic_store_relaxed(&unp->unp_dying, true); | 1608 | atomic_store_relaxed(&unp->unp_dying, true); | |
1618 | 1609 | |||
1619 | mutex_enter(&unp->unp_rxlock); | 1610 | mutex_enter(&unp->unp_rxlock); | |
1620 | mutex_enter(&unp->unp_txlock); | 1611 | mutex_enter(&unp->unp_txlock); | |
1621 | unp->unp_stopping = true; | 1612 | unp->unp_stopping = true; | |
1622 | mutex_exit(&unp->unp_txlock); | 1613 | mutex_exit(&unp->unp_txlock); | |
1623 | mutex_exit(&unp->unp_rxlock); | 1614 | mutex_exit(&unp->unp_rxlock); | |
1624 | 1615 | |||
1625 | return 0; | 1616 | return 0; | |
1626 | default: | 1617 | default: | |
1627 | return EOPNOTSUPP; | 1618 | return EOPNOTSUPP; | |
1628 | } | 1619 | } | |
1629 | } | 1620 | } | |
1630 | 1621 | |||
1631 | MODULE(MODULE_CLASS_MISC, usbnet, NULL); | 1622 | MODULE(MODULE_CLASS_MISC, usbnet, NULL); | |
1632 | 1623 | |||
1633 | static int | 1624 | static int | |
1634 | usbnet_modcmd(modcmd_t cmd, void *arg) | 1625 | usbnet_modcmd(modcmd_t cmd, void *arg) | |
1635 | { | 1626 | { | |
1636 | switch (cmd) { | 1627 | switch (cmd) { | |
1637 | case MODULE_CMD_INIT: | 1628 | case MODULE_CMD_INIT: | |
1638 | return 0; | 1629 | return 0; | |
1639 | case MODULE_CMD_FINI: | 1630 | case MODULE_CMD_FINI: | |
1640 | return 0; | 1631 | return 0; | |
1641 | case MODULE_CMD_STAT: | 1632 | case MODULE_CMD_STAT: | |
1642 | case MODULE_CMD_AUTOUNLOAD: | 1633 | case MODULE_CMD_AUTOUNLOAD: | |
1643 | default: | 1634 | default: | |
1644 | return ENOTTY; | 1635 | return ENOTTY; | |
1645 | } | 1636 | } | |
1646 | } | 1637 | } |
--- src/sys/dev/usb/utoppy.c 2020/03/14 02:35:34 1.35
+++ src/sys/dev/usb/utoppy.c 2022/03/03 06:05:38 1.36
@@ -1,1865 +1,1862 @@ | @@ -1,1865 +1,1862 @@ | |||
1 | /* $NetBSD: utoppy.c,v 1.35 2020/03/14 02:35:34 christos Exp $ */ | 1 | /* $NetBSD: utoppy.c,v 1.36 2022/03/03 06:05:38 riastradh Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2006 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2006 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Steve C. Woodford. | 8 | * by Steve C. Woodford. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | __KERNEL_RCSID(0, "$NetBSD: utoppy.c,v 1.35 2020/03/14 02:35:34 christos Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: utoppy.c,v 1.36 2022/03/03 06:05:38 riastradh Exp $"); | |
34 | 34 | |||
35 | #ifdef _KERNEL_OPT | 35 | #ifdef _KERNEL_OPT | |
36 | #include "opt_usb.h" | 36 | #include "opt_usb.h" | |
37 | #endif | 37 | #endif | |
38 | 38 | |||
39 | #include <sys/param.h> | 39 | #include <sys/param.h> | |
40 | #include <sys/systm.h> | 40 | #include <sys/systm.h> | |
41 | #include <sys/proc.h> | 41 | #include <sys/proc.h> | |
42 | #include <sys/kernel.h> | 42 | #include <sys/kernel.h> | |
43 | #include <sys/fcntl.h> | 43 | #include <sys/fcntl.h> | |
44 | #include <sys/device.h> | 44 | #include <sys/device.h> | |
45 | #include <sys/ioctl.h> | 45 | #include <sys/ioctl.h> | |
46 | #include <sys/uio.h> | 46 | #include <sys/uio.h> | |
47 | #include <sys/conf.h> | 47 | #include <sys/conf.h> | |
48 | #include <sys/vnode.h> | 48 | #include <sys/vnode.h> | |
49 | #include <sys/bus.h> | 49 | #include <sys/bus.h> | |
50 | 50 | |||
51 | #include <lib/libkern/crc16.h> | 51 | #include <lib/libkern/crc16.h> | |
52 | 52 | |||
53 | #include <dev/usb/usb.h> | 53 | #include <dev/usb/usb.h> | |
54 | #include <dev/usb/usbdi.h> | 54 | #include <dev/usb/usbdi.h> | |
55 | #include <dev/usb/usbdivar.h> | 55 | #include <dev/usb/usbdivar.h> | |
56 | #include <dev/usb/usbdi_util.h> | 56 | #include <dev/usb/usbdi_util.h> | |
57 | #include <dev/usb/usbdevs.h> | 57 | #include <dev/usb/usbdevs.h> | |
58 | #include <dev/usb/usb_quirks.h> | 58 | #include <dev/usb/usb_quirks.h> | |
59 | #include <dev/usb/utoppy.h> | 59 | #include <dev/usb/utoppy.h> | |
60 | 60 | |||
61 | #include "ioconf.h" | 61 | #include "ioconf.h" | |
62 | 62 | |||
63 | #undef UTOPPY_DEBUG | 63 | #undef UTOPPY_DEBUG | |
64 | #ifdef UTOPPY_DEBUG | 64 | #ifdef UTOPPY_DEBUG | |
65 | #define UTOPPY_DBG_OPEN 0x0001 | 65 | #define UTOPPY_DBG_OPEN 0x0001 | |
66 | #define UTOPPY_DBG_CLOSE 0x0002 | 66 | #define UTOPPY_DBG_CLOSE 0x0002 | |
67 | #define UTOPPY_DBG_READ 0x0004 | 67 | #define UTOPPY_DBG_READ 0x0004 | |
68 | #define UTOPPY_DBG_WRITE 0x0008 | 68 | #define UTOPPY_DBG_WRITE 0x0008 | |
69 | #define UTOPPY_DBG_IOCTL 0x0010 | 69 | #define UTOPPY_DBG_IOCTL 0x0010 | |
70 | #define UTOPPY_DBG_SEND_PACKET 0x0020 | 70 | #define UTOPPY_DBG_SEND_PACKET 0x0020 | |
71 | #define UTOPPY_DBG_RECV_PACKET 0x0040 | 71 | #define UTOPPY_DBG_RECV_PACKET 0x0040 | |
72 | #define UTOPPY_DBG_ADDPATH 0x0080 | 72 | #define UTOPPY_DBG_ADDPATH 0x0080 | |
73 | #define UTOPPY_DBG_READDIR 0x0100 | 73 | #define UTOPPY_DBG_READDIR 0x0100 | |
74 | #define UTOPPY_DBG_DUMP 0x0200 | 74 | #define UTOPPY_DBG_DUMP 0x0200 | |
75 | #define DPRINTF(l, m) \ | 75 | #define DPRINTF(l, m) \ | |
76 | do { \ | 76 | do { \ | |
77 | if (utoppy_debug & l) \ | 77 | if (utoppy_debug & l) \ | |
78 | printf m; \ | 78 | printf m; \ | |
79 | } while (/*CONSTCOND*/0) | 79 | } while (/*CONSTCOND*/0) | |
80 | static int utoppy_debug = 0; | 80 | static int utoppy_debug = 0; | |
81 | static void utoppy_dump_packet(const void *, size_t); | 81 | static void utoppy_dump_packet(const void *, size_t); | |
82 | #define DDUMP_PACKET(p, l) \ | 82 | #define DDUMP_PACKET(p, l) \ | |
83 | do { \ | 83 | do { \ | |
84 | if (utoppy_debug & UTOPPY_DBG_DUMP) \ | 84 | if (utoppy_debug & UTOPPY_DBG_DUMP) \ | |
85 | utoppy_dump_packet((p), (l)); \ | 85 | utoppy_dump_packet((p), (l)); \ | |
86 | } while (/*CONSTCOND*/0) | 86 | } while (/*CONSTCOND*/0) | |
87 | #else | 87 | #else | |
88 | #define DPRINTF(l, m) /* nothing */ | 88 | #define DPRINTF(l, m) /* nothing */ | |
89 | #define DDUMP_PACKET(p, l) /* nothing */ | 89 | #define DDUMP_PACKET(p, l) /* nothing */ | |
90 | #endif | 90 | #endif | |
91 | 91 | |||
92 | 92 | |||
93 | #define UTOPPY_CONFIG_NO 1 | 93 | #define UTOPPY_CONFIG_NO 1 | |
94 | #define UTOPPY_NUMENDPOINTS 2 | 94 | #define UTOPPY_NUMENDPOINTS 2 | |
95 | 95 | |||
96 | #define UTOPPY_BSIZE 0xffff | 96 | #define UTOPPY_BSIZE 0xffff | |
97 | #define UTOPPY_FRAG_SIZE 0x1000 | 97 | #define UTOPPY_FRAG_SIZE 0x1000 | |
98 | #define UTOPPY_HEADER_SIZE 8 | 98 | #define UTOPPY_HEADER_SIZE 8 | |
99 | #define UTOPPY_SHORT_TIMEOUT (500) /* 0.5 seconds */ | 99 | #define UTOPPY_SHORT_TIMEOUT (500) /* 0.5 seconds */ | |
100 | #define UTOPPY_LONG_TIMEOUT (10 * 1000) /* 10 seconds */ | 100 | #define UTOPPY_LONG_TIMEOUT (10 * 1000) /* 10 seconds */ | |
101 | 101 | |||
102 | /* Protocol Commands and Responses */ | 102 | /* Protocol Commands and Responses */ | |
103 | #define UTOPPY_RESP_ERROR 0x0001 | 103 | #define UTOPPY_RESP_ERROR 0x0001 | |
104 | #define UTOPPY_CMD_ACK 0x0002 | 104 | #define UTOPPY_CMD_ACK 0x0002 | |
105 | #define UTOPPY_RESP_SUCCESS UTOPPY_CMD_ACK | 105 | #define UTOPPY_RESP_SUCCESS UTOPPY_CMD_ACK | |
106 | #define UTOPPY_CMD_CANCEL 0x0003 | 106 | #define UTOPPY_CMD_CANCEL 0x0003 | |
107 | #define UTOPPY_CMD_READY 0x0100 | 107 | #define UTOPPY_CMD_READY 0x0100 | |
108 | #define UTOPPY_CMD_RESET 0x0101 | 108 | #define UTOPPY_CMD_RESET 0x0101 | |
109 | #define UTOPPY_CMD_TURBO 0x0102 | 109 | #define UTOPPY_CMD_TURBO 0x0102 | |
110 | #define UTOPPY_CMD_STATS 0x1000 | 110 | #define UTOPPY_CMD_STATS 0x1000 | |
111 | #define UTOPPY_RESP_STATS_DATA 0x1001 | 111 | #define UTOPPY_RESP_STATS_DATA 0x1001 | |
112 | #define UTOPPY_CMD_READDIR 0x1002 | 112 | #define UTOPPY_CMD_READDIR 0x1002 | |
113 | #define UTOPPY_RESP_READDIR_DATA 0x1003 | 113 | #define UTOPPY_RESP_READDIR_DATA 0x1003 | |
114 | #define UTOPPY_RESP_READDIR_END 0x1004 | 114 | #define UTOPPY_RESP_READDIR_END 0x1004 | |
115 | #define UTOPPY_CMD_DELETE 0x1005 | 115 | #define UTOPPY_CMD_DELETE 0x1005 | |
116 | #define UTOPPY_CMD_RENAME 0x1006 | 116 | #define UTOPPY_CMD_RENAME 0x1006 | |
117 | #define UTOPPY_CMD_MKDIR 0x1007 | 117 | #define UTOPPY_CMD_MKDIR 0x1007 | |
118 | #define UTOPPY_CMD_FILE 0x1008 | 118 | #define UTOPPY_CMD_FILE 0x1008 | |
119 | #define UTOPPY_FILE_WRITE 0 | 119 | #define UTOPPY_FILE_WRITE 0 | |
120 | #define UTOPPY_FILE_READ 1 | 120 | #define UTOPPY_FILE_READ 1 | |
121 | #define UTOPPY_RESP_FILE_HEADER 0x1009 | 121 | #define UTOPPY_RESP_FILE_HEADER 0x1009 | |
122 | #define UTOPPY_RESP_FILE_DATA 0x100a | 122 | #define UTOPPY_RESP_FILE_DATA 0x100a | |
123 | #define UTOPPY_RESP_FILE_END 0x100b | 123 | #define UTOPPY_RESP_FILE_END 0x100b | |
124 | 124 | |||
125 | enum utoppy_state { | 125 | enum utoppy_state { | |
126 | UTOPPY_STATE_CLOSED, | 126 | UTOPPY_STATE_CLOSED, | |
127 | UTOPPY_STATE_OPENING, | 127 | UTOPPY_STATE_OPENING, | |
128 | UTOPPY_STATE_IDLE, | 128 | UTOPPY_STATE_IDLE, | |
129 | UTOPPY_STATE_READDIR, | 129 | UTOPPY_STATE_READDIR, | |
130 | UTOPPY_STATE_READFILE, | 130 | UTOPPY_STATE_READFILE, | |
131 | UTOPPY_STATE_WRITEFILE | 131 | UTOPPY_STATE_WRITEFILE | |
132 | }; | 132 | }; | |
133 | 133 | |||
134 | struct utoppy_softc { | 134 | struct utoppy_softc { | |
135 | device_t sc_dev; | 135 | device_t sc_dev; | |
136 | struct usbd_device *sc_udev; /* device */ | 136 | struct usbd_device *sc_udev; /* device */ | |
137 | struct usbd_interface *sc_iface; /* interface */ | 137 | struct usbd_interface *sc_iface; /* interface */ | |
138 | int sc_dying; | 138 | int sc_dying; | |
139 | int sc_refcnt; | 139 | int sc_refcnt; | |
140 | 140 | |||
141 | enum utoppy_state sc_state; | 141 | enum utoppy_state sc_state; | |
142 | u_int sc_turbo_mode; | 142 | u_int sc_turbo_mode; | |
143 | 143 | |||
144 | int sc_out; | 144 | int sc_out; | |
145 | struct usbd_pipe *sc_out_pipe; /* bulk out pipe */ | 145 | struct usbd_pipe *sc_out_pipe; /* bulk out pipe */ | |
146 | struct usbd_xfer *sc_out_xfer; | 146 | struct usbd_xfer *sc_out_xfer; | |
147 | void *sc_out_buf; | 147 | void *sc_out_buf; | |
148 | void *sc_out_data; | 148 | void *sc_out_data; | |
149 | uint64_t sc_wr_offset; | 149 | uint64_t sc_wr_offset; | |
150 | uint64_t sc_wr_size; | 150 | uint64_t sc_wr_size; | |
151 | 151 | |||
152 | int sc_in; | 152 | int sc_in; | |
153 | struct usbd_pipe *sc_in_pipe; /* bulk in pipe */ | 153 | struct usbd_pipe *sc_in_pipe; /* bulk in pipe */ | |
154 | struct usbd_xfer *sc_in_xfer; | 154 | struct usbd_xfer *sc_in_xfer; | |
155 | void *sc_in_buf; | 155 | void *sc_in_buf; | |
156 | void *sc_in_data; | 156 | void *sc_in_data; | |
157 | size_t sc_in_len; | 157 | size_t sc_in_len; | |
158 | u_int sc_in_offset; | 158 | u_int sc_in_offset; | |
159 | }; | 159 | }; | |
160 | 160 | |||
161 | struct utoppy_header { | 161 | struct utoppy_header { | |
162 | uint16_t h_len; | 162 | uint16_t h_len; | |
163 | uint16_t h_crc; | 163 | uint16_t h_crc; | |
164 | uint16_t h_cmd2; | 164 | uint16_t h_cmd2; | |
165 | uint16_t h_cmd; | 165 | uint16_t h_cmd; | |
166 | uint8_t h_data[0]; | 166 | uint8_t h_data[0]; | |
167 | }; | 167 | }; | |
168 | #define UTOPPY_OUT_INIT(sc) \ | 168 | #define UTOPPY_OUT_INIT(sc) \ | |
169 | do { \ | 169 | do { \ | |
170 | struct utoppy_header *_h = sc->sc_out_data; \ | 170 | struct utoppy_header *_h = sc->sc_out_data; \ | |
171 | _h->h_len = 0; \ | 171 | _h->h_len = 0; \ | |
172 | } while (/*CONSTCOND*/0) | 172 | } while (/*CONSTCOND*/0) | |
173 | 173 | |||
174 | #define UTOPPY_MJD_1970 40587u /* MJD value for Jan 1 00:00:00 1970 */ | 174 | #define UTOPPY_MJD_1970 40587u /* MJD value for Jan 1 00:00:00 1970 */ | |
175 | 175 | |||
176 | #define UTOPPY_FTYPE_DIR 1 | 176 | #define UTOPPY_FTYPE_DIR 1 | |
177 | #define UTOPPY_FTYPE_FILE 2 | 177 | #define UTOPPY_FTYPE_FILE 2 | |
178 | 178 | |||
179 | #define UTOPPY_IN_DATA(sc) \ | 179 | #define UTOPPY_IN_DATA(sc) \ | |
180 | ((void*)&(((uint8_t*)(sc)->sc_in_data)[(sc)->sc_in_offset+UTOPPY_HEADER_SIZE])) | 180 | ((void*)&(((uint8_t*)(sc)->sc_in_data)[(sc)->sc_in_offset+UTOPPY_HEADER_SIZE])) | |
181 | 181 | |||
182 | static dev_type_open(utoppyopen); | 182 | static dev_type_open(utoppyopen); | |
183 | static dev_type_close(utoppyclose); | 183 | static dev_type_close(utoppyclose); | |
184 | static dev_type_read(utoppyread); | 184 | static dev_type_read(utoppyread); | |
185 | static dev_type_write(utoppywrite); | 185 | static dev_type_write(utoppywrite); | |
186 | static dev_type_ioctl(utoppyioctl); | 186 | static dev_type_ioctl(utoppyioctl); | |
187 | 187 | |||
188 | const struct cdevsw utoppy_cdevsw = { | 188 | const struct cdevsw utoppy_cdevsw = { | |
189 | .d_open = utoppyopen, | 189 | .d_open = utoppyopen, | |
190 | .d_close = utoppyclose, | 190 | .d_close = utoppyclose, | |
191 | .d_read = utoppyread, | 191 | .d_read = utoppyread, | |
192 | .d_write = utoppywrite, | 192 | .d_write = utoppywrite, | |
193 | .d_ioctl = utoppyioctl, | 193 | .d_ioctl = utoppyioctl, | |
194 | .d_stop = nostop, | 194 | .d_stop = nostop, | |
195 | .d_tty = notty, | 195 | .d_tty = notty, | |
196 | .d_poll = nopoll, | 196 | .d_poll = nopoll, | |
197 | .d_mmap = nommap, | 197 | .d_mmap = nommap, | |
198 | .d_kqfilter = nokqfilter, | 198 | .d_kqfilter = nokqfilter, | |
199 | .d_discard = nodiscard, | 199 | .d_discard = nodiscard, | |
200 | .d_flag = D_OTHER | 200 | .d_flag = D_OTHER | |
201 | }; | 201 | }; | |
202 | 202 | |||
203 | #define UTOPPYUNIT(n) (minor(n)) | 203 | #define UTOPPYUNIT(n) (minor(n)) | |
204 | 204 | |||
205 | static int utoppy_match(device_t, cfdata_t, void *); | 205 | static int utoppy_match(device_t, cfdata_t, void *); | |
206 | static void utoppy_attach(device_t, device_t, void *); | 206 | static void utoppy_attach(device_t, device_t, void *); | |
207 | static int utoppy_detach(device_t, int); | 207 | static int utoppy_detach(device_t, int); | |
208 | static int utoppy_activate(device_t, enum devact); | 208 | static int utoppy_activate(device_t, enum devact); | |
209 | 209 | |||
210 | CFATTACH_DECL_NEW(utoppy, sizeof(struct utoppy_softc), utoppy_match, | 210 | CFATTACH_DECL_NEW(utoppy, sizeof(struct utoppy_softc), utoppy_match, | |
211 | utoppy_attach, utoppy_detach, utoppy_activate); | 211 | utoppy_attach, utoppy_detach, utoppy_activate); | |
212 | 212 | |||
213 | static int | 213 | static int | |
214 | utoppy_match(device_t parent, cfdata_t match, void *aux) | 214 | utoppy_match(device_t parent, cfdata_t match, void *aux) | |
215 | { | 215 | { | |
216 | struct usb_attach_arg *uaa = aux; | 216 | struct usb_attach_arg *uaa = aux; | |
217 | 217 | |||
218 | if (uaa->uaa_vendor == USB_VENDOR_TOPFIELD && | 218 | if (uaa->uaa_vendor == USB_VENDOR_TOPFIELD && | |
219 | uaa->uaa_product == USB_PRODUCT_TOPFIELD_TF5000PVR) | 219 | uaa->uaa_product == USB_PRODUCT_TOPFIELD_TF5000PVR) | |
220 | return UMATCH_VENDOR_PRODUCT; | 220 | return UMATCH_VENDOR_PRODUCT; | |
221 | 221 | |||
222 | return UMATCH_NONE; | 222 | return UMATCH_NONE; | |
223 | } | 223 | } | |
224 | 224 | |||
225 | static void | 225 | static void | |
226 | utoppy_attach(device_t parent, device_t self, void *aux) | 226 | utoppy_attach(device_t parent, device_t self, void *aux) | |
227 | { | 227 | { | |
228 | struct utoppy_softc *sc = device_private(self); | 228 | struct utoppy_softc *sc = device_private(self); | |
229 | struct usb_attach_arg *uaa = aux; | 229 | struct usb_attach_arg *uaa = aux; | |
230 | struct usbd_device *dev = uaa->uaa_device; | 230 | struct usbd_device *dev = uaa->uaa_device; | |
231 | struct usbd_interface *iface; | 231 | struct usbd_interface *iface; | |
232 | usb_endpoint_descriptor_t *ed; | 232 | usb_endpoint_descriptor_t *ed; | |
233 | char *devinfop; | 233 | char *devinfop; | |
234 | uint8_t epcount; | 234 | uint8_t epcount; | |
235 | int i; | 235 | int i; | |
236 | 236 | |||
237 | sc->sc_dev = self; | 237 | sc->sc_dev = self; | |
238 | 238 | |||
239 | aprint_naive("\n"); | 239 | aprint_naive("\n"); | |
240 | aprint_normal("\n"); | 240 | aprint_normal("\n"); | |
241 | 241 | |||
242 | devinfop = usbd_devinfo_alloc(dev, 0); | 242 | devinfop = usbd_devinfo_alloc(dev, 0); | |
243 | aprint_normal_dev(self, "%s\n", devinfop); | 243 | aprint_normal_dev(self, "%s\n", devinfop); | |
244 | usbd_devinfo_free(devinfop); | 244 | usbd_devinfo_free(devinfop); | |
245 | 245 | |||
246 | sc->sc_dying = 0; | 246 | sc->sc_dying = 0; | |
247 | sc->sc_refcnt = 0; | 247 | sc->sc_refcnt = 0; | |
248 | sc->sc_udev = dev; | 248 | sc->sc_udev = dev; | |
249 | 249 | |||
250 | if (usbd_set_config_index(dev, 0, 1) | 250 | if (usbd_set_config_index(dev, 0, 1) | |
251 | || usbd_device2interface_handle(dev, 0, &iface)) { | 251 | || usbd_device2interface_handle(dev, 0, &iface)) { | |
252 | aprint_error_dev(self, "Configuration failed\n"); | 252 | aprint_error_dev(self, "Configuration failed\n"); | |
253 | return; | 253 | return; | |
254 | } | 254 | } | |
255 | 255 | |||
256 | epcount = 0; | 256 | epcount = 0; | |
257 | (void) usbd_endpoint_count(iface, &epcount); | 257 | (void) usbd_endpoint_count(iface, &epcount); | |
258 | if (epcount != UTOPPY_NUMENDPOINTS) { | 258 | if (epcount != UTOPPY_NUMENDPOINTS) { | |
259 | aprint_error_dev(self, "Expected %d endpoints, got %d\n", | 259 | aprint_error_dev(self, "Expected %d endpoints, got %d\n", | |
260 | UTOPPY_NUMENDPOINTS, epcount); | 260 | UTOPPY_NUMENDPOINTS, epcount); | |
261 | return; | 261 | return; | |
262 | } | 262 | } | |
263 | 263 | |||
264 | sc->sc_in = -1; | 264 | sc->sc_in = -1; | |
265 | sc->sc_out = -1; | 265 | sc->sc_out = -1; | |
266 | 266 | |||
267 | for (i = 0; i < epcount; i++) { | 267 | for (i = 0; i < epcount; i++) { | |
268 | ed = usbd_interface2endpoint_descriptor(iface, i); | 268 | ed = usbd_interface2endpoint_descriptor(iface, i); | |
269 | if (ed == NULL) { | 269 | if (ed == NULL) { | |
270 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 270 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
271 | return; | 271 | return; | |
272 | } | 272 | } | |
273 | 273 | |||
274 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 274 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
275 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 275 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
276 | sc->sc_in = ed->bEndpointAddress; | 276 | sc->sc_in = ed->bEndpointAddress; | |
277 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 277 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
278 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 278 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
279 | sc->sc_out = ed->bEndpointAddress; | 279 | sc->sc_out = ed->bEndpointAddress; | |
280 | } | 280 | } | |
281 | } | 281 | } | |
282 | 282 | |||
283 | if (sc->sc_out == -1 || sc->sc_in == -1) { | 283 | if (sc->sc_out == -1 || sc->sc_in == -1) { | |
284 | aprint_error_dev(self, | 284 | aprint_error_dev(self, | |
285 | "could not find bulk in/out endpoints\n"); | 285 | "could not find bulk in/out endpoints\n"); | |
286 | sc->sc_dying = 1; | 286 | sc->sc_dying = 1; | |
287 | return; | 287 | return; | |
288 | } | 288 | } | |
289 | 289 | |||
290 | sc->sc_iface = iface; | 290 | sc->sc_iface = iface; | |
291 | sc->sc_udev = dev; | 291 | sc->sc_udev = dev; | |
292 | 292 | |||
293 | sc->sc_out_pipe = NULL; | 293 | sc->sc_out_pipe = NULL; | |
294 | sc->sc_in_pipe = NULL; | 294 | sc->sc_in_pipe = NULL; | |
295 | 295 | |||
296 | if (usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe)) { | 296 | if (usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe)) { | |
297 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: usbd_open_pipe(OUT) failed\n", | 297 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: usbd_open_pipe(OUT) failed\n", | |
298 | device_xname(sc->sc_dev))); | 298 | device_xname(sc->sc_dev))); | |
299 | aprint_error_dev(self, "could not open OUT pipe\n"); | 299 | aprint_error_dev(self, "could not open OUT pipe\n"); | |
300 | sc->sc_dying = 1; | 300 | sc->sc_dying = 1; | |
301 | return; | 301 | return; | |
302 | } | 302 | } | |
303 | 303 | |||
304 | if (usbd_open_pipe(sc->sc_iface, sc->sc_in, 0, &sc->sc_in_pipe)) { | 304 | if (usbd_open_pipe(sc->sc_iface, sc->sc_in, 0, &sc->sc_in_pipe)) { | |
305 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: usbd_open_pipe(IN) failed\n", | 305 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: usbd_open_pipe(IN) failed\n", | |
306 | device_xname(sc->sc_dev))); | 306 | device_xname(sc->sc_dev))); | |
307 | aprint_error_dev(self, "could not open IN pipe\n"); | 307 | aprint_error_dev(self, "could not open IN pipe\n"); | |
308 | 308 | |||
309 | usbd_close_pipe(sc->sc_out_pipe); | 309 | usbd_close_pipe(sc->sc_out_pipe); | |
310 | sc->sc_out_pipe = NULL; | 310 | sc->sc_out_pipe = NULL; | |
311 | sc->sc_dying = 1; | 311 | sc->sc_dying = 1; | |
312 | return; | 312 | return; | |
313 | } | 313 | } | |
314 | 314 | |||
315 | int error; | 315 | int error; | |
316 | error = usbd_create_xfer(sc->sc_out_pipe, UTOPPY_FRAG_SIZE, 0, 0, | 316 | error = usbd_create_xfer(sc->sc_out_pipe, UTOPPY_FRAG_SIZE, 0, 0, | |
317 | &sc->sc_out_xfer); | 317 | &sc->sc_out_xfer); | |
318 | if (error) { | 318 | if (error) { | |
319 | aprint_error_dev(self, "could not allocate bulk out xfer\n"); | 319 | aprint_error_dev(self, "could not allocate bulk out xfer\n"); | |
320 | goto fail0; | 320 | goto fail0; | |
321 | } | 321 | } | |
322 | 322 | |||
323 | error = usbd_create_xfer(sc->sc_in_pipe, UTOPPY_FRAG_SIZE, | 323 | error = usbd_create_xfer(sc->sc_in_pipe, UTOPPY_FRAG_SIZE, | |
324 | 0, 0, &sc->sc_in_xfer); | 324 | 0, 0, &sc->sc_in_xfer); | |
325 | if (error) { | 325 | if (error) { | |
326 | aprint_error_dev(self, "could not allocate bulk in xfer\n"); | 326 | aprint_error_dev(self, "could not allocate bulk in xfer\n"); | |
327 | goto fail1; | 327 | goto fail1; | |
328 | } | 328 | } | |
329 | 329 | |||
330 | sc->sc_out_buf = usbd_get_buffer(sc->sc_out_xfer); | 330 | sc->sc_out_buf = usbd_get_buffer(sc->sc_out_xfer); | |
331 | sc->sc_in_buf = usbd_get_buffer(sc->sc_in_xfer); | 331 | sc->sc_in_buf = usbd_get_buffer(sc->sc_in_xfer); | |
332 | 332 | |||
333 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); | 333 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); | |
334 | 334 | |||
335 | return; | 335 | return; | |
336 | 336 | |||
337 | fail1: usbd_destroy_xfer(sc->sc_out_xfer); | 337 | fail1: usbd_destroy_xfer(sc->sc_out_xfer); | |
338 | sc->sc_out_xfer = NULL; | 338 | sc->sc_out_xfer = NULL; | |
339 | 339 | |||
340 | fail0: sc->sc_dying = 1; | 340 | fail0: sc->sc_dying = 1; | |
341 | return; | 341 | return; | |
342 | } | 342 | } | |
343 | 343 | |||
344 | static int | 344 | static int | |
345 | utoppy_activate(device_t self, enum devact act) | 345 | utoppy_activate(device_t self, enum devact act) | |
346 | { | 346 | { | |
347 | struct utoppy_softc *sc = device_private(self); | 347 | struct utoppy_softc *sc = device_private(self); | |
348 | 348 | |||
349 | switch (act) { | 349 | switch (act) { | |
350 | case DVACT_DEACTIVATE: | 350 | case DVACT_DEACTIVATE: | |
351 | sc->sc_dying = 1; | 351 | sc->sc_dying = 1; | |
352 | return 0; | 352 | return 0; | |
353 | default: | 353 | default: | |
354 | return EOPNOTSUPP; | 354 | return EOPNOTSUPP; | |
355 | } | 355 | } | |
356 | } | 356 | } | |
357 | 357 | |||
358 | static int | 358 | static int | |
359 | utoppy_detach(device_t self, int flags) | 359 | utoppy_detach(device_t self, int flags) | |
360 | { | 360 | { | |
361 | struct utoppy_softc *sc = device_private(self); | 361 | struct utoppy_softc *sc = device_private(self); | |
362 | int maj, mn; | 362 | int maj, mn; | |
363 | int s; | 363 | int s; | |
364 | 364 | |||
365 | sc->sc_dying = 1; | 365 | sc->sc_dying = 1; | |
366 | if (sc->sc_out_pipe != NULL) | 366 | if (sc->sc_out_pipe != NULL) | |
367 | usbd_abort_pipe(sc->sc_out_pipe); | 367 | usbd_abort_pipe(sc->sc_out_pipe); | |
368 | if (sc->sc_in_pipe != NULL) | 368 | if (sc->sc_in_pipe != NULL) | |
369 | usbd_abort_pipe(sc->sc_in_pipe); | 369 | usbd_abort_pipe(sc->sc_in_pipe); | |
370 | 370 | |||
371 | if (sc->sc_in_xfer != NULL) | 371 | if (sc->sc_in_xfer != NULL) | |
372 | usbd_destroy_xfer(sc->sc_in_xfer); | 372 | usbd_destroy_xfer(sc->sc_in_xfer); | |
373 | if (sc->sc_out_xfer != NULL) | 373 | if (sc->sc_out_xfer != NULL) | |
374 | usbd_destroy_xfer(sc->sc_out_xfer); | 374 | usbd_destroy_xfer(sc->sc_out_xfer); | |
375 | 375 | |||
376 | if (sc->sc_out_pipe != NULL) | 376 | if (sc->sc_out_pipe != NULL) | |
377 | usbd_close_pipe(sc->sc_out_pipe); | 377 | usbd_close_pipe(sc->sc_out_pipe); | |
378 | if (sc->sc_in_pipe != NULL) | 378 | if (sc->sc_in_pipe != NULL) | |
379 | usbd_close_pipe(sc->sc_in_pipe); | 379 | usbd_close_pipe(sc->sc_in_pipe); | |
380 | 380 | |||
381 | s = splusb(); | 381 | s = splusb(); | |
382 | if (--sc->sc_refcnt >= 0) | 382 | if (--sc->sc_refcnt >= 0) | |
383 | usb_detach_waitold(sc->sc_dev); | 383 | usb_detach_waitold(sc->sc_dev); | |
384 | splx(s); | 384 | splx(s); | |
385 | 385 | |||
386 | /* locate the major number */ | 386 | /* locate the major number */ | |
387 | maj = cdevsw_lookup_major(&utoppy_cdevsw); | 387 | maj = cdevsw_lookup_major(&utoppy_cdevsw); | |
388 | 388 | |||
389 | /* Nuke the vnodes for any open instances (calls close). */ | 389 | /* Nuke the vnodes for any open instances (calls close). */ | |
390 | mn = device_unit(self); | 390 | mn = device_unit(self); | |
391 | vdevgone(maj, mn, mn, VCHR); | 391 | vdevgone(maj, mn, mn, VCHR); | |
392 | 392 | |||
393 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); | 393 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); | |
394 | 394 | |||
395 | return 0; | 395 | return 0; | |
396 | } | 396 | } | |
397 | 397 | |||
398 | #define UTOPPY_CRC16(ccrc,b) crc16_byte((ccrc), (b)) /* from crc16.h */ | 398 | #define UTOPPY_CRC16(ccrc,b) crc16_byte((ccrc), (b)) /* from crc16.h */ | |
399 | 399 | |||
400 | static const int utoppy_usbdstatus_lookup[] = { | 400 | static const int utoppy_usbdstatus_lookup[] = { | |
401 | 0, /* USBD_NORMAL_COMPLETION */ | 401 | 0, /* USBD_NORMAL_COMPLETION */ | |
402 | EINPROGRESS, /* USBD_IN_PROGRESS */ | 402 | EINPROGRESS, /* USBD_IN_PROGRESS */ | |
403 | EALREADY, /* USBD_PENDING_REQUESTS */ | 403 | EALREADY, /* USBD_PENDING_REQUESTS */ | |
404 | EAGAIN, /* USBD_NOT_STARTED */ | 404 | EAGAIN, /* USBD_NOT_STARTED */ | |
405 | EINVAL, /* USBD_INVAL */ | 405 | EINVAL, /* USBD_INVAL */ | |
406 | ENOMEM, /* USBD_NOMEM */ | 406 | ENOMEM, /* USBD_NOMEM */ | |
407 | ECONNRESET, /* USBD_CANCELLED */ | 407 | ECONNRESET, /* USBD_CANCELLED */ | |
408 | EFAULT, /* USBD_BAD_ADDRESS */ | 408 | EFAULT, /* USBD_BAD_ADDRESS */ | |
409 | EBUSY, /* USBD_IN_USE */ | 409 | EBUSY, /* USBD_IN_USE */ | |
410 | EADDRNOTAVAIL, /* USBD_NO_ADDR */ | 410 | EADDRNOTAVAIL, /* USBD_NO_ADDR */ | |
411 | ENETDOWN, /* USBD_SET_ADDR_FAILED */ | 411 | ENETDOWN, /* USBD_SET_ADDR_FAILED */ | |
412 | EIO, /* USBD_NO_POWER */ | 412 | EIO, /* USBD_NO_POWER */ | |
413 | EMLINK, /* USBD_TOO_DEEP */ | 413 | EMLINK, /* USBD_TOO_DEEP */ | |
414 | EIO, /* USBD_IOERROR */ | 414 | EIO, /* USBD_IOERROR */ | |
415 | ENXIO, /* USBD_NOT_CONFIGURED */ | 415 | ENXIO, /* USBD_NOT_CONFIGURED */ | |
416 | ETIMEDOUT, /* USBD_TIMEOUT */ | 416 | ETIMEDOUT, /* USBD_TIMEOUT */ | |
417 | EBADMSG, /* USBD_SHORT_XFER */ | 417 | EBADMSG, /* USBD_SHORT_XFER */ | |
418 | EHOSTDOWN, /* USBD_STALLED */ | 418 | EHOSTDOWN, /* USBD_STALLED */ | |
419 | EINTR /* USBD_INTERRUPTED */ | 419 | EINTR /* USBD_INTERRUPTED */ | |
420 | }; | 420 | }; | |
421 | 421 | |||
422 | static __inline int | 422 | static __inline int | |
423 | utoppy_usbd_status2errno(usbd_status err) | 423 | utoppy_usbd_status2errno(usbd_status err) | |
424 | { | 424 | { | |
425 | 425 | |||
426 | if (err >= USBD_ERROR_MAX) | 426 | if (err >= USBD_ERROR_MAX) | |
427 | return EFAULT; | 427 | return EFAULT; | |
428 | return utoppy_usbdstatus_lookup[err]; | 428 | return utoppy_usbdstatus_lookup[err]; | |
429 | } | 429 | } | |
430 | 430 | |||
431 | #ifdef UTOPPY_DEBUG | 431 | #ifdef UTOPPY_DEBUG | |
432 | static const char * | 432 | static const char * | |
433 | utoppy_state_string(enum utoppy_state state) | 433 | utoppy_state_string(enum utoppy_state state) | |
434 | { | 434 | { | |
435 | const char *str; | 435 | const char *str; | |
436 | 436 | |||
437 | switch (state) { | 437 | switch (state) { | |
438 | case UTOPPY_STATE_CLOSED: | 438 | case UTOPPY_STATE_CLOSED: | |
439 | str = "CLOSED"; | 439 | str = "CLOSED"; | |
440 | break; | 440 | break; | |
441 | case UTOPPY_STATE_OPENING: | 441 | case UTOPPY_STATE_OPENING: | |
442 | str = "OPENING"; | 442 | str = "OPENING"; | |
443 | break; | 443 | break; | |
444 | case UTOPPY_STATE_IDLE: | 444 | case UTOPPY_STATE_IDLE: | |
445 | str = "IDLE"; | 445 | str = "IDLE"; | |
446 | break; | 446 | break; | |
447 | case UTOPPY_STATE_READDIR: | 447 | case UTOPPY_STATE_READDIR: | |
448 | str = "READ DIRECTORY"; | 448 | str = "READ DIRECTORY"; | |
449 | break; | 449 | break; | |
450 | case UTOPPY_STATE_READFILE: | 450 | case UTOPPY_STATE_READFILE: | |
451 | str = "READ FILE"; | 451 | str = "READ FILE"; | |
452 | break; | 452 | break; | |
453 | case UTOPPY_STATE_WRITEFILE: | 453 | case UTOPPY_STATE_WRITEFILE: | |
454 | str = "WRITE FILE"; | 454 | str = "WRITE FILE"; | |
455 | break; | 455 | break; | |
456 | default: | 456 | default: | |
457 | str = "INVALID!"; | 457 | str = "INVALID!"; | |
458 | break; | 458 | break; | |
459 | } | 459 | } | |
460 | 460 | |||
461 | return str; | 461 | return str; | |
462 | } | 462 | } | |
463 | 463 | |||
464 | static void | 464 | static void | |
465 | utoppy_dump_packet(const void *b, size_t len) | 465 | utoppy_dump_packet(const void *b, size_t len) | |
466 | { | 466 | { | |
467 | const uint8_t *buf = b, *l; | 467 | const uint8_t *buf = b, *l; | |
468 | uint8_t c; | 468 | uint8_t c; | |
469 | size_t i, j; | 469 | size_t i, j; | |
470 | 470 | |||
471 | if (len == 0) | 471 | if (len == 0) | |
472 | return; | 472 | return; | |
473 | 473 | |||
474 | len = uimin(len, 256); | 474 | len = uimin(len, 256); | |
475 | 475 | |||
476 | printf("00: "); | 476 | printf("00: "); | |
477 | 477 | |||
478 | for (i = 0, l = buf; i < len; i++) { | 478 | for (i = 0, l = buf; i < len; i++) { | |
479 | printf("%02x ", *buf++); | 479 | printf("%02x ", *buf++); | |
480 | 480 | |||
481 | if ((i % 16) == 15) { | 481 | if ((i % 16) == 15) { | |
482 | for (j = 0; j < 16; j++) { | 482 | for (j = 0; j < 16; j++) { | |
483 | c = *l++; | 483 | c = *l++; | |
484 | if (c < ' ' || c > 0x7e) | 484 | if (c < ' ' || c > 0x7e) | |
485 | c = '.'; | 485 | c = '.'; | |
486 | printf("%c", c); | 486 | printf("%c", c); | |
487 | } | 487 | } | |
488 | 488 | |||
489 | printf("\n"); | 489 | printf("\n"); | |
490 | l = buf; | 490 | l = buf; | |
491 | 491 | |||
492 | if ((i + 1) < len) | 492 | if ((i + 1) < len) | |
493 | printf("%02x: ", (u_int)i + 1); | 493 | printf("%02x: ", (u_int)i + 1); | |
494 | } | 494 | } | |
495 | } | 495 | } | |
496 | 496 | |||
497 | while ((i++ % 16) != 0) | 497 | while ((i++ % 16) != 0) | |
498 | printf(" "); | 498 | printf(" "); | |
499 | 499 | |||
500 | if (l < buf) { | 500 | if (l < buf) { | |
501 | while (l < buf) { | 501 | while (l < buf) { | |
502 | c = *l++; | 502 | c = *l++; | |
503 | if (c < ' ' || c > 0x7e) | 503 | if (c < ' ' || c > 0x7e) | |
504 | c = '.'; | 504 | c = '.'; | |
505 | printf("%c", c); | 505 | printf("%c", c); | |
506 | } | 506 | } | |
507 | 507 | |||
508 | printf("\n"); | 508 | printf("\n"); | |
509 | } | 509 | } | |
510 | } | 510 | } | |
511 | #endif | 511 | #endif | |
512 | 512 | |||
513 | static usbd_status | 513 | static usbd_status | |
514 | utoppy_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, | 514 | utoppy_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, | |
515 | uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) | 515 | uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) | |
516 | { | 516 | { | |
517 | usbd_status err; | 517 | usbd_status err; | |
518 | 518 | |||
519 | usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); | 519 | usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); | |
520 | 520 | |||
521 | err = usbd_sync_transfer_sig(xfer); | 521 | err = usbd_sync_transfer_sig(xfer); | |
522 | 522 | |||
523 | usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); | 523 | usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); | |
524 | return err; | 524 | return err; | |
525 | } | 525 | } | |
526 | 526 | |||
527 | static int | 527 | static int | |
528 | utoppy_send_packet(struct utoppy_softc *sc, uint16_t cmd, uint32_t timeout) | 528 | utoppy_send_packet(struct utoppy_softc *sc, uint16_t cmd, uint32_t timeout) | |
529 | { | 529 | { | |
530 | struct utoppy_header *h; | 530 | struct utoppy_header *h; | |
531 | usbd_status err; | 531 | usbd_status err; | |
532 | uint32_t len; | 532 | uint32_t len; | |
533 | uint16_t dlen, crc; | 533 | uint16_t dlen, crc; | |
534 | uint8_t *data, *e, t1, t2; | 534 | uint8_t *data, *e, t1, t2; | |
535 | 535 | |||
536 | h = sc->sc_out_data; | 536 | h = sc->sc_out_data; | |
537 | 537 | |||
538 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: cmd 0x%04x, " | 538 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: cmd 0x%04x, " | |
539 | "len %d\n", device_xname(sc->sc_dev), (u_int)cmd, h->h_len)); | 539 | "len %d\n", device_xname(sc->sc_dev), (u_int)cmd, h->h_len)); | |
540 | 540 | |||
541 | dlen = h->h_len; | 541 | dlen = h->h_len; | |
542 | len = dlen + UTOPPY_HEADER_SIZE; | 542 | len = dlen + UTOPPY_HEADER_SIZE; | |
543 | 543 | |||
544 | if (len & 1) | 544 | if (len & 1) | |
545 | len++; | 545 | len++; | |
546 | if ((len % 64) == 0) | 546 | if ((len % 64) == 0) | |
547 | len += 2; | 547 | len += 2; | |
548 | 548 | |||
549 | if (len >= UTOPPY_BSIZE) { | 549 | if (len >= UTOPPY_BSIZE) { | |
550 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: " | 550 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: " | |
551 | "packet too big (%d)\n", device_xname(sc->sc_dev), | 551 | "packet too big (%d)\n", device_xname(sc->sc_dev), | |
552 | (int)len)); | 552 | (int)len)); | |
553 | return EINVAL; | 553 | return EINVAL; | |
554 | } | 554 | } | |
555 | 555 | |||
556 | h->h_len = htole16(dlen + UTOPPY_HEADER_SIZE); | 556 | h->h_len = htole16(dlen + UTOPPY_HEADER_SIZE); | |
557 | h->h_cmd2 = 0; | 557 | h->h_cmd2 = 0; | |
558 | h->h_cmd = htole16(cmd); | 558 | h->h_cmd = htole16(cmd); | |
559 | 559 | |||
560 | /* The command word is part of the CRC */ | 560 | /* The command word is part of the CRC */ | |
561 | crc = UTOPPY_CRC16(0, 0); | 561 | crc = UTOPPY_CRC16(0, 0); | |
562 | crc = UTOPPY_CRC16(crc, 0); | 562 | crc = UTOPPY_CRC16(crc, 0); | |
563 | crc = UTOPPY_CRC16(crc, cmd >> 8); | 563 | crc = UTOPPY_CRC16(crc, cmd >> 8); | |
564 | crc = UTOPPY_CRC16(crc, cmd); | 564 | crc = UTOPPY_CRC16(crc, cmd); | |
565 | 565 | |||
566 | /* | 566 | /* | |
567 | * If there is data following the header, calculate the CRC and | 567 | * If there is data following the header, calculate the CRC and | |
568 | * byte-swap as we go. | 568 | * byte-swap as we go. | |
569 | */ | 569 | */ | |
570 | if (dlen) { | 570 | if (dlen) { | |
571 | data = h->h_data; | 571 | data = h->h_data; | |
572 | e = data + (dlen & ~1); | 572 | e = data + (dlen & ~1); | |
573 | 573 | |||
574 | do { | 574 | do { | |
575 | t1 = data[0]; | 575 | t1 = data[0]; | |
576 | t2 = data[1]; | 576 | t2 = data[1]; | |
577 | crc = UTOPPY_CRC16(crc, t1); | 577 | crc = UTOPPY_CRC16(crc, t1); | |
578 | crc = UTOPPY_CRC16(crc, t2); | 578 | crc = UTOPPY_CRC16(crc, t2); | |
579 | *data++ = t2; | 579 | *data++ = t2; | |
580 | *data++ = t1; | 580 | *data++ = t1; | |
581 | } while (data < e); | 581 | } while (data < e); | |
582 | 582 | |||
583 | if (dlen & 1) { | 583 | if (dlen & 1) { | |
584 | t1 = data[0]; | 584 | t1 = data[0]; | |
585 | crc = UTOPPY_CRC16(crc, t1); | 585 | crc = UTOPPY_CRC16(crc, t1); | |
586 | data[1] = t1; | 586 | data[1] = t1; | |
587 | } | 587 | } | |
588 | } | 588 | } | |
589 | 589 | |||
590 | h->h_crc = htole16(crc); | 590 | h->h_crc = htole16(crc); | |
591 | data = sc->sc_out_data; | 591 | data = sc->sc_out_data; | |
592 | 592 | |||
593 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: total len " | 593 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: total len " | |
594 | "%d...\n", device_xname(sc->sc_dev), (int)len)); | 594 | "%d...\n", device_xname(sc->sc_dev), (int)len)); | |
595 | DDUMP_PACKET(data, len); | 595 | DDUMP_PACKET(data, len); | |
596 | 596 | |||
597 | do { | 597 | do { | |
598 | uint32_t thislen; | 598 | uint32_t thislen; | |
599 | 599 | |||
600 | thislen = uimin(len, UTOPPY_FRAG_SIZE); | 600 | thislen = uimin(len, UTOPPY_FRAG_SIZE); | |
601 | 601 | |||
602 | memcpy(sc->sc_out_buf, data, thislen); | 602 | memcpy(sc->sc_out_buf, data, thislen); | |
603 | 603 | |||
604 | err = utoppy_bulk_transfer(sc->sc_out_xfer, sc->sc_out_pipe, | 604 | err = utoppy_bulk_transfer(sc->sc_out_xfer, sc->sc_out_pipe, | |
605 | 0, timeout, sc->sc_out_buf, &thislen); | 605 | 0, timeout, sc->sc_out_buf, &thislen); | |
606 | 606 | |||
607 | if (thislen != uimin(len, UTOPPY_FRAG_SIZE)) { | 607 | if (thislen != uimin(len, UTOPPY_FRAG_SIZE)) { | |
608 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: " | 608 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: " | |
609 | "utoppy_send_packet: sent %ld, err %d\n", | 609 | "utoppy_send_packet: sent %ld, err %d\n", | |
610 | device_xname(sc->sc_dev), (u_long)thislen, err)); | 610 | device_xname(sc->sc_dev), (u_long)thislen, err)); | |
611 | } | 611 | } | |
612 | 612 | |||
613 | if (err == 0) { | 613 | if (err == 0) { | |
614 | len -= thislen; | 614 | len -= thislen; | |
615 | data += thislen; | 615 | data += thislen; | |
616 | } | 616 | } | |
617 | } while (err == 0 && len); | 617 | } while (err == 0 && len); | |
618 | 618 | |||
619 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: " | 619 | DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: " | |
620 | "usbd_bulk_transfer() returned %d.\n", | 620 | "usbd_bulk_transfer() returned %d.\n", | |
621 | device_xname(sc->sc_dev),err)); | 621 | device_xname(sc->sc_dev),err)); | |
622 | 622 | |||
623 | return err ? utoppy_usbd_status2errno(err) : 0; | 623 | return err ? utoppy_usbd_status2errno(err) : 0; | |
624 | } | 624 | } | |
625 | 625 | |||
626 | static int | 626 | static int | |
627 | utoppy_recv_packet(struct utoppy_softc *sc, uint16_t *respp, uint32_t timeout) | 627 | utoppy_recv_packet(struct utoppy_softc *sc, uint16_t *respp, uint32_t timeout) | |
628 | { | 628 | { | |
629 | struct utoppy_header *h; | 629 | struct utoppy_header *h; | |
630 | usbd_status err; | 630 | usbd_status err; | |
631 | uint32_t len, thislen, requested, bytesleft; | 631 | uint32_t len, thislen, requested, bytesleft; | |
632 | uint16_t crc; | 632 | uint16_t crc; | |
633 | uint8_t *data, *e, t1, t2; | 633 | uint8_t *data, *e, t1, t2; | |
634 | 634 | |||
635 | data = sc->sc_in_data; | 635 | data = sc->sc_in_data; | |
636 | len = 0; | 636 | len = 0; | |
637 | bytesleft = UTOPPY_BSIZE; | 637 | bytesleft = UTOPPY_BSIZE; | |
638 | 638 | |||
639 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: ...\n", | 639 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: ...\n", | |
640 | device_xname(sc->sc_dev))); | 640 | device_xname(sc->sc_dev))); | |
641 | 641 | |||
642 | do { | 642 | do { | |
643 | requested = thislen = uimin(bytesleft, UTOPPY_FRAG_SIZE); | 643 | requested = thislen = uimin(bytesleft, UTOPPY_FRAG_SIZE); | |
644 | 644 | |||
645 | err = utoppy_bulk_transfer(sc->sc_in_xfer, sc->sc_in_pipe, | 645 | err = utoppy_bulk_transfer(sc->sc_in_xfer, sc->sc_in_pipe, | |
646 | USBD_SHORT_XFER_OK, timeout, sc->sc_in_buf, | 646 | USBD_SHORT_XFER_OK, timeout, sc->sc_in_buf, | |
647 | &thislen); | 647 | &thislen); | |
648 | 648 | |||
649 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: " | 649 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: " | |
650 | "usbd_bulk_transfer() returned %d, thislen %d, data %p\n", | 650 | "usbd_bulk_transfer() returned %d, thislen %d, data %p\n", | |
651 | device_xname(sc->sc_dev), err, (u_int)thislen, data)); | 651 | device_xname(sc->sc_dev), err, (u_int)thislen, data)); | |
652 | 652 | |||
653 | if (err == 0) { | 653 | if (err == 0) { | |
654 | memcpy(data, sc->sc_in_buf, thislen); | 654 | memcpy(data, sc->sc_in_buf, thislen); | |
655 | DDUMP_PACKET(data, thislen); | 655 | DDUMP_PACKET(data, thislen); | |
656 | len += thislen; | 656 | len += thislen; | |
657 | bytesleft -= thislen; | 657 | bytesleft -= thislen; | |
658 | data += thislen; | 658 | data += thislen; | |
659 | } | 659 | } | |
660 | } while (err == 0 && bytesleft && thislen == requested); | 660 | } while (err == 0 && bytesleft && thislen == requested); | |
661 | 661 | |||
662 | if (err) | 662 | if (err) | |
663 | return utoppy_usbd_status2errno(err); | 663 | return utoppy_usbd_status2errno(err); | |
664 | 664 | |||
665 | h = sc->sc_in_data; | 665 | h = sc->sc_in_data; | |
666 | 666 | |||
667 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: received %d " | 667 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: received %d " | |
668 | "bytes in total to %p\n", device_xname(sc->sc_dev), (u_int)len, h)); | 668 | "bytes in total to %p\n", device_xname(sc->sc_dev), (u_int)len, h)); | |
669 | DDUMP_PACKET(h, len); | 669 | DDUMP_PACKET(h, len); | |
670 | 670 | |||
671 | if (len < UTOPPY_HEADER_SIZE || len < (uint32_t)le16toh(h->h_len)) { | 671 | if (len < UTOPPY_HEADER_SIZE || len < (uint32_t)le16toh(h->h_len)) { | |
672 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: bad " | 672 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: bad " | |
673 | " length (len %d, h_len %d)\n", device_xname(sc->sc_dev), | 673 | " length (len %d, h_len %d)\n", device_xname(sc->sc_dev), | |
674 | (int)len, le16toh(h->h_len))); | 674 | (int)len, le16toh(h->h_len))); | |
675 | return EIO; | 675 | return EIO; | |
676 | } | 676 | } | |
677 | 677 | |||
678 | len = h->h_len = le16toh(h->h_len); | 678 | len = h->h_len = le16toh(h->h_len); | |
679 | h->h_crc = le16toh(h->h_crc); | 679 | h->h_crc = le16toh(h->h_crc); | |
680 | *respp = h->h_cmd = le16toh(h->h_cmd); | 680 | *respp = h->h_cmd = le16toh(h->h_cmd); | |
681 | h->h_cmd2 = le16toh(h->h_cmd2); | 681 | h->h_cmd2 = le16toh(h->h_cmd2); | |
682 | 682 | |||
683 | /* | 683 | /* | |
684 | * To maximise data throughput when transferring files, acknowledge | 684 | * To maximise data throughput when transferring files, acknowledge | |
685 | * data blocks as soon as we receive them. If we detect an error | 685 | * data blocks as soon as we receive them. If we detect an error | |
686 | * later on, we can always cancel. | 686 | * later on, we can always cancel. | |
687 | */ | 687 | */ | |
688 | if (*respp == UTOPPY_RESP_FILE_DATA) { | 688 | if (*respp == UTOPPY_RESP_FILE_DATA) { | |
689 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: " | 689 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: " | |
690 | "ACKing file data\n", device_xname(sc->sc_dev))); | 690 | "ACKing file data\n", device_xname(sc->sc_dev))); | |
691 | 691 | |||
692 | UTOPPY_OUT_INIT(sc); | 692 | UTOPPY_OUT_INIT(sc); | |
693 | err = utoppy_send_packet(sc, UTOPPY_CMD_ACK, | 693 | err = utoppy_send_packet(sc, UTOPPY_CMD_ACK, | |
694 | UTOPPY_SHORT_TIMEOUT); | 694 | UTOPPY_SHORT_TIMEOUT); | |
695 | if (err) { | 695 | if (err) { | |
696 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: " | 696 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: " | |
697 | "utoppy_recv_packet: failed to ACK file data: %d\n", | 697 | "utoppy_recv_packet: failed to ACK file data: %d\n", | |
698 | device_xname(sc->sc_dev), err)); | 698 | device_xname(sc->sc_dev), err)); | |
699 | return err; | 699 | return err; | |
700 | } | 700 | } | |
701 | } | 701 | } | |
702 | 702 | |||
703 | /* The command word is part of the CRC */ | 703 | /* The command word is part of the CRC */ | |
704 | crc = UTOPPY_CRC16(0, h->h_cmd2 >> 8); | 704 | crc = UTOPPY_CRC16(0, h->h_cmd2 >> 8); | |
705 | crc = UTOPPY_CRC16(crc, h->h_cmd2); | 705 | crc = UTOPPY_CRC16(crc, h->h_cmd2); | |
706 | crc = UTOPPY_CRC16(crc, h->h_cmd >> 8); | 706 | crc = UTOPPY_CRC16(crc, h->h_cmd >> 8); | |
707 | crc = UTOPPY_CRC16(crc, h->h_cmd); | 707 | crc = UTOPPY_CRC16(crc, h->h_cmd); | |
708 | 708 | |||
709 | /* | 709 | /* | |
710 | * Extract any payload, byte-swapping and calculating the CRC16 | 710 | * Extract any payload, byte-swapping and calculating the CRC16 | |
711 | * as we go. | 711 | * as we go. | |
712 | */ | 712 | */ | |
713 | if (len > UTOPPY_HEADER_SIZE) { | 713 | if (len > UTOPPY_HEADER_SIZE) { | |
714 | data = h->h_data; | 714 | data = h->h_data; | |
715 | e = data + ((len & ~1) - UTOPPY_HEADER_SIZE); | 715 | e = data + ((len & ~1) - UTOPPY_HEADER_SIZE); | |
716 | 716 | |||
717 | while (data < e) { | 717 | while (data < e) { | |
718 | t1 = data[0]; | 718 | t1 = data[0]; | |
719 | t2 = data[1]; | 719 | t2 = data[1]; | |
720 | crc = UTOPPY_CRC16(crc, t2); | 720 | crc = UTOPPY_CRC16(crc, t2); | |
721 | crc = UTOPPY_CRC16(crc, t1); | 721 | crc = UTOPPY_CRC16(crc, t1); | |
722 | *data++ = t2; | 722 | *data++ = t2; | |
723 | *data++ = t1; | 723 | *data++ = t1; | |
724 | } | 724 | } | |
725 | 725 | |||
726 | if (len & 1) { | 726 | if (len & 1) { | |
727 | t1 = data[1]; | 727 | t1 = data[1]; | |
728 | crc = UTOPPY_CRC16(crc, t1); | 728 | crc = UTOPPY_CRC16(crc, t1); | |
729 | *data = t1; | 729 | *data = t1; | |
730 | } | 730 | } | |
731 | } | 731 | } | |
732 | 732 | |||
733 | sc->sc_in_len = (size_t) len - UTOPPY_HEADER_SIZE; | 733 | sc->sc_in_len = (size_t) len - UTOPPY_HEADER_SIZE; | |
734 | sc->sc_in_offset = 0; | 734 | sc->sc_in_offset = 0; | |
735 | 735 | |||
736 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: len %d, " | 736 | DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: len %d, " | |
737 | "crc 0x%04x, hdrcrc 0x%04x\n", device_xname(sc->sc_dev), | 737 | "crc 0x%04x, hdrcrc 0x%04x\n", device_xname(sc->sc_dev), | |
738 | (int)len, crc, h->h_crc)); | 738 | (int)len, crc, h->h_crc)); | |
739 | DDUMP_PACKET(h, len); | 739 | DDUMP_PACKET(h, len); | |
740 | 740 | |||
741 | return (crc == h->h_crc) ? 0 : EBADMSG; | 741 | return (crc == h->h_crc) ? 0 : EBADMSG; | |
742 | } | 742 | } | |
743 | 743 | |||
744 | static __inline void * | 744 | static __inline void * | |
745 | utoppy_current_ptr(void *b) | 745 | utoppy_current_ptr(void *b) | |
746 | { | 746 | { | |
747 | struct utoppy_header *h = b; | 747 | struct utoppy_header *h = b; | |
748 | 748 | |||
749 | return &h->h_data[h->h_len]; | 749 | return &h->h_data[h->h_len]; | |
750 | } | 750 | } | |
751 | 751 | |||
752 | static __inline void | 752 | static __inline void | |
753 | utoppy_advance_ptr(void *b, size_t len) | 753 | utoppy_advance_ptr(void *b, size_t len) | |
754 | { | 754 | { | |
755 | struct utoppy_header *h = b; | 755 | struct utoppy_header *h = b; | |
756 | 756 | |||
757 | h->h_len += len; | 757 | h->h_len += len; | |
758 | } | 758 | } | |
759 | 759 | |||
760 | static __inline void | 760 | static __inline void | |
761 | utoppy_add_8(struct utoppy_softc *sc, uint8_t v) | 761 | utoppy_add_8(struct utoppy_softc *sc, uint8_t v) | |
762 | { | 762 | { | |
763 | struct utoppy_header *h = sc->sc_out_data; | 763 | struct utoppy_header *h = sc->sc_out_data; | |
764 | uint8_t *p; | 764 | uint8_t *p; | |
765 | 765 | |||
766 | p = utoppy_current_ptr(h); | 766 | p = utoppy_current_ptr(h); | |
767 | *p = v; | 767 | *p = v; | |
768 | utoppy_advance_ptr(h, sizeof(v)); | 768 | utoppy_advance_ptr(h, sizeof(v)); | |
769 | } | 769 | } | |
770 | 770 | |||
771 | static __inline void | 771 | static __inline void | |
772 | utoppy_add_16(struct utoppy_softc *sc, uint16_t v) | 772 | utoppy_add_16(struct utoppy_softc *sc, uint16_t v) | |
773 | { | 773 | { | |
774 | struct utoppy_header *h = sc->sc_out_data; | 774 | struct utoppy_header *h = sc->sc_out_data; | |
775 | uint8_t *p; | 775 | uint8_t *p; | |
776 | 776 | |||
777 | p = utoppy_current_ptr(h); | 777 | p = utoppy_current_ptr(h); | |
778 | *p++ = (uint8_t)(v >> 8); | 778 | *p++ = (uint8_t)(v >> 8); | |
779 | *p = (uint8_t)v; | 779 | *p = (uint8_t)v; | |
780 | utoppy_advance_ptr(h, sizeof(v)); | 780 | utoppy_advance_ptr(h, sizeof(v)); | |
781 | } | 781 | } | |
782 | 782 | |||
783 | static __inline void | 783 | static __inline void | |
784 | utoppy_add_32(struct utoppy_softc *sc, uint32_t v) | 784 | utoppy_add_32(struct utoppy_softc *sc, uint32_t v) | |
785 | { | 785 | { | |
786 | struct utoppy_header *h = sc->sc_out_data; | 786 | struct utoppy_header *h = sc->sc_out_data; | |
787 | uint8_t *p; | 787 | uint8_t *p; | |
788 | 788 | |||
789 | p = utoppy_current_ptr(h); | 789 | p = utoppy_current_ptr(h); | |
790 | *p++ = (uint8_t)(v >> 24); | 790 | *p++ = (uint8_t)(v >> 24); | |
791 | *p++ = (uint8_t)(v >> 16); | 791 | *p++ = (uint8_t)(v >> 16); | |
792 | *p++ = (uint8_t)(v >> 8); | 792 | *p++ = (uint8_t)(v >> 8); | |
793 | *p = (uint8_t)v; | 793 | *p = (uint8_t)v; | |
794 | utoppy_advance_ptr(h, sizeof(v)); | 794 | utoppy_advance_ptr(h, sizeof(v)); | |
795 | } | 795 | } | |
796 | 796 | |||
797 | static __inline void | 797 | static __inline void | |
798 | utoppy_add_64(struct utoppy_softc *sc, uint64_t v) | 798 | utoppy_add_64(struct utoppy_softc *sc, uint64_t v) | |
799 | { | 799 | { | |
800 | struct utoppy_header *h = sc->sc_out_data; | 800 | struct utoppy_header *h = sc->sc_out_data; | |
801 | uint8_t *p; | 801 | uint8_t *p; | |
802 | 802 | |||
803 | p = utoppy_current_ptr(h); | 803 | p = utoppy_current_ptr(h); | |
804 | *p++ = (uint8_t)(v >> 56); | 804 | *p++ = (uint8_t)(v >> 56); | |
805 | *p++ = (uint8_t)(v >> 48); | 805 | *p++ = (uint8_t)(v >> 48); | |
806 | *p++ = (uint8_t)(v >> 40); | 806 | *p++ = (uint8_t)(v >> 40); | |
807 | *p++ = (uint8_t)(v >> 32); | 807 | *p++ = (uint8_t)(v >> 32); | |
808 | *p++ = (uint8_t)(v >> 24); | 808 | *p++ = (uint8_t)(v >> 24); | |
809 | *p++ = (uint8_t)(v >> 16); | 809 | *p++ = (uint8_t)(v >> 16); | |
810 | *p++ = (uint8_t)(v >> 8); | 810 | *p++ = (uint8_t)(v >> 8); | |
811 | *p = (uint8_t)v; | 811 | *p = (uint8_t)v; | |
812 | utoppy_advance_ptr(h, sizeof(v)); | 812 | utoppy_advance_ptr(h, sizeof(v)); | |
813 | } | 813 | } | |
814 | 814 | |||
815 | static __inline void | 815 | static __inline void | |
816 | utoppy_add_string(struct utoppy_softc *sc, const char *str, size_t len) | 816 | utoppy_add_string(struct utoppy_softc *sc, const char *str, size_t len) | |
817 | { | 817 | { | |
818 | struct utoppy_header *h = sc->sc_out_data; | 818 | struct utoppy_header *h = sc->sc_out_data; | |
819 | char *p; | 819 | char *p; | |
820 | 820 | |||
821 | p = utoppy_current_ptr(h); | 821 | p = utoppy_current_ptr(h); | |
822 | memset(p, 0, len); | 822 | memset(p, 0, len); | |
823 | strncpy(p, str, len); | 823 | strncpy(p, str, len); | |
824 | utoppy_advance_ptr(h, len); | 824 | utoppy_advance_ptr(h, len); | |
825 | } | 825 | } | |
826 | 826 | |||
827 | static int | 827 | static int | |
828 | utoppy_add_path(struct utoppy_softc *sc, const char *path, int putlen) | 828 | utoppy_add_path(struct utoppy_softc *sc, const char *path, int putlen) | |
829 | { | 829 | { | |
830 | struct utoppy_header *h = sc->sc_out_data; | 830 | struct utoppy_header *h = sc->sc_out_data; | |
831 | uint8_t *p, *str, *s; | 831 | uint8_t *p, *str, *s; | |
832 | size_t len; | 832 | size_t len; | |
833 | int err; | 833 | int err; | |
834 | 834 | |||
835 | p = utoppy_current_ptr(h); | 835 | p = utoppy_current_ptr(h); | |
836 | 836 | |||
837 | str = putlen ? (p + sizeof(uint16_t)) : p; | 837 | str = putlen ? (p + sizeof(uint16_t)) : p; | |
838 | 838 | |||
839 | err = copyinstr(path, str, UTOPPY_MAX_FILENAME_LEN, &len); | 839 | err = copyinstr(path, str, UTOPPY_MAX_FILENAME_LEN, &len); | |
840 | 840 | |||
841 | DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: err %d, len %d\n", | 841 | DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: err %d, len %d\n", | |
842 | err, (int)len)); | 842 | err, (int)len)); | |
843 | 843 | |||
844 | if (err) | 844 | if (err) | |
845 | return err; | 845 | return err; | |
846 | 846 | |||
847 | if (len < 2) | 847 | if (len < 2) | |
848 | return EINVAL; | 848 | return EINVAL; | |
849 | 849 | |||
850 | /* | 850 | /* | |
851 | * copyinstr(9) has already copied the terminating NUL character, | 851 | * copyinstr(9) has already copied the terminating NUL character, | |
852 | * but we append another one in case we have to pad the length | 852 | * but we append another one in case we have to pad the length | |
853 | * later on. | 853 | * later on. | |
854 | */ | 854 | */ | |
855 | str[len] = '\0'; | 855 | str[len] = '\0'; | |
856 | 856 | |||
857 | /* | 857 | /* | |
858 | * The Toppy uses backslash as the directory separator, so convert | 858 | * The Toppy uses backslash as the directory separator, so convert | |
859 | * all forward slashes. | 859 | * all forward slashes. | |
860 | */ | 860 | */ | |
861 | for (s = &str[len - 2]; s >= str; s--) | 861 | for (s = &str[len - 2]; s >= str; s--) | |
862 | if (*s == '/') | 862 | if (*s == '/') | |
863 | *s = '\\'; | 863 | *s = '\\'; | |
864 | 864 | |||
865 | if ((len + h->h_len) & 1) | 865 | if ((len + h->h_len) & 1) | |
866 | len++; | 866 | len++; | |
867 | 867 | |||
868 | if (putlen) | 868 | if (putlen) | |
869 | utoppy_add_16(sc, len); | 869 | utoppy_add_16(sc, len); | |
870 | 870 | |||
871 | utoppy_advance_ptr(h, len); | 871 | utoppy_advance_ptr(h, len); | |
872 | 872 | |||
873 | DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: final len %d\n", | 873 | DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: final len %d\n", | |
874 | (u_int)len)); | 874 | (u_int)len)); | |
875 | 875 | |||
876 | return 0; | 876 | return 0; | |
877 | } | 877 | } | |
878 | 878 | |||
879 | static __inline int | 879 | static __inline int | |
880 | utoppy_get_8(struct utoppy_softc *sc, uint8_t *vp) | 880 | utoppy_get_8(struct utoppy_softc *sc, uint8_t *vp) | |
881 | { | 881 | { | |
882 | uint8_t *p; | 882 | uint8_t *p; | |
883 | 883 | |||
884 | if (sc->sc_in_len < sizeof(*vp)) | 884 | if (sc->sc_in_len < sizeof(*vp)) | |
885 | return 1; | 885 | return 1; | |
886 | 886 | |||
887 | p = UTOPPY_IN_DATA(sc); | 887 | p = UTOPPY_IN_DATA(sc); | |
888 | *vp = *p; | 888 | *vp = *p; | |
889 | sc->sc_in_offset += sizeof(*vp); | 889 | sc->sc_in_offset += sizeof(*vp); | |
890 | sc->sc_in_len -= sizeof(*vp); | 890 | sc->sc_in_len -= sizeof(*vp); | |
891 | return 0; | 891 | return 0; | |
892 | } | 892 | } | |
893 | 893 | |||
894 | static __inline int | 894 | static __inline int | |
895 | utoppy_get_16(struct utoppy_softc *sc, uint16_t *vp) | 895 | utoppy_get_16(struct utoppy_softc *sc, uint16_t *vp) | |
896 | { | 896 | { | |
897 | uint16_t v; | 897 | uint16_t v; | |
898 | uint8_t *p; | 898 | uint8_t *p; | |
899 | 899 | |||
900 | if (sc->sc_in_len < sizeof(v)) | 900 | if (sc->sc_in_len < sizeof(v)) | |
901 | return 1; | 901 | return 1; | |
902 | 902 | |||
903 | p = UTOPPY_IN_DATA(sc); | 903 | p = UTOPPY_IN_DATA(sc); | |
904 | v = *p++; | 904 | v = *p++; | |
905 | v = (v << 8) | *p; | 905 | v = (v << 8) | *p; | |
906 | *vp = v; | 906 | *vp = v; | |
907 | sc->sc_in_offset += sizeof(v); | 907 | sc->sc_in_offset += sizeof(v); | |
908 | sc->sc_in_len -= sizeof(v); | 908 | sc->sc_in_len -= sizeof(v); | |
909 | return 0; | 909 | return 0; | |
910 | } | 910 | } | |
911 | 911 | |||
912 | static __inline int | 912 | static __inline int | |
913 | utoppy_get_32(struct utoppy_softc *sc, uint32_t *vp) | 913 | utoppy_get_32(struct utoppy_softc *sc, uint32_t *vp) | |
914 | { | 914 | { | |
915 | uint32_t v; | 915 | uint32_t v; | |
916 | uint8_t *p; | 916 | uint8_t *p; | |
917 | 917 | |||
918 | if (sc->sc_in_len < sizeof(v)) | 918 | if (sc->sc_in_len < sizeof(v)) | |
919 | return 1; | 919 | return 1; | |
920 | 920 | |||
921 | p = UTOPPY_IN_DATA(sc); | 921 | p = UTOPPY_IN_DATA(sc); | |
922 | v = *p++; | 922 | v = *p++; | |
923 | v = (v << 8) | *p++; | 923 | v = (v << 8) | *p++; | |
924 | v = (v << 8) | *p++; | 924 | v = (v << 8) | *p++; | |
925 | v = (v << 8) | *p; | 925 | v = (v << 8) | *p; | |
926 | *vp = v; | 926 | *vp = v; | |
927 | sc->sc_in_offset += sizeof(v); | 927 | sc->sc_in_offset += sizeof(v); | |
928 | sc->sc_in_len -= sizeof(v); | 928 | sc->sc_in_len -= sizeof(v); | |
929 | return 0; | 929 | return 0; | |
930 | } | 930 | } | |
931 | 931 | |||
932 | static __inline int | 932 | static __inline int | |
933 | utoppy_get_64(struct utoppy_softc *sc, uint64_t *vp) | 933 | utoppy_get_64(struct utoppy_softc *sc, uint64_t *vp) | |
934 | { | 934 | { | |
935 | uint64_t v; | 935 | uint64_t v; | |
936 | uint8_t *p; | 936 | uint8_t *p; | |
937 | 937 | |||
938 | if (sc->sc_in_len < sizeof(v)) | 938 | if (sc->sc_in_len < sizeof(v)) | |
939 | return 1; | 939 | return 1; | |
940 | 940 | |||
941 | p = UTOPPY_IN_DATA(sc); | 941 | p = UTOPPY_IN_DATA(sc); | |
942 | v = *p++; | 942 | v = *p++; | |
943 | v = (v << 8) | *p++; | 943 | v = (v << 8) | *p++; | |
944 | v = (v << 8) | *p++; | 944 | v = (v << 8) | *p++; | |
945 | v = (v << 8) | *p++; | 945 | v = (v << 8) | *p++; | |
946 | v = (v << 8) | *p++; | 946 | v = (v << 8) | *p++; | |
947 | v = (v << 8) | *p++; | 947 | v = (v << 8) | *p++; | |
948 | v = (v << 8) | *p++; | 948 | v = (v << 8) | *p++; | |
949 | v = (v << 8) | *p; | 949 | v = (v << 8) | *p; | |
950 | *vp = v; | 950 | *vp = v; | |
951 | sc->sc_in_offset += sizeof(v); | 951 | sc->sc_in_offset += sizeof(v); | |
952 | sc->sc_in_len -= sizeof(v); | 952 | sc->sc_in_len -= sizeof(v); | |
953 | return 0; | 953 | return 0; | |
954 | } | 954 | } | |
955 | 955 | |||
956 | static __inline int | 956 | static __inline int | |
957 | utoppy_get_string(struct utoppy_softc *sc, char *str, size_t len) | 957 | utoppy_get_string(struct utoppy_softc *sc, char *str, size_t len) | |
958 | { | 958 | { | |
959 | char *p; | 959 | char *p; | |
960 | 960 | |||
961 | if (sc->sc_in_len < len) | 961 | if (sc->sc_in_len < len) | |
962 | return 1; | 962 | return 1; | |
963 | 963 | |||
964 | memset(str, 0, len); | 964 | memset(str, 0, len); | |
965 | p = UTOPPY_IN_DATA(sc); | 965 | p = UTOPPY_IN_DATA(sc); | |
966 | strncpy(str, p, len); | 966 | strncpy(str, p, len); | |
967 | sc->sc_in_offset += len; | 967 | sc->sc_in_offset += len; | |
968 | sc->sc_in_len -= len; | 968 | sc->sc_in_len -= len; | |
969 | return 0; | 969 | return 0; | |
970 | } | 970 | } | |
971 | 971 | |||
972 | static int | 972 | static int | |
973 | utoppy_command(struct utoppy_softc *sc, uint16_t cmd, int timeout, | 973 | utoppy_command(struct utoppy_softc *sc, uint16_t cmd, int timeout, | |
974 | uint16_t *presp) | 974 | uint16_t *presp) | |
975 | { | 975 | { | |
976 | int err; | 976 | int err; | |
977 | 977 | |||
978 | err = utoppy_send_packet(sc, cmd, timeout); | 978 | err = utoppy_send_packet(sc, cmd, timeout); | |
979 | if (err) | 979 | if (err) | |
980 | return err; | 980 | return err; | |
981 | 981 | |||
982 | err = utoppy_recv_packet(sc, presp, timeout); | 982 | err = utoppy_recv_packet(sc, presp, timeout); | |
983 | if (err == EBADMSG) { | 983 | if (err == EBADMSG) { | |
984 | UTOPPY_OUT_INIT(sc); | 984 | UTOPPY_OUT_INIT(sc); | |
985 | utoppy_send_packet(sc, UTOPPY_RESP_ERROR, timeout); | 985 | utoppy_send_packet(sc, UTOPPY_RESP_ERROR, timeout); | |
986 | } | 986 | } | |
987 | 987 | |||
988 | return err; | 988 | return err; | |
989 | } | 989 | } | |
990 | 990 | |||
991 | static int | 991 | static int | |
992 | utoppy_timestamp_decode(struct utoppy_softc *sc, time_t *tp) | 992 | utoppy_timestamp_decode(struct utoppy_softc *sc, time_t *tp) | |
993 | { | 993 | { | |
994 | uint16_t mjd; | 994 | uint16_t mjd; | |
995 | uint8_t hour, minute, sec; | 995 | uint8_t hour, minute, sec; | |
996 | uint32_t rv; | 996 | uint32_t rv; | |
997 | 997 | |||
998 | if (utoppy_get_16(sc, &mjd) || utoppy_get_8(sc, &hour) || | 998 | if (utoppy_get_16(sc, &mjd) || utoppy_get_8(sc, &hour) || | |
999 | utoppy_get_8(sc, &minute) || utoppy_get_8(sc, &sec)) | 999 | utoppy_get_8(sc, &minute) || utoppy_get_8(sc, &sec)) | |
1000 | return 1; | 1000 | return 1; | |
1001 | 1001 | |||
1002 | if (mjd == 0xffffu && hour == 0xffu && minute == 0xffu && sec == 0xffu){ | 1002 | if (mjd == 0xffffu && hour == 0xffu && minute == 0xffu && sec == 0xffu){ | |
1003 | *tp = 0; | 1003 | *tp = 0; | |
1004 | return 0; | 1004 | return 0; | |
1005 | } | 1005 | } | |
1006 | 1006 | |||
1007 | rv = (mjd < UTOPPY_MJD_1970) ? UTOPPY_MJD_1970 : (uint32_t) mjd; | 1007 | rv = (mjd < UTOPPY_MJD_1970) ? UTOPPY_MJD_1970 : (uint32_t) mjd; | |
1008 | 1008 | |||
1009 | /* Calculate seconds since 1970 */ | 1009 | /* Calculate seconds since 1970 */ | |
1010 | rv = (rv - UTOPPY_MJD_1970) * 60 * 60 * 24; | 1010 | rv = (rv - UTOPPY_MJD_1970) * 60 * 60 * 24; | |
1011 | 1011 | |||
1012 | /* Add in the hours, minutes, and seconds */ | 1012 | /* Add in the hours, minutes, and seconds */ | |
1013 | rv += (uint32_t)hour * 60 * 60; | 1013 | rv += (uint32_t)hour * 60 * 60; | |
1014 | rv += (uint32_t)minute * 60; | 1014 | rv += (uint32_t)minute * 60; | |
1015 | rv += sec; | 1015 | rv += sec; | |
1016 | *tp = (time_t)rv; | 1016 | *tp = (time_t)rv; | |
1017 | 1017 | |||
1018 | return 0; | 1018 | return 0; | |
1019 | } | 1019 | } | |
1020 | 1020 | |||
1021 | static void | 1021 | static void | |
1022 | utoppy_timestamp_encode(struct utoppy_softc *sc, time_t t) | 1022 | utoppy_timestamp_encode(struct utoppy_softc *sc, time_t t) | |
1023 | { | 1023 | { | |
1024 | u_int mjd, hour, minute; | 1024 | u_int mjd, hour, minute; | |
1025 | 1025 | |||
1026 | mjd = t / (60 * 60 * 24); | 1026 | mjd = t / (60 * 60 * 24); | |
1027 | t -= mjd * 60 * 60 * 24; | 1027 | t -= mjd * 60 * 60 * 24; | |
1028 | 1028 | |||
1029 | hour = t / (60 * 60); | 1029 | hour = t / (60 * 60); | |
1030 | t -= hour * 60 * 60; | 1030 | t -= hour * 60 * 60; | |
1031 | 1031 | |||
1032 | minute = t / 60; | 1032 | minute = t / 60; | |
1033 | t -= minute * 60; | 1033 | t -= minute * 60; | |
1034 | 1034 | |||
1035 | utoppy_add_16(sc, mjd + UTOPPY_MJD_1970); | 1035 | utoppy_add_16(sc, mjd + UTOPPY_MJD_1970); | |
1036 | utoppy_add_8(sc, hour); | 1036 | utoppy_add_8(sc, hour); | |
1037 | utoppy_add_8(sc, minute); | 1037 | utoppy_add_8(sc, minute); | |
1038 | utoppy_add_8(sc, t); | 1038 | utoppy_add_8(sc, t); | |
1039 | } | 1039 | } | |
1040 | 1040 | |||
1041 | static int | 1041 | static int | |
1042 | utoppy_turbo_mode(struct utoppy_softc *sc, int state) | 1042 | utoppy_turbo_mode(struct utoppy_softc *sc, int state) | |
1043 | { | 1043 | { | |
1044 | uint16_t r; | 1044 | uint16_t r; | |
1045 | int err; | 1045 | int err; | |
1046 | 1046 | |||
1047 | UTOPPY_OUT_INIT(sc); | 1047 | UTOPPY_OUT_INIT(sc); | |
1048 | utoppy_add_32(sc, state); | 1048 | utoppy_add_32(sc, state); | |
1049 | 1049 | |||
1050 | err = utoppy_command(sc, UTOPPY_CMD_TURBO, UTOPPY_SHORT_TIMEOUT, &r); | 1050 | err = utoppy_command(sc, UTOPPY_CMD_TURBO, UTOPPY_SHORT_TIMEOUT, &r); | |
1051 | if (err) | 1051 | if (err) | |
1052 | return err; | 1052 | return err; | |
1053 | 1053 | |||
1054 | return (r == UTOPPY_RESP_SUCCESS) ? 0 : EIO; | 1054 | return (r == UTOPPY_RESP_SUCCESS) ? 0 : EIO; | |
1055 | } | 1055 | } | |
1056 | 1056 | |||
1057 | static int | 1057 | static int | |
1058 | utoppy_check_ready(struct utoppy_softc *sc) | 1058 | utoppy_check_ready(struct utoppy_softc *sc) | |
1059 | { | 1059 | { | |
1060 | uint16_t r; | 1060 | uint16_t r; | |
1061 | int err; | 1061 | int err; | |
1062 | 1062 | |||
1063 | UTOPPY_OUT_INIT(sc); | 1063 | UTOPPY_OUT_INIT(sc); | |
1064 | 1064 | |||
1065 | err = utoppy_command(sc, UTOPPY_CMD_READY, UTOPPY_LONG_TIMEOUT, &r); | 1065 | err = utoppy_command(sc, UTOPPY_CMD_READY, UTOPPY_LONG_TIMEOUT, &r); | |
1066 | if (err) | 1066 | if (err) | |
1067 | return err; | 1067 | return err; | |
1068 | 1068 | |||
1069 | return (r == UTOPPY_RESP_SUCCESS) ? 0 : EIO; | 1069 | return (r == UTOPPY_RESP_SUCCESS) ? 0 : EIO; | |
1070 | } | 1070 | } | |
1071 | 1071 | |||
1072 | static int | 1072 | static int | |
1073 | utoppy_cancel(struct utoppy_softc *sc) | 1073 | utoppy_cancel(struct utoppy_softc *sc) | |
1074 | { | 1074 | { | |
1075 | uint16_t r; | 1075 | uint16_t r; | |
1076 | int err, i; | 1076 | int err, i; | |
1077 | 1077 | |||
1078 | /* | 1078 | /* | |
1079 | * Issue the cancel command serveral times. the Toppy doesn't | 1079 | * Issue the cancel command serveral times. the Toppy doesn't | |
1080 | * always respond to the first. | 1080 | * always respond to the first. | |
1081 | */ | 1081 | */ | |
1082 | for (i = 0; i < 3; i++) { | 1082 | for (i = 0; i < 3; i++) { | |
1083 | UTOPPY_OUT_INIT(sc); | 1083 | UTOPPY_OUT_INIT(sc); | |
1084 | err = utoppy_command(sc, UTOPPY_CMD_CANCEL, | 1084 | err = utoppy_command(sc, UTOPPY_CMD_CANCEL, | |
1085 | UTOPPY_SHORT_TIMEOUT, &r); | 1085 | UTOPPY_SHORT_TIMEOUT, &r); | |
1086 | if (err == 0 && r == UTOPPY_RESP_SUCCESS) | 1086 | if (err == 0 && r == UTOPPY_RESP_SUCCESS) | |
1087 | break; | 1087 | break; | |
1088 | err = ETIMEDOUT; | 1088 | err = ETIMEDOUT; | |
1089 | } | 1089 | } | |
1090 | 1090 | |||
1091 | if (err) | 1091 | if (err) | |
1092 | return err; | 1092 | return err; | |
1093 | 1093 | |||
1094 | /* | 1094 | /* | |
1095 | * Make sure turbo mode is off, otherwise the Toppy will not | 1095 | * Make sure turbo mode is off, otherwise the Toppy will not | |
1096 | * respond to remote control input. | 1096 | * respond to remote control input. | |
1097 | */ | 1097 | */ | |
1098 | (void) utoppy_turbo_mode(sc, 0); | 1098 | (void) utoppy_turbo_mode(sc, 0); | |
1099 | 1099 | |||
1100 | sc->sc_state = UTOPPY_STATE_IDLE; | 1100 | sc->sc_state = UTOPPY_STATE_IDLE; | |
1101 | return 0; | 1101 | return 0; | |
1102 | } | 1102 | } | |
1103 | 1103 | |||
1104 | static int | 1104 | static int | |
1105 | utoppy_stats(struct utoppy_softc *sc, struct utoppy_stats *us) | 1105 | utoppy_stats(struct utoppy_softc *sc, struct utoppy_stats *us) | |
1106 | { | 1106 | { | |
1107 | uint32_t hsize, hfree; | 1107 | uint32_t hsize, hfree; | |
1108 | uint16_t r; | 1108 | uint16_t r; | |
1109 | int err; | 1109 | int err; | |
1110 | 1110 | |||
1111 | UTOPPY_OUT_INIT(sc); | 1111 | UTOPPY_OUT_INIT(sc); | |
1112 | err = utoppy_command(sc, UTOPPY_CMD_STATS, UTOPPY_LONG_TIMEOUT, &r); | 1112 | err = utoppy_command(sc, UTOPPY_CMD_STATS, UTOPPY_LONG_TIMEOUT, &r); | |
1113 | if (err) | 1113 | if (err) | |
1114 | return err; | 1114 | return err; | |
1115 | 1115 | |||
1116 | if (r != UTOPPY_RESP_STATS_DATA) | 1116 | if (r != UTOPPY_RESP_STATS_DATA) | |
1117 | return EIO; | 1117 | return EIO; | |
1118 | 1118 | |||
1119 | if (utoppy_get_32(sc, &hsize) || utoppy_get_32(sc, &hfree)) | 1119 | if (utoppy_get_32(sc, &hsize) || utoppy_get_32(sc, &hfree)) | |
1120 | return EIO; | 1120 | return EIO; | |
1121 | 1121 | |||
1122 | us->us_hdd_size = hsize; | 1122 | us->us_hdd_size = hsize; | |
1123 | us->us_hdd_size *= 1024; | 1123 | us->us_hdd_size *= 1024; | |
1124 | us->us_hdd_free = hfree; | 1124 | us->us_hdd_free = hfree; | |
1125 | us->us_hdd_free *= 1024; | 1125 | us->us_hdd_free *= 1024; | |
1126 | 1126 | |||
1127 | return 0; | 1127 | return 0; | |
1128 | } | 1128 | } | |
1129 | 1129 | |||
1130 | static int | 1130 | static int | |
1131 | utoppy_readdir_next(struct utoppy_softc *sc) | 1131 | utoppy_readdir_next(struct utoppy_softc *sc) | |
1132 | { | 1132 | { | |
1133 | uint16_t resp; | 1133 | uint16_t resp; | |
1134 | int err; | 1134 | int err; | |
1135 | 1135 | |||
1136 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: running...\n", | 1136 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: running...\n", | |
1137 | device_xname(sc->sc_dev))); | 1137 | device_xname(sc->sc_dev))); | |
1138 | 1138 | |||
1139 | /* | 1139 | /* | |
1140 | * Fetch the next READDIR response | 1140 | * Fetch the next READDIR response | |
1141 | */ | 1141 | */ | |
1142 | err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT); | 1142 | err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT); | |
1143 | if (err) { | 1143 | if (err) { | |
1144 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | 1144 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | |
1145 | "utoppy_recv_packet() returned %d\n", | 1145 | "utoppy_recv_packet() returned %d\n", | |
1146 | device_xname(sc->sc_dev), err)); | 1146 | device_xname(sc->sc_dev), err)); | |
1147 | if (err == EBADMSG) { | 1147 | if (err == EBADMSG) { | |
1148 | UTOPPY_OUT_INIT(sc); | 1148 | UTOPPY_OUT_INIT(sc); | |
1149 | utoppy_send_packet(sc, UTOPPY_RESP_ERROR, | 1149 | utoppy_send_packet(sc, UTOPPY_RESP_ERROR, | |
1150 | UTOPPY_LONG_TIMEOUT); | 1150 | UTOPPY_LONG_TIMEOUT); | |
1151 | } | 1151 | } | |
1152 | utoppy_cancel(sc); | 1152 | utoppy_cancel(sc); | |
1153 | return err; | 1153 | return err; | |
1154 | } | 1154 | } | |
1155 | 1155 | |||
1156 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | 1156 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | |
1157 | "utoppy_recv_packet() returned %d, len %ld\n", | 1157 | "utoppy_recv_packet() returned %d, len %ld\n", | |
1158 | device_xname(sc->sc_dev), err, (u_long)sc->sc_in_len)); | 1158 | device_xname(sc->sc_dev), err, (u_long)sc->sc_in_len)); | |
1159 | 1159 | |||
1160 | switch (resp) { | 1160 | switch (resp) { | |
1161 | case UTOPPY_RESP_READDIR_DATA: | 1161 | case UTOPPY_RESP_READDIR_DATA: | |
1162 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | 1162 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | |
1163 | "UTOPPY_RESP_READDIR_DATA\n", device_xname(sc->sc_dev))); | 1163 | "UTOPPY_RESP_READDIR_DATA\n", device_xname(sc->sc_dev))); | |
1164 | 1164 | |||
1165 | UTOPPY_OUT_INIT(sc); | 1165 | UTOPPY_OUT_INIT(sc); | |
1166 | err = utoppy_send_packet(sc, UTOPPY_CMD_ACK, | 1166 | err = utoppy_send_packet(sc, UTOPPY_CMD_ACK, | |
1167 | UTOPPY_LONG_TIMEOUT); | 1167 | UTOPPY_LONG_TIMEOUT); | |
1168 | if (err) { | 1168 | if (err) { | |
1169 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | 1169 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | |
1170 | "utoppy_send_packet(ACK) returned %d\n", | 1170 | "utoppy_send_packet(ACK) returned %d\n", | |
1171 | device_xname(sc->sc_dev), err)); | 1171 | device_xname(sc->sc_dev), err)); | |
1172 | utoppy_cancel(sc); | 1172 | utoppy_cancel(sc); | |
1173 | return err; | 1173 | return err; | |
1174 | } | 1174 | } | |
1175 | sc->sc_state = UTOPPY_STATE_READDIR; | 1175 | sc->sc_state = UTOPPY_STATE_READDIR; | |
1176 | sc->sc_in_offset = 0; | 1176 | sc->sc_in_offset = 0; | |
1177 | break; | 1177 | break; | |
1178 | 1178 | |||
1179 | case UTOPPY_RESP_READDIR_END: | 1179 | case UTOPPY_RESP_READDIR_END: | |
1180 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | 1180 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | |
1181 | "UTOPPY_RESP_READDIR_END\n", device_xname(sc->sc_dev))); | 1181 | "UTOPPY_RESP_READDIR_END\n", device_xname(sc->sc_dev))); | |
1182 | 1182 | |||
1183 | UTOPPY_OUT_INIT(sc); | 1183 | UTOPPY_OUT_INIT(sc); | |
1184 | utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT); | 1184 | utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT); | |
1185 | sc->sc_state = UTOPPY_STATE_IDLE; | 1185 | sc->sc_state = UTOPPY_STATE_IDLE; | |
1186 | sc->sc_in_len = 0; | 1186 | sc->sc_in_len = 0; | |
1187 | break; | 1187 | break; | |
1188 | 1188 | |||
1189 | default: | 1189 | default: | |
1190 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | 1190 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " | |
1191 | "bad response: %#x\n", device_xname(sc->sc_dev), resp)); | 1191 | "bad response: %#x\n", device_xname(sc->sc_dev), resp)); | |
1192 | sc->sc_state = UTOPPY_STATE_IDLE; | 1192 | sc->sc_state = UTOPPY_STATE_IDLE; | |
1193 | sc->sc_in_len = 0; | 1193 | sc->sc_in_len = 0; | |
1194 | return EIO; | 1194 | return EIO; | |
1195 | } | 1195 | } | |
1196 | 1196 | |||
1197 | return 0; | 1197 | return 0; | |
1198 | } | 1198 | } | |
1199 | 1199 | |||
1200 | static size_t | 1200 | static size_t | |
1201 | utoppy_readdir_decode(struct utoppy_softc *sc, struct utoppy_dirent *ud) | 1201 | utoppy_readdir_decode(struct utoppy_softc *sc, struct utoppy_dirent *ud) | |
1202 | { | 1202 | { | |
1203 | uint8_t ftype; | 1203 | uint8_t ftype; | |
1204 | 1204 | |||
1205 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: bytes left" | 1205 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: bytes left" | |
1206 | " %d\n", device_xname(sc->sc_dev), (int)sc->sc_in_len)); | 1206 | " %d\n", device_xname(sc->sc_dev), (int)sc->sc_in_len)); | |
1207 | 1207 | |||
1208 | if (utoppy_timestamp_decode(sc, &ud->ud_mtime) || | 1208 | if (utoppy_timestamp_decode(sc, &ud->ud_mtime) || | |
1209 | utoppy_get_8(sc, &ftype) || utoppy_get_64(sc, &ud->ud_size) || | 1209 | utoppy_get_8(sc, &ftype) || utoppy_get_64(sc, &ud->ud_size) || | |
1210 | utoppy_get_string(sc, ud->ud_path, UTOPPY_MAX_FILENAME_LEN + 1) || | 1210 | utoppy_get_string(sc, ud->ud_path, UTOPPY_MAX_FILENAME_LEN + 1) || | |
1211 | utoppy_get_32(sc, &ud->ud_attributes)) { | 1211 | utoppy_get_32(sc, &ud->ud_attributes)) { | |
1212 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: no " | 1212 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: no " | |
1213 | "more to decode\n", device_xname(sc->sc_dev))); | 1213 | "more to decode\n", device_xname(sc->sc_dev))); | |
1214 | return 0; | 1214 | return 0; | |
1215 | } | 1215 | } | |
1216 | 1216 | |||
1217 | switch (ftype) { | 1217 | switch (ftype) { | |
1218 | case UTOPPY_FTYPE_DIR: | 1218 | case UTOPPY_FTYPE_DIR: | |
1219 | ud->ud_type = UTOPPY_DIRENT_DIRECTORY; | 1219 | ud->ud_type = UTOPPY_DIRENT_DIRECTORY; | |
1220 | break; | 1220 | break; | |
1221 | case UTOPPY_FTYPE_FILE: | 1221 | case UTOPPY_FTYPE_FILE: | |
1222 | ud->ud_type = UTOPPY_DIRENT_FILE; | 1222 | ud->ud_type = UTOPPY_DIRENT_FILE; | |
1223 | break; | 1223 | break; | |
1224 | default: | 1224 | default: | |
1225 | ud->ud_type = UTOPPY_DIRENT_UNKNOWN; | 1225 | ud->ud_type = UTOPPY_DIRENT_UNKNOWN; | |
1226 | break; | 1226 | break; | |
1227 | } | 1227 | } | |
1228 | 1228 | |||
1229 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: %s '%s', " | 1229 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: %s '%s', " | |
1230 | "size %lld, time 0x%08lx, attr 0x%08x\n", device_xname(sc->sc_dev), | 1230 | "size %lld, time 0x%08lx, attr 0x%08x\n", device_xname(sc->sc_dev), | |
1231 | (ftype == UTOPPY_FTYPE_DIR) ? "DIR" : | 1231 | (ftype == UTOPPY_FTYPE_DIR) ? "DIR" : | |
1232 | ((ftype == UTOPPY_FTYPE_FILE) ? "FILE" : "UNKNOWN"), ud->ud_path, | 1232 | ((ftype == UTOPPY_FTYPE_FILE) ? "FILE" : "UNKNOWN"), ud->ud_path, | |
1233 | ud->ud_size, (u_long)ud->ud_mtime, ud->ud_attributes)); | 1233 | ud->ud_size, (u_long)ud->ud_mtime, ud->ud_attributes)); | |
1234 | 1234 | |||
1235 | return 1; | 1235 | return 1; | |
1236 | } | 1236 | } | |
1237 | 1237 | |||
1238 | static int | 1238 | static int | |
1239 | utoppy_readfile_next(struct utoppy_softc *sc) | 1239 | utoppy_readfile_next(struct utoppy_softc *sc) | |
1240 | { | 1240 | { | |
1241 | uint64_t off; | 1241 | uint64_t off; | |
1242 | uint16_t resp; | 1242 | uint16_t resp; | |
1243 | int err; | 1243 | int err; | |
1244 | 1244 | |||
1245 | err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT); | 1245 | err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT); | |
1246 | if (err) { | 1246 | if (err) { | |
1247 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | 1247 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | |
1248 | "utoppy_recv_packet() returned %d\n", | 1248 | "utoppy_recv_packet() returned %d\n", | |
1249 | device_xname(sc->sc_dev), err)); | 1249 | device_xname(sc->sc_dev), err)); | |
1250 | utoppy_cancel(sc); | 1250 | utoppy_cancel(sc); | |
1251 | return err; | 1251 | return err; | |
1252 | } | 1252 | } | |
1253 | 1253 | |||
1254 | switch (resp) { | 1254 | switch (resp) { | |
1255 | case UTOPPY_RESP_FILE_HEADER: | 1255 | case UTOPPY_RESP_FILE_HEADER: | |
1256 | /* ACK it */ | 1256 | /* ACK it */ | |
1257 | UTOPPY_OUT_INIT(sc); | 1257 | UTOPPY_OUT_INIT(sc); | |
1258 | err = utoppy_send_packet(sc, UTOPPY_CMD_ACK, | 1258 | err = utoppy_send_packet(sc, UTOPPY_CMD_ACK, | |
1259 | UTOPPY_LONG_TIMEOUT); | 1259 | UTOPPY_LONG_TIMEOUT); | |
1260 | if (err) { | 1260 | if (err) { | |
1261 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | 1261 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | |
1262 | "utoppy_send_packet(UTOPPY_CMD_ACK) returned %d\n", | 1262 | "utoppy_send_packet(UTOPPY_CMD_ACK) returned %d\n", | |
1263 | device_xname(sc->sc_dev), err)); | 1263 | device_xname(sc->sc_dev), err)); | |
1264 | utoppy_cancel(sc); | 1264 | utoppy_cancel(sc); | |
1265 | return err; | 1265 | return err; | |
1266 | } | 1266 | } | |
1267 | 1267 | |||
1268 | sc->sc_in_len = 0; | 1268 | sc->sc_in_len = 0; | |
1269 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | 1269 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | |
1270 | "FILE_HEADER done\n", device_xname(sc->sc_dev))); | 1270 | "FILE_HEADER done\n", device_xname(sc->sc_dev))); | |
1271 | break; | 1271 | break; | |
1272 | 1272 | |||
1273 | case UTOPPY_RESP_FILE_DATA: | 1273 | case UTOPPY_RESP_FILE_DATA: | |
1274 | /* Already ACK'd */ | 1274 | /* Already ACK'd */ | |
1275 | if (utoppy_get_64(sc, &off)) { | 1275 | if (utoppy_get_64(sc, &off)) { | |
1276 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | 1276 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | |
1277 | "UTOPPY_RESP_FILE_DATA did not provide offset\n", | 1277 | "UTOPPY_RESP_FILE_DATA did not provide offset\n", | |
1278 | device_xname(sc->sc_dev))); | 1278 | device_xname(sc->sc_dev))); | |
1279 | utoppy_cancel(sc); | 1279 | utoppy_cancel(sc); | |
1280 | return EBADMSG; | 1280 | return EBADMSG; | |
1281 | } | 1281 | } | |
1282 | 1282 | |||
1283 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | 1283 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | |
1284 | "UTOPPY_RESP_FILE_DATA: offset %lld, bytes left %ld\n", | 1284 | "UTOPPY_RESP_FILE_DATA: offset %lld, bytes left %ld\n", | |
1285 | device_xname(sc->sc_dev), off, (u_long)sc->sc_in_len)); | 1285 | device_xname(sc->sc_dev), off, (u_long)sc->sc_in_len)); | |
1286 | break; | 1286 | break; | |
1287 | 1287 | |||
1288 | case UTOPPY_RESP_FILE_END: | 1288 | case UTOPPY_RESP_FILE_END: | |
1289 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | 1289 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " | |
1290 | "UTOPPY_RESP_FILE_END: sending ACK\n", | 1290 | "UTOPPY_RESP_FILE_END: sending ACK\n", | |
1291 | device_xname(sc->sc_dev))); | 1291 | device_xname(sc->sc_dev))); | |
1292 | UTOPPY_OUT_INIT(sc); | 1292 | UTOPPY_OUT_INIT(sc); | |
1293 | utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT); | 1293 | utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT); | |
1294 | /*FALLTHROUGH*/ | 1294 | /*FALLTHROUGH*/ | |
1295 | 1295 | |||
1296 | case UTOPPY_RESP_SUCCESS: | 1296 | case UTOPPY_RESP_SUCCESS: | |
1297 | sc->sc_state = UTOPPY_STATE_IDLE; | 1297 | sc->sc_state = UTOPPY_STATE_IDLE; | |
1298 | (void) utoppy_turbo_mode(sc, 0); | 1298 | (void) utoppy_turbo_mode(sc, 0); | |
1299 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: all " | 1299 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: all " | |
1300 | "done\n", device_xname(sc->sc_dev))); | 1300 | "done\n", device_xname(sc->sc_dev))); | |
1301 | break; | 1301 | break; | |
1302 | 1302 | |||
1303 | case UTOPPY_RESP_ERROR: | 1303 | case UTOPPY_RESP_ERROR: | |
1304 | default: | 1304 | default: | |
1305 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: bad " | 1305 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: bad " | |
1306 | "response code 0x%0x\n", device_xname(sc->sc_dev), resp)); | 1306 | "response code 0x%0x\n", device_xname(sc->sc_dev), resp)); | |
1307 | utoppy_cancel(sc); | 1307 | utoppy_cancel(sc); | |
1308 | return EIO; | 1308 | return EIO; | |
1309 | } | 1309 | } | |
1310 | 1310 | |||
1311 | return 0; | 1311 | return 0; | |
1312 | } | 1312 | } | |
1313 | 1313 | |||
1314 | static int | 1314 | static int | |
1315 | utoppyopen(dev_t dev, int flag, int mode, | 1315 | utoppyopen(dev_t dev, int flag, int mode, | |
1316 | struct lwp *l) | 1316 | struct lwp *l) | |
1317 | { | 1317 | { | |
1318 | struct utoppy_softc *sc; | 1318 | struct utoppy_softc *sc; | |
1319 | int error = 0; | 1319 | int error = 0; | |
1320 | 1320 | |||
1321 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | 1321 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | |
1322 | if (sc == NULL) | 1322 | if (sc == NULL) | |
1323 | return ENXIO; | 1323 | return ENXIO; | |
1324 | 1324 | |||
1325 | if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying) | 1325 | if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying) | |
1326 | return ENXIO; | 1326 | return ENXIO; | |
1327 | 1327 | |||
1328 | if (sc->sc_state != UTOPPY_STATE_CLOSED) { | 1328 | if (sc->sc_state != UTOPPY_STATE_CLOSED) { | |
1329 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: already open\n", | 1329 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: already open\n", | |
1330 | device_xname(sc->sc_dev))); | 1330 | device_xname(sc->sc_dev))); | |
1331 | return EBUSY; | 1331 | return EBUSY; | |
1332 | } | 1332 | } | |
1333 | 1333 | |||
1334 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: opening...\n", | 1334 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: opening...\n", | |
1335 | device_xname(sc->sc_dev))); | 1335 | device_xname(sc->sc_dev))); | |
1336 | 1336 | |||
1337 | sc->sc_refcnt++; | 1337 | sc->sc_refcnt++; | |
1338 | sc->sc_state = UTOPPY_STATE_OPENING; | 1338 | sc->sc_state = UTOPPY_STATE_OPENING; | |
1339 | sc->sc_turbo_mode = 0; | 1339 | sc->sc_turbo_mode = 0; | |
1340 | sc->sc_out_data = kmem_alloc(UTOPPY_BSIZE + 1, KM_SLEEP); | 1340 | sc->sc_out_data = kmem_alloc(UTOPPY_BSIZE + 1, KM_SLEEP); | |
1341 | sc->sc_in_data = kmem_alloc(UTOPPY_BSIZE + 1, KM_SLEEP); | 1341 | sc->sc_in_data = kmem_alloc(UTOPPY_BSIZE + 1, KM_SLEEP); | |
1342 | 1342 | |||
1343 | if ((error = utoppy_cancel(sc)) != 0) | 1343 | if ((error = utoppy_cancel(sc)) != 0) | |
1344 | goto error; | 1344 | goto error; | |
1345 | 1345 | |||
1346 | if ((error = utoppy_check_ready(sc)) != 0) { | 1346 | if ((error = utoppy_check_ready(sc)) != 0) { | |
1347 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: utoppy_check_ready()" | 1347 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: utoppy_check_ready()" | |
1348 | " returned %d\n", device_xname(sc->sc_dev), error)); | 1348 | " returned %d\n", device_xname(sc->sc_dev), error)); | |
1349 | } | 1349 | } | |
1350 | 1350 | |||
1351 | error: | 1351 | error: | |
1352 | sc->sc_state = error ? UTOPPY_STATE_CLOSED : UTOPPY_STATE_IDLE; | 1352 | sc->sc_state = error ? UTOPPY_STATE_CLOSED : UTOPPY_STATE_IDLE; | |
1353 | 1353 | |||
1354 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: done. error %d, new state " | 1354 | DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: done. error %d, new state " | |
1355 | "'%s'\n", device_xname(sc->sc_dev), error, | 1355 | "'%s'\n", device_xname(sc->sc_dev), error, | |
1356 | utoppy_state_string(sc->sc_state))); | 1356 | utoppy_state_string(sc->sc_state))); | |
1357 | 1357 | |||
1358 | if (--sc->sc_refcnt < 0) | 1358 | if (--sc->sc_refcnt < 0) | |
1359 | usb_detach_wakeupold(sc->sc_dev); | 1359 | usb_detach_wakeupold(sc->sc_dev); | |
1360 | 1360 | |||
1361 | return error; | 1361 | return error; | |
1362 | } | 1362 | } | |
1363 | 1363 | |||
1364 | static int | 1364 | static int | |
1365 | utoppyclose(dev_t dev, int flag, int mode, struct lwp *l) | 1365 | utoppyclose(dev_t dev, int flag, int mode, struct lwp *l) | |
1366 | { | 1366 | { | |
1367 | struct utoppy_softc *sc; | 1367 | struct utoppy_softc *sc; | |
1368 | usbd_status err; | |||
1369 | 1368 | |||
1370 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | 1369 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | |
1371 | 1370 | |||
1372 | DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: closing...\n", | 1371 | DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: closing...\n", | |
1373 | device_xname(sc->sc_dev))); | 1372 | device_xname(sc->sc_dev))); | |
1374 | 1373 | |||
1375 | if (sc->sc_state < UTOPPY_STATE_IDLE) { | 1374 | if (sc->sc_state < UTOPPY_STATE_IDLE) { | |
1376 | /* We are being forced to close before the open completed. */ | 1375 | /* We are being forced to close before the open completed. */ | |
1377 | DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: not properly " | 1376 | DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: not properly " | |
1378 | "open: %s\n", device_xname(sc->sc_dev), | 1377 | "open: %s\n", device_xname(sc->sc_dev), | |
1379 | utoppy_state_string(sc->sc_state))); | 1378 | utoppy_state_string(sc->sc_state))); | |
1380 | return 0; | 1379 | return 0; | |
1381 | } | 1380 | } | |
1382 | 1381 | |||
1383 | if (sc->sc_out_data) | 1382 | if (sc->sc_out_data) | |
1384 | (void) utoppy_cancel(sc); | 1383 | (void) utoppy_cancel(sc); | |
1385 | 1384 | |||
1386 | if (sc->sc_out_pipe != NULL) { | 1385 | if (sc->sc_out_pipe != NULL) { | |
1387 | if ((err = usbd_abort_pipe(sc->sc_out_pipe)) != 0) | 1386 | usbd_abort_pipe(sc->sc_out_pipe); | |
1388 | printf("usbd_abort_pipe(OUT) returned %d\n", err); | |||
1389 | sc->sc_out_pipe = NULL; | 1387 | sc->sc_out_pipe = NULL; | |
1390 | } | 1388 | } | |
1391 | 1389 | |||
1392 | if (sc->sc_in_pipe != NULL) { | 1390 | if (sc->sc_in_pipe != NULL) { | |
1393 | if ((err = usbd_abort_pipe(sc->sc_in_pipe)) != 0) | 1391 | usbd_abort_pipe(sc->sc_in_pipe); | |
1394 | printf("usbd_abort_pipe(IN) returned %d\n", err); | |||
1395 | sc->sc_in_pipe = NULL; | 1392 | sc->sc_in_pipe = NULL; | |
1396 | } | 1393 | } | |
1397 | 1394 | |||
1398 | if (sc->sc_out_data) { | 1395 | if (sc->sc_out_data) { | |
1399 | kmem_free(sc->sc_out_data, UTOPPY_BSIZE + 1); | 1396 | kmem_free(sc->sc_out_data, UTOPPY_BSIZE + 1); | |
1400 | sc->sc_out_data = NULL; | 1397 | sc->sc_out_data = NULL; | |
1401 | } | 1398 | } | |
1402 | 1399 | |||
1403 | if (sc->sc_in_data) { | 1400 | if (sc->sc_in_data) { | |
1404 | kmem_free(sc->sc_in_data, UTOPPY_BSIZE + 1); | 1401 | kmem_free(sc->sc_in_data, UTOPPY_BSIZE + 1); | |
1405 | sc->sc_in_data = NULL; | 1402 | sc->sc_in_data = NULL; | |
1406 | } | 1403 | } | |
1407 | 1404 | |||
1408 | sc->sc_state = UTOPPY_STATE_CLOSED; | 1405 | sc->sc_state = UTOPPY_STATE_CLOSED; | |
1409 | 1406 | |||
1410 | DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: done.\n", | 1407 | DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: done.\n", | |
1411 | device_xname(sc->sc_dev))); | 1408 | device_xname(sc->sc_dev))); | |
1412 | 1409 | |||
1413 | return 0; | 1410 | return 0; | |
1414 | } | 1411 | } | |
1415 | 1412 | |||
1416 | static int | 1413 | static int | |
1417 | utoppyread(dev_t dev, struct uio *uio, int flags) | 1414 | utoppyread(dev_t dev, struct uio *uio, int flags) | |
1418 | { | 1415 | { | |
1419 | struct utoppy_softc *sc; | 1416 | struct utoppy_softc *sc; | |
1420 | struct utoppy_dirent ud; | 1417 | struct utoppy_dirent ud; | |
1421 | size_t len; | 1418 | size_t len; | |
1422 | int err; | 1419 | int err; | |
1423 | 1420 | |||
1424 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | 1421 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | |
1425 | 1422 | |||
1426 | if (sc->sc_dying) | 1423 | if (sc->sc_dying) | |
1427 | return EIO; | 1424 | return EIO; | |
1428 | 1425 | |||
1429 | sc->sc_refcnt++; | 1426 | sc->sc_refcnt++; | |
1430 | 1427 | |||
1431 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: reading: state '%s'\n", | 1428 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: reading: state '%s'\n", | |
1432 | device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state))); | 1429 | device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state))); | |
1433 | 1430 | |||
1434 | switch (sc->sc_state) { | 1431 | switch (sc->sc_state) { | |
1435 | case UTOPPY_STATE_READDIR: | 1432 | case UTOPPY_STATE_READDIR: | |
1436 | err = 0; | 1433 | err = 0; | |
1437 | while (err == 0 && uio->uio_resid >= sizeof(ud) && | 1434 | while (err == 0 && uio->uio_resid >= sizeof(ud) && | |
1438 | sc->sc_state != UTOPPY_STATE_IDLE) { | 1435 | sc->sc_state != UTOPPY_STATE_IDLE) { | |
1439 | if (utoppy_readdir_decode(sc, &ud) == 0) | 1436 | if (utoppy_readdir_decode(sc, &ud) == 0) | |
1440 | err = utoppy_readdir_next(sc); | 1437 | err = utoppy_readdir_next(sc); | |
1441 | else | 1438 | else | |
1442 | if ((err = uiomove(&ud, sizeof(ud), uio)) != 0) | 1439 | if ((err = uiomove(&ud, sizeof(ud), uio)) != 0) | |
1443 | utoppy_cancel(sc); | 1440 | utoppy_cancel(sc); | |
1444 | } | 1441 | } | |
1445 | break; | 1442 | break; | |
1446 | 1443 | |||
1447 | case UTOPPY_STATE_READFILE: | 1444 | case UTOPPY_STATE_READFILE: | |
1448 | err = 0; | 1445 | err = 0; | |
1449 | while (err == 0 && uio->uio_resid > 0 && | 1446 | while (err == 0 && uio->uio_resid > 0 && | |
1450 | sc->sc_state != UTOPPY_STATE_IDLE) { | 1447 | sc->sc_state != UTOPPY_STATE_IDLE) { | |
1451 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: READFILE: " | 1448 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: READFILE: " | |
1452 | "resid %ld, bytes_left %ld\n", | 1449 | "resid %ld, bytes_left %ld\n", | |
1453 | device_xname(sc->sc_dev), (u_long)uio->uio_resid, | 1450 | device_xname(sc->sc_dev), (u_long)uio->uio_resid, | |
1454 | (u_long)sc->sc_in_len)); | 1451 | (u_long)sc->sc_in_len)); | |
1455 | 1452 | |||
1456 | if (sc->sc_in_len == 0 && | 1453 | if (sc->sc_in_len == 0 && | |
1457 | (err = utoppy_readfile_next(sc)) != 0) { | 1454 | (err = utoppy_readfile_next(sc)) != 0) { | |
1458 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: " | 1455 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: " | |
1459 | "READFILE: utoppy_readfile_next returned " | 1456 | "READFILE: utoppy_readfile_next returned " | |
1460 | "%d\n", device_xname(sc->sc_dev), err)); | 1457 | "%d\n", device_xname(sc->sc_dev), err)); | |
1461 | break; | 1458 | break; | |
1462 | } | 1459 | } | |
1463 | 1460 | |||
1464 | len = uimin(uio->uio_resid, sc->sc_in_len); | 1461 | len = uimin(uio->uio_resid, sc->sc_in_len); | |
1465 | if (len) { | 1462 | if (len) { | |
1466 | err = uiomove(UTOPPY_IN_DATA(sc), len, uio); | 1463 | err = uiomove(UTOPPY_IN_DATA(sc), len, uio); | |
1467 | if (err == 0) { | 1464 | if (err == 0) { | |
1468 | sc->sc_in_offset += len; | 1465 | sc->sc_in_offset += len; | |
1469 | sc->sc_in_len -= len; | 1466 | sc->sc_in_len -= len; | |
1470 | } | 1467 | } | |
1471 | } | 1468 | } | |
1472 | } | 1469 | } | |
1473 | break; | 1470 | break; | |
1474 | 1471 | |||
1475 | case UTOPPY_STATE_IDLE: | 1472 | case UTOPPY_STATE_IDLE: | |
1476 | err = 0; | 1473 | err = 0; | |
1477 | break; | 1474 | break; | |
1478 | 1475 | |||
1479 | case UTOPPY_STATE_WRITEFILE: | 1476 | case UTOPPY_STATE_WRITEFILE: | |
1480 | err = EBUSY; | 1477 | err = EBUSY; | |
1481 | break; | 1478 | break; | |
1482 | 1479 | |||
1483 | default: | 1480 | default: | |
1484 | err = EIO; | 1481 | err = EIO; | |
1485 | break; | 1482 | break; | |
1486 | } | 1483 | } | |
1487 | 1484 | |||
1488 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: done. err %d, state '%s'\n", | 1485 | DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: done. err %d, state '%s'\n", | |
1489 | device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state))); | 1486 | device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state))); | |
1490 | 1487 | |||
1491 | if (--sc->sc_refcnt < 0) | 1488 | if (--sc->sc_refcnt < 0) | |
1492 | usb_detach_wakeupold(sc->sc_dev); | 1489 | usb_detach_wakeupold(sc->sc_dev); | |
1493 | 1490 | |||
1494 | return err; | 1491 | return err; | |
1495 | } | 1492 | } | |
1496 | 1493 | |||
1497 | static int | 1494 | static int | |
1498 | utoppywrite(dev_t dev, struct uio *uio, int flags) | 1495 | utoppywrite(dev_t dev, struct uio *uio, int flags) | |
1499 | { | 1496 | { | |
1500 | struct utoppy_softc *sc; | 1497 | struct utoppy_softc *sc; | |
1501 | uint16_t resp; | 1498 | uint16_t resp; | |
1502 | size_t len; | 1499 | size_t len; | |
1503 | int err; | 1500 | int err; | |
1504 | 1501 | |||
1505 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | 1502 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | |
1506 | 1503 | |||
1507 | if (sc->sc_dying) | 1504 | if (sc->sc_dying) | |
1508 | return EIO; | 1505 | return EIO; | |
1509 | 1506 | |||
1510 | switch(sc->sc_state) { | 1507 | switch(sc->sc_state) { | |
1511 | case UTOPPY_STATE_WRITEFILE: | 1508 | case UTOPPY_STATE_WRITEFILE: | |
1512 | break; | 1509 | break; | |
1513 | 1510 | |||
1514 | case UTOPPY_STATE_IDLE: | 1511 | case UTOPPY_STATE_IDLE: | |
1515 | return 0; | 1512 | return 0; | |
1516 | 1513 | |||
1517 | default: | 1514 | default: | |
1518 | return EIO; | 1515 | return EIO; | |
1519 | } | 1516 | } | |
1520 | 1517 | |||
1521 | sc->sc_refcnt++; | 1518 | sc->sc_refcnt++; | |
1522 | err = 0; | 1519 | err = 0; | |
1523 | 1520 | |||
1524 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: PRE-WRITEFILE: resid " | 1521 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: PRE-WRITEFILE: resid " | |
1525 | "%ld, wr_size %lld, wr_offset %lld\n", device_xname(sc->sc_dev), | 1522 | "%ld, wr_size %lld, wr_offset %lld\n", device_xname(sc->sc_dev), | |
1526 | (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset)); | 1523 | (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset)); | |
1527 | 1524 | |||
1528 | while (sc->sc_state == UTOPPY_STATE_WRITEFILE && | 1525 | while (sc->sc_state == UTOPPY_STATE_WRITEFILE && | |
1529 | (len = uimin(uio->uio_resid, sc->sc_wr_size)) != 0) { | 1526 | (len = uimin(uio->uio_resid, sc->sc_wr_size)) != 0) { | |
1530 | 1527 | |||
1531 | len = uimin(len, UTOPPY_BSIZE - (UTOPPY_HEADER_SIZE + | 1528 | len = uimin(len, UTOPPY_BSIZE - (UTOPPY_HEADER_SIZE + | |
1532 | sizeof(uint64_t) + 3)); | 1529 | sizeof(uint64_t) + 3)); | |
1533 | 1530 | |||
1534 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove(%ld)\n", | 1531 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove(%ld)\n", | |
1535 | device_xname(sc->sc_dev), (u_long)len)); | 1532 | device_xname(sc->sc_dev), (u_long)len)); | |
1536 | 1533 | |||
1537 | UTOPPY_OUT_INIT(sc); | 1534 | UTOPPY_OUT_INIT(sc); | |
1538 | utoppy_add_64(sc, sc->sc_wr_offset); | 1535 | utoppy_add_64(sc, sc->sc_wr_offset); | |
1539 | 1536 | |||
1540 | err = uiomove(utoppy_current_ptr(sc->sc_out_data), len, uio); | 1537 | err = uiomove(utoppy_current_ptr(sc->sc_out_data), len, uio); | |
1541 | if (err) { | 1538 | if (err) { | |
1542 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove()" | 1539 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove()" | |
1543 | " returned %d\n", device_xname(sc->sc_dev), err)); | 1540 | " returned %d\n", device_xname(sc->sc_dev), err)); | |
1544 | break; | 1541 | break; | |
1545 | } | 1542 | } | |
1546 | 1543 | |||
1547 | utoppy_advance_ptr(sc->sc_out_data, len); | 1544 | utoppy_advance_ptr(sc->sc_out_data, len); | |
1548 | 1545 | |||
1549 | err = utoppy_command(sc, UTOPPY_RESP_FILE_DATA, | 1546 | err = utoppy_command(sc, UTOPPY_RESP_FILE_DATA, | |
1550 | UTOPPY_LONG_TIMEOUT, &resp); | 1547 | UTOPPY_LONG_TIMEOUT, &resp); | |
1551 | if (err) { | 1548 | if (err) { | |
1552 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: " | 1549 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: " | |
1553 | "utoppy_command(UTOPPY_RESP_FILE_DATA) " | 1550 | "utoppy_command(UTOPPY_RESP_FILE_DATA) " | |
1554 | "returned %d\n", device_xname(sc->sc_dev), err)); | 1551 | "returned %d\n", device_xname(sc->sc_dev), err)); | |
1555 | break; | 1552 | break; | |
1556 | } | 1553 | } | |
1557 | if (resp != UTOPPY_RESP_SUCCESS) { | 1554 | if (resp != UTOPPY_RESP_SUCCESS) { | |
1558 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: " | 1555 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: " | |
1559 | "utoppy_command(UTOPPY_RESP_FILE_DATA) returned " | 1556 | "utoppy_command(UTOPPY_RESP_FILE_DATA) returned " | |
1560 | "bad response %#x\n", device_xname(sc->sc_dev), | 1557 | "bad response %#x\n", device_xname(sc->sc_dev), | |
1561 | resp)); | 1558 | resp)); | |
1562 | utoppy_cancel(sc); | 1559 | utoppy_cancel(sc); | |
1563 | err = EIO; | 1560 | err = EIO; | |
1564 | break; | 1561 | break; | |
1565 | } | 1562 | } | |
1566 | 1563 | |||
1567 | sc->sc_wr_offset += len; | 1564 | sc->sc_wr_offset += len; | |
1568 | sc->sc_wr_size -= len; | 1565 | sc->sc_wr_size -= len; | |
1569 | } | 1566 | } | |
1570 | 1567 | |||
1571 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: POST-WRITEFILE: resid " | 1568 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: POST-WRITEFILE: resid " | |
1572 | "%ld, wr_size %lld, wr_offset %lld, err %d\n", | 1569 | "%ld, wr_size %lld, wr_offset %lld, err %d\n", | |
1573 | device_xname(sc->sc_dev), (u_long)uio->uio_resid, sc->sc_wr_size, | 1570 | device_xname(sc->sc_dev), (u_long)uio->uio_resid, sc->sc_wr_size, | |
1574 | sc->sc_wr_offset, err)); | 1571 | sc->sc_wr_offset, err)); | |
1575 | 1572 | |||
1576 | if (err == 0 && sc->sc_wr_size == 0) { | 1573 | if (err == 0 && sc->sc_wr_size == 0) { | |
1577 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: sending " | 1574 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: sending " | |
1578 | "FILE_END...\n", device_xname(sc->sc_dev))); | 1575 | "FILE_END...\n", device_xname(sc->sc_dev))); | |
1579 | UTOPPY_OUT_INIT(sc); | 1576 | UTOPPY_OUT_INIT(sc); | |
1580 | err = utoppy_command(sc, UTOPPY_RESP_FILE_END, | 1577 | err = utoppy_command(sc, UTOPPY_RESP_FILE_END, | |
1581 | UTOPPY_LONG_TIMEOUT, &resp); | 1578 | UTOPPY_LONG_TIMEOUT, &resp); | |
1582 | if (err) { | 1579 | if (err) { | |
1583 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: " | 1580 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: " | |
1584 | "utoppy_command(UTOPPY_RESP_FILE_END) returned " | 1581 | "utoppy_command(UTOPPY_RESP_FILE_END) returned " | |
1585 | "%d\n", device_xname(sc->sc_dev), err)); | 1582 | "%d\n", device_xname(sc->sc_dev), err)); | |
1586 | 1583 | |||
1587 | utoppy_cancel(sc); | 1584 | utoppy_cancel(sc); | |
1588 | } | 1585 | } | |
1589 | 1586 | |||
1590 | sc->sc_state = UTOPPY_STATE_IDLE; | 1587 | sc->sc_state = UTOPPY_STATE_IDLE; | |
1591 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: state %s\n", | 1588 | DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: state %s\n", | |
1592 | device_xname(sc->sc_dev), | 1589 | device_xname(sc->sc_dev), | |
1593 | utoppy_state_string(sc->sc_state))); | 1590 | utoppy_state_string(sc->sc_state))); | |
1594 | } | 1591 | } | |
1595 | 1592 | |||
1596 | if (--sc->sc_refcnt < 0) | 1593 | if (--sc->sc_refcnt < 0) | |
1597 | usb_detach_wakeupold(sc->sc_dev); | 1594 | usb_detach_wakeupold(sc->sc_dev); | |
1598 | 1595 | |||
1599 | return err; | 1596 | return err; | |
1600 | } | 1597 | } | |
1601 | 1598 | |||
1602 | static int | 1599 | static int | |
1603 | utoppyioctl(dev_t dev, u_long cmd, void *data, int flag, | 1600 | utoppyioctl(dev_t dev, u_long cmd, void *data, int flag, | |
1604 | struct lwp *l) | 1601 | struct lwp *l) | |
1605 | { | 1602 | { | |
1606 | struct utoppy_softc *sc; | 1603 | struct utoppy_softc *sc; | |
1607 | struct utoppy_rename *ur; | 1604 | struct utoppy_rename *ur; | |
1608 | struct utoppy_readfile *urf; | 1605 | struct utoppy_readfile *urf; | |
1609 | struct utoppy_writefile *uw; | 1606 | struct utoppy_writefile *uw; | |
1610 | char uwf[UTOPPY_MAX_FILENAME_LEN + 1], *uwfp; | 1607 | char uwf[UTOPPY_MAX_FILENAME_LEN + 1], *uwfp; | |
1611 | uint16_t resp; | 1608 | uint16_t resp; | |
1612 | int err; | 1609 | int err; | |
1613 | 1610 | |||
1614 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | 1611 | sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); | |
1615 | 1612 | |||
1616 | if (sc->sc_dying) | 1613 | if (sc->sc_dying) | |
1617 | return EIO; | 1614 | return EIO; | |
1618 | 1615 | |||
1619 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n", | 1616 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n", | |
1620 | device_xname(sc->sc_dev), cmd, utoppy_state_string(sc->sc_state))); | 1617 | device_xname(sc->sc_dev), cmd, utoppy_state_string(sc->sc_state))); | |
1621 | 1618 | |||
1622 | if (sc->sc_state != UTOPPY_STATE_IDLE && cmd != UTOPPYIOCANCEL) { | 1619 | if (sc->sc_state != UTOPPY_STATE_IDLE && cmd != UTOPPYIOCANCEL) { | |
1623 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: still busy.\n", | 1620 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: still busy.\n", | |
1624 | device_xname(sc->sc_dev))); | 1621 | device_xname(sc->sc_dev))); | |
1625 | return EBUSY; | 1622 | return EBUSY; | |
1626 | } | 1623 | } | |
1627 | 1624 | |||
1628 | sc->sc_refcnt++; | 1625 | sc->sc_refcnt++; | |
1629 | 1626 | |||
1630 | switch (cmd) { | 1627 | switch (cmd) { | |
1631 | case UTOPPYIOTURBO: | 1628 | case UTOPPYIOTURBO: | |
1632 | err = 0; | 1629 | err = 0; | |
1633 | sc->sc_turbo_mode = *((int *)data) ? 1 : 0; | 1630 | sc->sc_turbo_mode = *((int *)data) ? 1 : 0; | |
1634 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOTURBO: " | 1631 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOTURBO: " | |
1635 | "%s\n", device_xname(sc->sc_dev), | 1632 | "%s\n", device_xname(sc->sc_dev), | |
1636 | sc->sc_turbo_mode ? "On" : "Off")); | 1633 | sc->sc_turbo_mode ? "On" : "Off")); | |
1637 | break; | 1634 | break; | |
1638 | 1635 | |||
1639 | case UTOPPYIOCANCEL: | 1636 | case UTOPPYIOCANCEL: | |
1640 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOCANCEL\n", | 1637 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOCANCEL\n", | |
1641 | device_xname(sc->sc_dev))); | 1638 | device_xname(sc->sc_dev))); | |
1642 | err = utoppy_cancel(sc); | 1639 | err = utoppy_cancel(sc); | |
1643 | break; | 1640 | break; | |
1644 | 1641 | |||
1645 | case UTOPPYIOREBOOT: | 1642 | case UTOPPYIOREBOOT: | |
1646 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREBOOT\n", | 1643 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREBOOT\n", | |
1647 | device_xname(sc->sc_dev))); | 1644 | device_xname(sc->sc_dev))); | |
1648 | UTOPPY_OUT_INIT(sc); | 1645 | UTOPPY_OUT_INIT(sc); | |
1649 | err = utoppy_command(sc, UTOPPY_CMD_RESET, UTOPPY_LONG_TIMEOUT, | 1646 | err = utoppy_command(sc, UTOPPY_CMD_RESET, UTOPPY_LONG_TIMEOUT, | |
1650 | &resp); | 1647 | &resp); | |
1651 | if (err) | 1648 | if (err) | |
1652 | break; | 1649 | break; | |
1653 | 1650 | |||
1654 | if (resp != UTOPPY_RESP_SUCCESS) | 1651 | if (resp != UTOPPY_RESP_SUCCESS) | |
1655 | err = EIO; | 1652 | err = EIO; | |
1656 | break; | 1653 | break; | |
1657 | 1654 | |||
1658 | case UTOPPYIOSTATS: | 1655 | case UTOPPYIOSTATS: | |
1659 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOSTATS\n", | 1656 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOSTATS\n", | |
1660 | device_xname(sc->sc_dev))); | 1657 | device_xname(sc->sc_dev))); | |
1661 | err = utoppy_stats(sc, (struct utoppy_stats *)data); | 1658 | err = utoppy_stats(sc, (struct utoppy_stats *)data); | |
1662 | break; | 1659 | break; | |
1663 | 1660 | |||
1664 | case UTOPPYIORENAME: | 1661 | case UTOPPYIORENAME: | |
1665 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIORENAME\n", | 1662 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIORENAME\n", | |
1666 | device_xname(sc->sc_dev))); | 1663 | device_xname(sc->sc_dev))); | |
1667 | ur = (struct utoppy_rename *)data; | 1664 | ur = (struct utoppy_rename *)data; | |
1668 | UTOPPY_OUT_INIT(sc); | 1665 | UTOPPY_OUT_INIT(sc); | |
1669 | 1666 | |||
1670 | if ((err = utoppy_add_path(sc, ur->ur_old_path, 1)) != 0) | 1667 | if ((err = utoppy_add_path(sc, ur->ur_old_path, 1)) != 0) | |
1671 | break; | 1668 | break; | |
1672 | if ((err = utoppy_add_path(sc, ur->ur_new_path, 1)) != 0) | 1669 | if ((err = utoppy_add_path(sc, ur->ur_new_path, 1)) != 0) | |
1673 | break; | 1670 | break; | |
1674 | 1671 | |||
1675 | err = utoppy_command(sc, UTOPPY_CMD_RENAME, | 1672 | err = utoppy_command(sc, UTOPPY_CMD_RENAME, | |
1676 | UTOPPY_LONG_TIMEOUT, &resp); | 1673 | UTOPPY_LONG_TIMEOUT, &resp); | |
1677 | if (err) | 1674 | if (err) | |
1678 | break; | 1675 | break; | |
1679 | 1676 | |||
1680 | if (resp != UTOPPY_RESP_SUCCESS) | 1677 | if (resp != UTOPPY_RESP_SUCCESS) | |
1681 | err = EIO; | 1678 | err = EIO; | |
1682 | break; | 1679 | break; | |
1683 | 1680 | |||
1684 | case UTOPPYIOMKDIR: | 1681 | case UTOPPYIOMKDIR: | |
1685 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOMKDIR\n", | 1682 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOMKDIR\n", | |
1686 | device_xname(sc->sc_dev))); | 1683 | device_xname(sc->sc_dev))); | |
1687 | UTOPPY_OUT_INIT(sc); | 1684 | UTOPPY_OUT_INIT(sc); | |
1688 | err = utoppy_add_path(sc, *((const char **)data), 1); | 1685 | err = utoppy_add_path(sc, *((const char **)data), 1); | |
1689 | if (err) | 1686 | if (err) | |
1690 | break; | 1687 | break; | |
1691 | 1688 | |||
1692 | err = utoppy_command(sc, UTOPPY_CMD_MKDIR, UTOPPY_LONG_TIMEOUT, | 1689 | err = utoppy_command(sc, UTOPPY_CMD_MKDIR, UTOPPY_LONG_TIMEOUT, | |
1693 | &resp); | 1690 | &resp); | |
1694 | if (err) | 1691 | if (err) | |
1695 | break; | 1692 | break; | |
1696 | 1693 | |||
1697 | if (resp != UTOPPY_RESP_SUCCESS) | 1694 | if (resp != UTOPPY_RESP_SUCCESS) | |
1698 | err = EIO; | 1695 | err = EIO; | |
1699 | break; | 1696 | break; | |
1700 | 1697 | |||
1701 | case UTOPPYIODELETE: | 1698 | case UTOPPYIODELETE: | |
1702 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIODELETE\n", | 1699 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIODELETE\n", | |
1703 | device_xname(sc->sc_dev))); | 1700 | device_xname(sc->sc_dev))); | |
1704 | UTOPPY_OUT_INIT(sc); | 1701 | UTOPPY_OUT_INIT(sc); | |
1705 | err = utoppy_add_path(sc, *((const char **)data), 0); | 1702 | err = utoppy_add_path(sc, *((const char **)data), 0); | |
1706 | if (err) | 1703 | if (err) | |
1707 | break; | 1704 | break; | |
1708 | 1705 | |||
1709 | err = utoppy_command(sc, UTOPPY_CMD_DELETE, UTOPPY_LONG_TIMEOUT, | 1706 | err = utoppy_command(sc, UTOPPY_CMD_DELETE, UTOPPY_LONG_TIMEOUT, | |
1710 | &resp); | 1707 | &resp); | |
1711 | if (err) | 1708 | if (err) | |
1712 | break; | 1709 | break; | |
1713 | 1710 | |||
1714 | if (resp != UTOPPY_RESP_SUCCESS) | 1711 | if (resp != UTOPPY_RESP_SUCCESS) | |
1715 | err = EIO; | 1712 | err = EIO; | |
1716 | break; | 1713 | break; | |
1717 | 1714 | |||
1718 | case UTOPPYIOREADDIR: | 1715 | case UTOPPYIOREADDIR: | |
1719 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREADDIR\n", | 1716 | DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREADDIR\n", | |
1720 | device_xname(sc->sc_dev))); | 1717 | device_xname(sc->sc_dev))); | |
1721 | UTOPPY_OUT_INIT(sc); | 1718 | UTOPPY_OUT_INIT(sc); | |
1722 | err = utoppy_add_path(sc, *((const char **)data), 0); | 1719 | err = utoppy_add_path(sc, *((const char **)data), 0); | |
1723 | if (err) { | 1720 | if (err) { | |
1724 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: " | 1721 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: " | |
1725 | "utoppy_add_path() returned %d\n", | 1722 | "utoppy_add_path() returned %d\n", | |
1726 | device_xname(sc->sc_dev), err)); | 1723 | device_xname(sc->sc_dev), err)); | |
1727 | break; | 1724 | break; | |
1728 | } | 1725 | } | |
1729 | 1726 | |||
1730 | err = utoppy_send_packet(sc, UTOPPY_CMD_READDIR, | 1727 | err = utoppy_send_packet(sc, UTOPPY_CMD_READDIR, | |
1731 | UTOPPY_LONG_TIMEOUT); | 1728 | UTOPPY_LONG_TIMEOUT); | |
1732 | if (err != 0) { | 1729 | if (err != 0) { | |
1733 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: " | 1730 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: " | |
1734 | "UTOPPY_CMD_READDIR returned %d\n", | 1731 | "UTOPPY_CMD_READDIR returned %d\n", | |
1735 | device_xname(sc->sc_dev), err)); | 1732 | device_xname(sc->sc_dev), err)); | |
1736 | break; | 1733 | break; | |
1737 | } | 1734 | } | |
1738 | 1735 | |||
1739 | err = utoppy_readdir_next(sc); | 1736 | err = utoppy_readdir_next(sc); | |
1740 | if (err) { | 1737 | if (err) { | |
1741 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: " | 1738 | DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: " | |
1742 | "utoppy_readdir_next() returned %d\n", | 1739 | "utoppy_readdir_next() returned %d\n", | |
1743 | device_xname(sc->sc_dev), err)); | 1740 | device_xname(sc->sc_dev), err)); | |
1744 | } | 1741 | } | |
1745 | break; | 1742 | break; | |
1746 | 1743 | |||
1747 | case UTOPPYIOREADFILE: | 1744 | case UTOPPYIOREADFILE: | |
1748 | urf = (struct utoppy_readfile *)data; | 1745 | urf = (struct utoppy_readfile *)data; | |
1749 | 1746 | |||
1750 | DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOREADFILE " | 1747 | DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOREADFILE " | |
1751 | "%s, offset %lld\n", device_xname(sc->sc_dev), | 1748 | "%s, offset %lld\n", device_xname(sc->sc_dev), | |
1752 | urf->ur_path, urf->ur_offset)); | 1749 | urf->ur_path, urf->ur_offset)); | |
1753 | 1750 | |||
1754 | if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0) | 1751 | if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0) | |
1755 | break; | 1752 | break; | |
1756 | 1753 | |||
1757 | UTOPPY_OUT_INIT(sc); | 1754 | UTOPPY_OUT_INIT(sc); | |
1758 | utoppy_add_8(sc, UTOPPY_FILE_READ); | 1755 | utoppy_add_8(sc, UTOPPY_FILE_READ); | |
1759 | 1756 | |||
1760 | if ((err = utoppy_add_path(sc, urf->ur_path, 1)) != 0) | 1757 | if ((err = utoppy_add_path(sc, urf->ur_path, 1)) != 0) | |
1761 | break; | 1758 | break; | |
1762 | 1759 | |||
1763 | utoppy_add_64(sc, urf->ur_offset); | 1760 | utoppy_add_64(sc, urf->ur_offset); | |
1764 | 1761 | |||
1765 | sc->sc_state = UTOPPY_STATE_READFILE; | 1762 | sc->sc_state = UTOPPY_STATE_READFILE; | |
1766 | sc->sc_in_offset = 0; | 1763 | sc->sc_in_offset = 0; | |
1767 | 1764 | |||
1768 | err = utoppy_send_packet(sc, UTOPPY_CMD_FILE, | 1765 | err = utoppy_send_packet(sc, UTOPPY_CMD_FILE, | |
1769 | UTOPPY_LONG_TIMEOUT); | 1766 | UTOPPY_LONG_TIMEOUT); | |
1770 | if (err == 0) | 1767 | if (err == 0) | |
1771 | err = utoppy_readfile_next(sc); | 1768 | err = utoppy_readfile_next(sc); | |
1772 | break; | 1769 | break; | |
1773 | 1770 | |||
1774 | case UTOPPYIOWRITEFILE: | 1771 | case UTOPPYIOWRITEFILE: | |
1775 | uw = (struct utoppy_writefile *)data; | 1772 | uw = (struct utoppy_writefile *)data; | |
1776 | 1773 | |||
1777 | DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOWRITEFILE " | 1774 | DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOWRITEFILE " | |
1778 | "%s, size %lld, offset %lld\n", device_xname(sc->sc_dev), | 1775 | "%s, size %lld, offset %lld\n", device_xname(sc->sc_dev), | |
1779 | uw->uw_path, uw->uw_size, uw->uw_offset)); | 1776 | uw->uw_path, uw->uw_size, uw->uw_offset)); | |
1780 | 1777 | |||
1781 | if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0) | 1778 | if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0) | |
1782 | break; | 1779 | break; | |
1783 | 1780 | |||
1784 | UTOPPY_OUT_INIT(sc); | 1781 | UTOPPY_OUT_INIT(sc); | |
1785 | utoppy_add_8(sc, UTOPPY_FILE_WRITE); | 1782 | utoppy_add_8(sc, UTOPPY_FILE_WRITE); | |
1786 | uwfp = utoppy_current_ptr(sc->sc_out_data); | 1783 | uwfp = utoppy_current_ptr(sc->sc_out_data); | |
1787 | 1784 | |||
1788 | if ((err = utoppy_add_path(sc, uw->uw_path, 1)) != 0) { | 1785 | if ((err = utoppy_add_path(sc, uw->uw_path, 1)) != 0) { | |
1789 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: add_path()" | 1786 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: add_path()" | |
1790 | " returned %d\n", device_xname(sc->sc_dev), err)); | 1787 | " returned %d\n", device_xname(sc->sc_dev), err)); | |
1791 | break; | 1788 | break; | |
1792 | } | 1789 | } | |
1793 | 1790 | |||
1794 | strncpy(uwf, &uwfp[2], sizeof(uwf)); | 1791 | strncpy(uwf, &uwfp[2], sizeof(uwf)); | |
1795 | utoppy_add_64(sc, uw->uw_offset); | 1792 | utoppy_add_64(sc, uw->uw_offset); | |
1796 | 1793 | |||
1797 | err = utoppy_command(sc, UTOPPY_CMD_FILE, UTOPPY_LONG_TIMEOUT, | 1794 | err = utoppy_command(sc, UTOPPY_CMD_FILE, UTOPPY_LONG_TIMEOUT, | |
1798 | &resp); | 1795 | &resp); | |
1799 | if (err) { | 1796 | if (err) { | |
1800 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " | 1797 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " | |
1801 | "utoppy_command(UTOPPY_CMD_FILE) returned " | 1798 | "utoppy_command(UTOPPY_CMD_FILE) returned " | |
1802 | "%d\n", device_xname(sc->sc_dev), err)); | 1799 | "%d\n", device_xname(sc->sc_dev), err)); | |
1803 | break; | 1800 | break; | |
1804 | } | 1801 | } | |
1805 | if (resp != UTOPPY_RESP_SUCCESS) { | 1802 | if (resp != UTOPPY_RESP_SUCCESS) { | |
1806 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " | 1803 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " | |
1807 | "utoppy_command(UTOPPY_CMD_FILE) returned " | 1804 | "utoppy_command(UTOPPY_CMD_FILE) returned " | |
1808 | "bad response %#x\n", device_xname(sc->sc_dev), | 1805 | "bad response %#x\n", device_xname(sc->sc_dev), | |
1809 | resp)); | 1806 | resp)); | |
1810 | err = EIO; | 1807 | err = EIO; | |
1811 | break; | 1808 | break; | |
1812 | } | 1809 | } | |
1813 | 1810 | |||
1814 | UTOPPY_OUT_INIT(sc); | 1811 | UTOPPY_OUT_INIT(sc); | |
1815 | utoppy_timestamp_encode(sc, uw->uw_mtime); | 1812 | utoppy_timestamp_encode(sc, uw->uw_mtime); | |
1816 | utoppy_add_8(sc, UTOPPY_FTYPE_FILE); | 1813 | utoppy_add_8(sc, UTOPPY_FTYPE_FILE); | |
1817 | utoppy_add_64(sc, uw->uw_size); | 1814 | utoppy_add_64(sc, uw->uw_size); | |
1818 | utoppy_add_string(sc, uwf, sizeof(uwf)); | 1815 | utoppy_add_string(sc, uwf, sizeof(uwf)); | |
1819 | utoppy_add_32(sc, 0); | 1816 | utoppy_add_32(sc, 0); | |
1820 | 1817 | |||
1821 | err = utoppy_command(sc, UTOPPY_RESP_FILE_HEADER, | 1818 | err = utoppy_command(sc, UTOPPY_RESP_FILE_HEADER, | |
1822 | UTOPPY_LONG_TIMEOUT, &resp); | 1819 | UTOPPY_LONG_TIMEOUT, &resp); | |
1823 | if (err) { | 1820 | if (err) { | |
1824 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " | 1821 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " | |
1825 | "utoppy_command(UTOPPY_RESP_FILE_HEADER) " | 1822 | "utoppy_command(UTOPPY_RESP_FILE_HEADER) " | |
1826 | "returned %d\n", device_xname(sc->sc_dev), err)); | 1823 | "returned %d\n", device_xname(sc->sc_dev), err)); | |
1827 | break; | 1824 | break; | |
1828 | } | 1825 | } | |
1829 | if (resp != UTOPPY_RESP_SUCCESS) { | 1826 | if (resp != UTOPPY_RESP_SUCCESS) { | |
1830 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " | 1827 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " | |
1831 | "utoppy_command(UTOPPY_RESP_FILE_HEADER) " | 1828 | "utoppy_command(UTOPPY_RESP_FILE_HEADER) " | |
1832 | "returned bad response %#x\n", | 1829 | "returned bad response %#x\n", | |
1833 | device_xname(sc->sc_dev), resp)); | 1830 | device_xname(sc->sc_dev), resp)); | |
1834 | err = EIO; | 1831 | err = EIO; | |
1835 | break; | 1832 | break; | |
1836 | } | 1833 | } | |
1837 | 1834 | |||
1838 | sc->sc_wr_offset = uw->uw_offset; | 1835 | sc->sc_wr_offset = uw->uw_offset; | |
1839 | sc->sc_wr_size = uw->uw_size; | 1836 | sc->sc_wr_size = uw->uw_size; | |
1840 | sc->sc_state = UTOPPY_STATE_WRITEFILE; | 1837 | sc->sc_state = UTOPPY_STATE_WRITEFILE; | |
1841 | 1838 | |||
1842 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: Changing state to " | 1839 | DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: Changing state to " | |
1843 | "%s. wr_offset %lld, wr_size %lld\n", | 1840 | "%s. wr_offset %lld, wr_size %lld\n", | |
1844 | device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state), | 1841 | device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state), | |
1845 | sc->sc_wr_offset, sc->sc_wr_size)); | 1842 | sc->sc_wr_offset, sc->sc_wr_size)); | |
1846 | break; | 1843 | break; | |
1847 | 1844 | |||
1848 | default: | 1845 | default: | |
1849 | DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: Invalid cmd\n", | 1846 | DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: Invalid cmd\n", | |
1850 | device_xname(sc->sc_dev))); | 1847 | device_xname(sc->sc_dev))); | |
1851 | err = ENODEV; | 1848 | err = ENODEV; | |
1852 | break; | 1849 | break; | |
1853 | } | 1850 | } | |
1854 | 1851 | |||
1855 | DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: done. err %d, state '%s'\n", | 1852 | DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: done. err %d, state '%s'\n", | |
1856 | device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state))); | 1853 | device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state))); | |
1857 | 1854 | |||
1858 | if (err) | 1855 | if (err) | |
1859 | utoppy_cancel(sc); | 1856 | utoppy_cancel(sc); | |
1860 | 1857 | |||
1861 | if (--sc->sc_refcnt < 0) | 1858 | if (--sc->sc_refcnt < 0) | |
1862 | usb_detach_wakeupold(sc->sc_dev); | 1859 | usb_detach_wakeupold(sc->sc_dev); | |
1863 | 1860 | |||
1864 | return err; | 1861 | return err; | |
1865 | } | 1862 | } |