| @@ -1,1192 +1,1186 @@ | | | @@ -1,1192 +1,1186 @@ |
1 | /* $NetBSD: sl811hs.c,v 1.96 2016/09/24 15:06:29 skrll Exp $ */ | | 1 | /* $NetBSD: sl811hs.c,v 1.97 2016/10/01 13:46:52 christos Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Not (c) 2007 Matthew Orgass | | 4 | * Not (c) 2007 Matthew Orgass |
5 | * This file is public domain, meaning anyone can make any use of part or all | | 5 | * This file is public domain, meaning anyone can make any use of part or all |
6 | * of this file including copying into other works without credit. Any use, | | 6 | * of this file including copying into other works without credit. Any use, |
7 | * modified or not, is solely the responsibility of the user. If this file is | | 7 | * modified or not, is solely the responsibility of the user. If this file is |
8 | * part of a collection then use in the collection is governed by the terms of | | 8 | * part of a collection then use in the collection is governed by the terms of |
9 | * the collection. | | 9 | * the collection. |
10 | */ | | 10 | */ |
11 | | | 11 | |
12 | /* | | 12 | /* |
13 | * Cypress/ScanLogic SL811HS/T USB Host Controller | | 13 | * Cypress/ScanLogic SL811HS/T USB Host Controller |
14 | * Datasheet, Errata, and App Note available at www.cypress.com | | 14 | * Datasheet, Errata, and App Note available at www.cypress.com |
15 | * | | 15 | * |
16 | * Uses: Ratoc CFU1U PCMCIA USB Host Controller, Nereid X68k USB HC, ISA | | 16 | * Uses: Ratoc CFU1U PCMCIA USB Host Controller, Nereid X68k USB HC, ISA |
17 | * HCs. The Ratoc CFU2 uses a different chip. | | 17 | * HCs. The Ratoc CFU2 uses a different chip. |
18 | * | | 18 | * |
19 | * This chip puts the serial in USB. It implements USB by means of an eight | | 19 | * This chip puts the serial in USB. It implements USB by means of an eight |
20 | * bit I/O interface. It can be used for ISA, PCMCIA/CF, parallel port, | | 20 | * bit I/O interface. It can be used for ISA, PCMCIA/CF, parallel port, |
21 | * serial port, or any eight bit interface. It has 256 bytes of memory, the | | 21 | * serial port, or any eight bit interface. It has 256 bytes of memory, the |
22 | * first 16 of which are used for register access. There are two sets of | | 22 | * first 16 of which are used for register access. There are two sets of |
23 | * registers for sending individual bus transactions. Because USB is polled, | | 23 | * registers for sending individual bus transactions. Because USB is polled, |
24 | * this organization means that some amount of card access must often be made | | 24 | * this organization means that some amount of card access must often be made |
25 | * when devices are attached, even if when they are not directly being used. | | 25 | * when devices are attached, even if when they are not directly being used. |
26 | * A per-ms frame interrupt is necessary and many devices will poll with a | | 26 | * A per-ms frame interrupt is necessary and many devices will poll with a |
27 | * per-frame bulk transfer. | | 27 | * per-frame bulk transfer. |
28 | * | | 28 | * |
29 | * It is possible to write a little over two bytes to the chip (auto | | 29 | * It is possible to write a little over two bytes to the chip (auto |
30 | * incremented) per full speed byte time on the USB. Unfortunately, | | 30 | * incremented) per full speed byte time on the USB. Unfortunately, |
31 | * auto-increment does not work reliably so write and bus speed is | | 31 | * auto-increment does not work reliably so write and bus speed is |
32 | * approximately the same for full speed devices. | | 32 | * approximately the same for full speed devices. |
33 | * | | 33 | * |
34 | * In addition to the 240 byte packet size limit for isochronous transfers, | | 34 | * In addition to the 240 byte packet size limit for isochronous transfers, |
35 | * this chip has no means of determining the current frame number other than | | 35 | * this chip has no means of determining the current frame number other than |
36 | * getting all 1ms SOF interrupts, which is not always possible even on a fast | | 36 | * getting all 1ms SOF interrupts, which is not always possible even on a fast |
37 | * system. Isochronous transfers guarantee that transfers will never be | | 37 | * system. Isochronous transfers guarantee that transfers will never be |
38 | * retried in a later frame, so this can cause problems with devices beyond | | 38 | * retried in a later frame, so this can cause problems with devices beyond |
39 | * the difficulty in actually performing the transfer most frames. I tried | | 39 | * the difficulty in actually performing the transfer most frames. I tried |
40 | * implementing isoc transfers and was able to play CD-derrived audio via an | | 40 | * implementing isoc transfers and was able to play CD-derrived audio via an |
41 | * iMic on a 2GHz PC, however it would still be interrupted at times and | | 41 | * iMic on a 2GHz PC, however it would still be interrupted at times and |
42 | * once interrupted, would stay out of sync. All isoc support has been | | 42 | * once interrupted, would stay out of sync. All isoc support has been |
43 | * removed. | | 43 | * removed. |
44 | * | | 44 | * |
45 | * BUGS: all chip revisions have problems with low speed devices through hubs. | | 45 | * BUGS: all chip revisions have problems with low speed devices through hubs. |
46 | * The chip stops generating SOF with hubs that send SE0 during SOF. See | | 46 | * The chip stops generating SOF with hubs that send SE0 during SOF. See |
47 | * comment in dointr(). All performance enhancing features of this chip seem | | 47 | * comment in dointr(). All performance enhancing features of this chip seem |
48 | * not to work properly, most confirmed buggy in errata doc. | | 48 | * not to work properly, most confirmed buggy in errata doc. |
49 | * | | 49 | * |
50 | */ | | 50 | */ |
51 | | | 51 | |
52 | /* | | 52 | /* |
53 | * The hard interrupt is the main entry point. Start, callbacks, and repeat | | 53 | * The hard interrupt is the main entry point. Start, callbacks, and repeat |
54 | * are the only others called frequently. | | 54 | * are the only others called frequently. |
55 | * | | 55 | * |
56 | * Since this driver attaches to pcmcia, card removal at any point should be | | 56 | * Since this driver attaches to pcmcia, card removal at any point should be |
57 | * expected and not cause panics or infinite loops. | | 57 | * expected and not cause panics or infinite loops. |
58 | */ | | 58 | */ |
59 | | | 59 | |
60 | /* | | 60 | /* |
61 | * XXX TODO: | | 61 | * XXX TODO: |
62 | * copy next output packet while transfering | | 62 | * copy next output packet while transfering |
63 | * usb suspend | | 63 | * usb suspend |
64 | * could keep track of known values of all buffer space? | | 64 | * could keep track of known values of all buffer space? |
65 | * combined print/log function for errors | | 65 | * combined print/log function for errors |
66 | * | | 66 | * |
67 | * ub_usepolling support is untested and may not work | | 67 | * ub_usepolling support is untested and may not work |
68 | */ | | 68 | */ |
69 | | | 69 | |
70 | #include <sys/cdefs.h> | | 70 | #include <sys/cdefs.h> |
71 | __KERNEL_RCSID(0, "$NetBSD: sl811hs.c,v 1.96 2016/09/24 15:06:29 skrll Exp $"); | | 71 | __KERNEL_RCSID(0, "$NetBSD: sl811hs.c,v 1.97 2016/10/01 13:46:52 christos Exp $"); |
72 | | | 72 | |
73 | #ifdef _KERNEL_OPT | | 73 | #ifdef _KERNEL_OPT |
74 | #include "opt_slhci.h" | | 74 | #include "opt_slhci.h" |
75 | #include "opt_usb.h" | | 75 | #include "opt_usb.h" |
76 | #endif | | 76 | #endif |
77 | | | 77 | |
78 | #include <sys/param.h> | | 78 | #include <sys/param.h> |
79 | | | 79 | |
80 | #include <sys/bus.h> | | 80 | #include <sys/bus.h> |
81 | #include <sys/cpu.h> | | 81 | #include <sys/cpu.h> |
82 | #include <sys/device.h> | | 82 | #include <sys/device.h> |
83 | #include <sys/gcq.h> | | 83 | #include <sys/gcq.h> |
84 | #include <sys/intr.h> | | 84 | #include <sys/intr.h> |
85 | #include <sys/kernel.h> | | 85 | #include <sys/kernel.h> |
86 | #include <sys/kmem.h> | | 86 | #include <sys/kmem.h> |
87 | #include <sys/proc.h> | | 87 | #include <sys/proc.h> |
88 | #include <sys/queue.h> | | 88 | #include <sys/queue.h> |
89 | #include <sys/sysctl.h> | | 89 | #include <sys/sysctl.h> |
90 | #include <sys/systm.h> | | 90 | #include <sys/systm.h> |
91 | | | 91 | |
92 | #include <dev/usb/usb.h> | | 92 | #include <dev/usb/usb.h> |
93 | #include <dev/usb/usbdi.h> | | 93 | #include <dev/usb/usbdi.h> |
94 | #include <dev/usb/usbdivar.h> | | 94 | #include <dev/usb/usbdivar.h> |
95 | #include <dev/usb/usbhist.h> | | 95 | #include <dev/usb/usbhist.h> |
96 | #include <dev/usb/usb_mem.h> | | 96 | #include <dev/usb/usb_mem.h> |
97 | #include <dev/usb/usbdevs.h> | | 97 | #include <dev/usb/usbdevs.h> |
98 | #include <dev/usb/usbroothub.h> | | 98 | #include <dev/usb/usbroothub.h> |
99 | | | 99 | |
100 | #include <dev/ic/sl811hsreg.h> | | 100 | #include <dev/ic/sl811hsreg.h> |
101 | #include <dev/ic/sl811hsvar.h> | | 101 | #include <dev/ic/sl811hsvar.h> |
102 | | | 102 | |
103 | #define Q_CB 0 /* Control/Bulk */ | | 103 | #define Q_CB 0 /* Control/Bulk */ |
104 | #define Q_NEXT_CB 1 | | 104 | #define Q_NEXT_CB 1 |
105 | #define Q_MAX_XFER Q_CB | | 105 | #define Q_MAX_XFER Q_CB |
106 | #define Q_CALLBACKS 2 | | 106 | #define Q_CALLBACKS 2 |
107 | #define Q_MAX Q_CALLBACKS | | 107 | #define Q_MAX Q_CALLBACKS |
108 | | | 108 | |
109 | #define F_AREADY (0x00000001) | | 109 | #define F_AREADY (0x00000001) |
110 | #define F_BREADY (0x00000002) | | 110 | #define F_BREADY (0x00000002) |
111 | #define F_AINPROG (0x00000004) | | 111 | #define F_AINPROG (0x00000004) |
112 | #define F_BINPROG (0x00000008) | | 112 | #define F_BINPROG (0x00000008) |
113 | #define F_LOWSPEED (0x00000010) | | 113 | #define F_LOWSPEED (0x00000010) |
114 | #define F_UDISABLED (0x00000020) /* Consider disabled for USB */ | | 114 | #define F_UDISABLED (0x00000020) /* Consider disabled for USB */ |
115 | #define F_NODEV (0x00000040) | | 115 | #define F_NODEV (0x00000040) |
116 | #define F_ROOTINTR (0x00000080) | | 116 | #define F_ROOTINTR (0x00000080) |
117 | #define F_REALPOWER (0x00000100) /* Actual power state */ | | 117 | #define F_REALPOWER (0x00000100) /* Actual power state */ |
118 | #define F_POWER (0x00000200) /* USB reported power state */ | | 118 | #define F_POWER (0x00000200) /* USB reported power state */ |
119 | #define F_ACTIVE (0x00000400) | | 119 | #define F_ACTIVE (0x00000400) |
120 | #define F_CALLBACK (0x00000800) /* Callback scheduled */ | | 120 | #define F_CALLBACK (0x00000800) /* Callback scheduled */ |
121 | #define F_SOFCHECK1 (0x00001000) | | 121 | #define F_SOFCHECK1 (0x00001000) |
122 | #define F_SOFCHECK2 (0x00002000) | | 122 | #define F_SOFCHECK2 (0x00002000) |
123 | #define F_CRESET (0x00004000) /* Reset done not reported */ | | 123 | #define F_CRESET (0x00004000) /* Reset done not reported */ |
124 | #define F_CCONNECT (0x00008000) /* Connect change not reported */ | | 124 | #define F_CCONNECT (0x00008000) /* Connect change not reported */ |
125 | #define F_RESET (0x00010000) | | 125 | #define F_RESET (0x00010000) |
126 | #define F_ISOC_WARNED (0x00020000) | | 126 | #define F_ISOC_WARNED (0x00020000) |
127 | #define F_LSVH_WARNED (0x00040000) | | 127 | #define F_LSVH_WARNED (0x00040000) |
128 | | | 128 | |
129 | #define F_DISABLED (F_NODEV|F_UDISABLED) | | 129 | #define F_DISABLED (F_NODEV|F_UDISABLED) |
130 | #define F_CHANGE (F_CRESET|F_CCONNECT) | | 130 | #define F_CHANGE (F_CRESET|F_CCONNECT) |
131 | | | 131 | |
132 | #ifdef SLHCI_TRY_LSVH | | 132 | #ifdef SLHCI_TRY_LSVH |
133 | unsigned int slhci_try_lsvh = 1; | | 133 | unsigned int slhci_try_lsvh = 1; |
134 | #else | | 134 | #else |
135 | unsigned int slhci_try_lsvh = 0; | | 135 | unsigned int slhci_try_lsvh = 0; |
136 | #endif | | 136 | #endif |
137 | | | 137 | |
138 | #define ADR 0 | | 138 | #define ADR 0 |
139 | #define LEN 1 | | 139 | #define LEN 1 |
140 | #define PID 2 | | 140 | #define PID 2 |
141 | #define DEV 3 | | 141 | #define DEV 3 |
142 | #define STAT 2 | | 142 | #define STAT 2 |
143 | #define CONT 3 | | 143 | #define CONT 3 |
144 | | | 144 | |
145 | #define A 0 | | 145 | #define A 0 |
146 | #define B 1 | | 146 | #define B 1 |
147 | | | 147 | |
148 | static const uint8_t slhci_tregs[2][4] = | | 148 | static const uint8_t slhci_tregs[2][4] = |
149 | {{SL11_E0ADDR, SL11_E0LEN, SL11_E0PID, SL11_E0DEV }, | | 149 | {{SL11_E0ADDR, SL11_E0LEN, SL11_E0PID, SL11_E0DEV }, |
150 | {SL11_E1ADDR, SL11_E1LEN, SL11_E1PID, SL11_E1DEV }}; | | 150 | {SL11_E1ADDR, SL11_E1LEN, SL11_E1PID, SL11_E1DEV }}; |
151 | | | 151 | |
152 | #define PT_ROOT_CTRL 0 | | 152 | #define PT_ROOT_CTRL 0 |
153 | #define PT_ROOT_INTR 1 | | 153 | #define PT_ROOT_INTR 1 |
154 | #define PT_CTRL_SETUP 2 | | 154 | #define PT_CTRL_SETUP 2 |
155 | #define PT_CTRL_DATA 3 | | 155 | #define PT_CTRL_DATA 3 |
156 | #define PT_CTRL_STATUS 4 | | 156 | #define PT_CTRL_STATUS 4 |
157 | #define PT_INTR 5 | | 157 | #define PT_INTR 5 |
158 | #define PT_BULK 6 | | 158 | #define PT_BULK 6 |
159 | #define PT_MAX 6 | | 159 | #define PT_MAX 6 |
160 | | | 160 | |
161 | #ifdef SLHCI_DEBUG | | 161 | #ifdef SLHCI_DEBUG |
162 | #define SLHCI_MEM_ACCOUNTING | | 162 | #define SLHCI_MEM_ACCOUNTING |
163 | #endif | | 163 | #endif |
164 | | | 164 | |
165 | /* | | 165 | /* |
166 | * Maximum allowable reserved bus time. Since intr/isoc transfers have | | 166 | * Maximum allowable reserved bus time. Since intr/isoc transfers have |
167 | * unconditional priority, this is all that ensures control and bulk transfers | | 167 | * unconditional priority, this is all that ensures control and bulk transfers |
168 | * get a chance. It is a single value for all frames since all transfers can | | 168 | * get a chance. It is a single value for all frames since all transfers can |
169 | * use multiple consecutive frames if an error is encountered. Note that it | | 169 | * use multiple consecutive frames if an error is encountered. Note that it |
170 | * is not really possible to fill the bus with transfers, so this value should | | 170 | * is not really possible to fill the bus with transfers, so this value should |
171 | * be on the low side. Defaults to giving a warning unless SLHCI_NO_OVERTIME | | 171 | * be on the low side. Defaults to giving a warning unless SLHCI_NO_OVERTIME |
172 | * is defined. Full time is 12000 - END_BUSTIME. | | 172 | * is defined. Full time is 12000 - END_BUSTIME. |
173 | */ | | 173 | */ |
174 | #ifndef SLHCI_RESERVED_BUSTIME | | 174 | #ifndef SLHCI_RESERVED_BUSTIME |
175 | #define SLHCI_RESERVED_BUSTIME 5000 | | 175 | #define SLHCI_RESERVED_BUSTIME 5000 |
176 | #endif | | 176 | #endif |
177 | | | 177 | |
178 | /* | | 178 | /* |
179 | * Rate for "exceeds reserved bus time" warnings (default) or errors. | | 179 | * Rate for "exceeds reserved bus time" warnings (default) or errors. |
180 | * Warnings only happen when an endpoint open causes the time to go above | | 180 | * Warnings only happen when an endpoint open causes the time to go above |
181 | * SLHCI_RESERVED_BUSTIME, not if it is already above. | | 181 | * SLHCI_RESERVED_BUSTIME, not if it is already above. |
182 | */ | | 182 | */ |
183 | #ifndef SLHCI_OVERTIME_WARNING_RATE | | 183 | #ifndef SLHCI_OVERTIME_WARNING_RATE |
184 | #define SLHCI_OVERTIME_WARNING_RATE { 60, 0 } /* 60 seconds */ | | 184 | #define SLHCI_OVERTIME_WARNING_RATE { 60, 0 } /* 60 seconds */ |
185 | #endif | | 185 | #endif |
186 | static const struct timeval reserved_warn_rate = SLHCI_OVERTIME_WARNING_RATE; | | 186 | static const struct timeval reserved_warn_rate = SLHCI_OVERTIME_WARNING_RATE; |
187 | | | 187 | |
188 | /* Rate for overflow warnings */ | | | |
189 | #ifndef SLHCI_OVERFLOW_WARNING_RATE | | | |
190 | #define SLHCI_OVERFLOW_WARNING_RATE { 60, 0 } /* 60 seconds */ | | | |
191 | #endif | | | |
192 | static const struct timeval overflow_warn_rate = SLHCI_OVERFLOW_WARNING_RATE; | | | |
193 | | | | |
194 | /* | | 188 | /* |
195 | * For EOF, the spec says 42 bit times, plus (I think) a possible hub skew of | | 189 | * For EOF, the spec says 42 bit times, plus (I think) a possible hub skew of |
196 | * 20 bit times. By default leave 66 bit times to start the transfer beyond | | 190 | * 20 bit times. By default leave 66 bit times to start the transfer beyond |
197 | * the required time. Units are full-speed bit times (a bit over 5us per 64). | | 191 | * the required time. Units are full-speed bit times (a bit over 5us per 64). |
198 | * Only multiples of 64 are significant. | | 192 | * Only multiples of 64 are significant. |
199 | */ | | 193 | */ |
200 | #define SLHCI_STANDARD_END_BUSTIME 128 | | 194 | #define SLHCI_STANDARD_END_BUSTIME 128 |
201 | #ifndef SLHCI_EXTRA_END_BUSTIME | | 195 | #ifndef SLHCI_EXTRA_END_BUSTIME |
202 | #define SLHCI_EXTRA_END_BUSTIME 0 | | 196 | #define SLHCI_EXTRA_END_BUSTIME 0 |
203 | #endif | | 197 | #endif |
204 | | | 198 | |
205 | #define SLHCI_END_BUSTIME (SLHCI_STANDARD_END_BUSTIME+SLHCI_EXTRA_END_BUSTIME) | | 199 | #define SLHCI_END_BUSTIME (SLHCI_STANDARD_END_BUSTIME+SLHCI_EXTRA_END_BUSTIME) |
206 | | | 200 | |
207 | /* | | 201 | /* |
208 | * This is an approximation of the USB worst-case timings presented on p. 54 of | | 202 | * This is an approximation of the USB worst-case timings presented on p. 54 of |
209 | * the USB 1.1 spec translated to full speed bit times. | | 203 | * the USB 1.1 spec translated to full speed bit times. |
210 | * FS = full speed with handshake, FSII = isoc in, FSIO = isoc out, | | 204 | * FS = full speed with handshake, FSII = isoc in, FSIO = isoc out, |
211 | * FSI = isoc (worst case), LS = low speed | | 205 | * FSI = isoc (worst case), LS = low speed |
212 | */ | | 206 | */ |
213 | #define SLHCI_FS_CONST 114 | | 207 | #define SLHCI_FS_CONST 114 |
214 | #define SLHCI_FSII_CONST 92 | | 208 | #define SLHCI_FSII_CONST 92 |
215 | #define SLHCI_FSIO_CONST 80 | | 209 | #define SLHCI_FSIO_CONST 80 |
216 | #define SLHCI_FSI_CONST 92 | | 210 | #define SLHCI_FSI_CONST 92 |
217 | #define SLHCI_LS_CONST 804 | | 211 | #define SLHCI_LS_CONST 804 |
218 | #ifndef SLHCI_PRECICE_BUSTIME | | 212 | #ifndef SLHCI_PRECICE_BUSTIME |
219 | /* | | 213 | /* |
220 | * These values are < 3% too high (compared to the multiply and divide) for | | 214 | * These values are < 3% too high (compared to the multiply and divide) for |
221 | * max sized packets. | | 215 | * max sized packets. |
222 | */ | | 216 | */ |
223 | #define SLHCI_FS_DATA_TIME(len) (((u_int)(len)<<3)+(len)+((len)>>1)) | | 217 | #define SLHCI_FS_DATA_TIME(len) (((u_int)(len)<<3)+(len)+((len)>>1)) |
224 | #define SLHCI_LS_DATA_TIME(len) (((u_int)(len)<<6)+((u_int)(len)<<4)) | | 218 | #define SLHCI_LS_DATA_TIME(len) (((u_int)(len)<<6)+((u_int)(len)<<4)) |
225 | #else | | 219 | #else |
226 | #define SLHCI_FS_DATA_TIME(len) (56*(len)/6) | | 220 | #define SLHCI_FS_DATA_TIME(len) (56*(len)/6) |
227 | #define SLHCI_LS_DATA_TIME(len) (449*(len)/6) | | 221 | #define SLHCI_LS_DATA_TIME(len) (449*(len)/6) |
228 | #endif | | 222 | #endif |
229 | | | 223 | |
230 | /* | | 224 | /* |
231 | * Set SLHCI_WAIT_SIZE to the desired maximum size of single FS transfer | | 225 | * Set SLHCI_WAIT_SIZE to the desired maximum size of single FS transfer |
232 | * to poll for after starting a transfer. 64 gets all full speed transfers. | | 226 | * to poll for after starting a transfer. 64 gets all full speed transfers. |
233 | * Note that even if 0 polling will occur if data equal or greater than the | | 227 | * Note that even if 0 polling will occur if data equal or greater than the |
234 | * transfer size is copied to the chip while the transfer is in progress. | | 228 | * transfer size is copied to the chip while the transfer is in progress. |
235 | * Setting SLHCI_WAIT_TIME to -12000 will disable polling. | | 229 | * Setting SLHCI_WAIT_TIME to -12000 will disable polling. |
236 | */ | | 230 | */ |
237 | #ifndef SLHCI_WAIT_SIZE | | 231 | #ifndef SLHCI_WAIT_SIZE |
238 | #define SLHCI_WAIT_SIZE 8 | | 232 | #define SLHCI_WAIT_SIZE 8 |
239 | #endif | | 233 | #endif |
240 | #ifndef SLHCI_WAIT_TIME | | 234 | #ifndef SLHCI_WAIT_TIME |
241 | #define SLHCI_WAIT_TIME (SLHCI_FS_CONST + \ | | 235 | #define SLHCI_WAIT_TIME (SLHCI_FS_CONST + \ |
242 | SLHCI_FS_DATA_TIME(SLHCI_WAIT_SIZE)) | | 236 | SLHCI_FS_DATA_TIME(SLHCI_WAIT_SIZE)) |
243 | #endif | | 237 | #endif |
244 | const int slhci_wait_time = SLHCI_WAIT_TIME; | | 238 | const int slhci_wait_time = SLHCI_WAIT_TIME; |
245 | | | 239 | |
246 | #ifndef SLHCI_MAX_RETRIES | | 240 | #ifndef SLHCI_MAX_RETRIES |
247 | #define SLHCI_MAX_RETRIES 3 | | 241 | #define SLHCI_MAX_RETRIES 3 |
248 | #endif | | 242 | #endif |
249 | | | 243 | |
250 | /* Check IER values for corruption after this many unrecognized interrupts. */ | | 244 | /* Check IER values for corruption after this many unrecognized interrupts. */ |
251 | #ifndef SLHCI_IER_CHECK_FREQUENCY | | 245 | #ifndef SLHCI_IER_CHECK_FREQUENCY |
252 | #ifdef SLHCI_DEBUG | | 246 | #ifdef SLHCI_DEBUG |
253 | #define SLHCI_IER_CHECK_FREQUENCY 1 | | 247 | #define SLHCI_IER_CHECK_FREQUENCY 1 |
254 | #else | | 248 | #else |
255 | #define SLHCI_IER_CHECK_FREQUENCY 100 | | 249 | #define SLHCI_IER_CHECK_FREQUENCY 100 |
256 | #endif | | 250 | #endif |
257 | #endif | | 251 | #endif |
258 | | | 252 | |
259 | /* Note that buffer points to the start of the buffer for this transfer. */ | | 253 | /* Note that buffer points to the start of the buffer for this transfer. */ |
260 | struct slhci_pipe { | | 254 | struct slhci_pipe { |
261 | struct usbd_pipe pipe; | | 255 | struct usbd_pipe pipe; |
262 | struct usbd_xfer *xfer; /* xfer in progress */ | | 256 | struct usbd_xfer *xfer; /* xfer in progress */ |
263 | uint8_t *buffer; /* I/O buffer (if needed) */ | | 257 | uint8_t *buffer; /* I/O buffer (if needed) */ |
264 | struct gcq ap; /* All pipes */ | | 258 | struct gcq ap; /* All pipes */ |
265 | struct gcq to; /* Timeout list */ | | 259 | struct gcq to; /* Timeout list */ |
266 | struct gcq xq; /* Xfer queues */ | | 260 | struct gcq xq; /* Xfer queues */ |
267 | unsigned int pflags; /* Pipe flags */ | | 261 | unsigned int pflags; /* Pipe flags */ |
268 | #define PF_GONE (0x01) /* Pipe is on disabled device */ | | 262 | #define PF_GONE (0x01) /* Pipe is on disabled device */ |
269 | #define PF_TOGGLE (0x02) /* Data toggle status */ | | 263 | #define PF_TOGGLE (0x02) /* Data toggle status */ |
270 | #define PF_LS (0x04) /* Pipe is low speed */ | | 264 | #define PF_LS (0x04) /* Pipe is low speed */ |
271 | #define PF_PREAMBLE (0x08) /* Needs preamble */ | | 265 | #define PF_PREAMBLE (0x08) /* Needs preamble */ |
272 | Frame to_frame; /* Frame number for timeout */ | | 266 | Frame to_frame; /* Frame number for timeout */ |
273 | Frame frame; /* Frame number for intr xfer */ | | 267 | Frame frame; /* Frame number for intr xfer */ |
274 | Frame lastframe; /* Previous frame number for intr */ | | 268 | Frame lastframe; /* Previous frame number for intr */ |
275 | uint16_t bustime; /* Worst case bus time usage */ | | 269 | uint16_t bustime; /* Worst case bus time usage */ |
276 | uint16_t newbustime[2]; /* new bustimes (see index below) */ | | 270 | uint16_t newbustime[2]; /* new bustimes (see index below) */ |
277 | uint8_t tregs[4]; /* ADR, LEN, PID, DEV */ | | 271 | uint8_t tregs[4]; /* ADR, LEN, PID, DEV */ |
278 | uint8_t newlen[2]; /* 0 = short data, 1 = ctrl data */ | | 272 | uint8_t newlen[2]; /* 0 = short data, 1 = ctrl data */ |
279 | uint8_t newpid; /* for ctrl */ | | 273 | uint8_t newpid; /* for ctrl */ |
280 | uint8_t wantshort; /* last xfer must be short */ | | 274 | uint8_t wantshort; /* last xfer must be short */ |
281 | uint8_t control; /* Host control register settings */ | | 275 | uint8_t control; /* Host control register settings */ |
282 | uint8_t nerrs; /* Current number of errors */ | | 276 | uint8_t nerrs; /* Current number of errors */ |
283 | uint8_t ptype; /* Pipe type */ | | 277 | uint8_t ptype; /* Pipe type */ |
284 | }; | | 278 | }; |
285 | | | 279 | |
286 | #define SLHCI_BUS2SC(bus) ((bus)->ub_hcpriv) | | 280 | #define SLHCI_BUS2SC(bus) ((bus)->ub_hcpriv) |
287 | #define SLHCI_PIPE2SC(pipe) SLHCI_BUS2SC((pipe)->up_dev->ud_bus) | | 281 | #define SLHCI_PIPE2SC(pipe) SLHCI_BUS2SC((pipe)->up_dev->ud_bus) |
288 | #define SLHCI_XFER2SC(xfer) SLHCI_BUS2SC((xfer)->ux_bus) | | 282 | #define SLHCI_XFER2SC(xfer) SLHCI_BUS2SC((xfer)->ux_bus) |
289 | | | 283 | |
290 | #define SLHCI_PIPE2SPIPE(pipe) ((struct slhci_pipe *)(pipe)) | | 284 | #define SLHCI_PIPE2SPIPE(pipe) ((struct slhci_pipe *)(pipe)) |
291 | #define SLHCI_XFER2SPIPE(xfer) SLHCI_PIPE2SPIPE((xfer)->ux_pipe) | | 285 | #define SLHCI_XFER2SPIPE(xfer) SLHCI_PIPE2SPIPE((xfer)->ux_pipe) |
292 | | | 286 | |
293 | #define SLHCI_XFER_TYPE(x) (SLHCI_XFER2SPIPE(xfer)->ptype) | | 287 | #define SLHCI_XFER_TYPE(x) (SLHCI_XFER2SPIPE(xfer)->ptype) |
294 | | | 288 | |
295 | #ifdef SLHCI_PROFILE_TRANSFER | | 289 | #ifdef SLHCI_PROFILE_TRANSFER |
296 | #if defined(__mips__) | | 290 | #if defined(__mips__) |
297 | /* | | 291 | /* |
298 | * MIPS cycle counter does not directly count cpu cycles but is a different | | 292 | * MIPS cycle counter does not directly count cpu cycles but is a different |
299 | * fraction of cpu cycles depending on the cpu. | | 293 | * fraction of cpu cycles depending on the cpu. |
300 | */ | | 294 | */ |
301 | typedef uint32_t cc_type; | | 295 | typedef uint32_t cc_type; |
302 | #define CC_TYPE_FMT "%u" | | 296 | #define CC_TYPE_FMT "%u" |
303 | #define slhci_cc_set(x) __asm volatile ("mfc0 %[cc], $9\n\tnop\n\tnop\n\tnop" \ | | 297 | #define slhci_cc_set(x) __asm volatile ("mfc0 %[cc], $9\n\tnop\n\tnop\n\tnop" \ |
304 | : [cc] "=r"(x)) | | 298 | : [cc] "=r"(x)) |
305 | #elif defined(__i386__) | | 299 | #elif defined(__i386__) |
306 | typedef uint64_t cc_type; | | 300 | typedef uint64_t cc_type; |
307 | #define CC_TYPE_FMT "%llu" | | 301 | #define CC_TYPE_FMT "%llu" |
308 | #define slhci_cc_set(x) __asm volatile ("rdtsc" : "=A"(x)) | | 302 | #define slhci_cc_set(x) __asm volatile ("rdtsc" : "=A"(x)) |
309 | #else | | 303 | #else |
310 | #error "SLHCI_PROFILE_TRANSFER not implemented on this MACHINE_ARCH (see sys/dev/ic/sl811hs.c)" | | 304 | #error "SLHCI_PROFILE_TRANSFER not implemented on this MACHINE_ARCH (see sys/dev/ic/sl811hs.c)" |
311 | #endif | | 305 | #endif |
312 | struct slhci_cc_time { | | 306 | struct slhci_cc_time { |
313 | cc_type start; | | 307 | cc_type start; |
314 | cc_type stop; | | 308 | cc_type stop; |
315 | unsigned int miscdata; | | 309 | unsigned int miscdata; |
316 | }; | | 310 | }; |
317 | #ifndef SLHCI_N_TIMES | | 311 | #ifndef SLHCI_N_TIMES |
318 | #define SLHCI_N_TIMES 200 | | 312 | #define SLHCI_N_TIMES 200 |
319 | #endif | | 313 | #endif |
320 | struct slhci_cc_times { | | 314 | struct slhci_cc_times { |
321 | struct slhci_cc_time times[SLHCI_N_TIMES]; | | 315 | struct slhci_cc_time times[SLHCI_N_TIMES]; |
322 | int current; | | 316 | int current; |
323 | int wraparound; | | 317 | int wraparound; |
324 | }; | | 318 | }; |
325 | | | 319 | |
326 | static struct slhci_cc_times t_ab[2]; | | 320 | static struct slhci_cc_times t_ab[2]; |
327 | static struct slhci_cc_times t_abdone; | | 321 | static struct slhci_cc_times t_abdone; |
328 | static struct slhci_cc_times t_copy_to_dev; | | 322 | static struct slhci_cc_times t_copy_to_dev; |
329 | static struct slhci_cc_times t_copy_from_dev; | | 323 | static struct slhci_cc_times t_copy_from_dev; |
330 | static struct slhci_cc_times t_intr; | | 324 | static struct slhci_cc_times t_intr; |
331 | static struct slhci_cc_times t_lock; | | 325 | static struct slhci_cc_times t_lock; |
332 | static struct slhci_cc_times t_delay; | | 326 | static struct slhci_cc_times t_delay; |
333 | static struct slhci_cc_times t_hard_int; | | 327 | static struct slhci_cc_times t_hard_int; |
334 | static struct slhci_cc_times t_callback; | | 328 | static struct slhci_cc_times t_callback; |
335 | | | 329 | |
336 | static inline void | | 330 | static inline void |
337 | start_cc_time(struct slhci_cc_times *times, unsigned int misc) { | | 331 | start_cc_time(struct slhci_cc_times *times, unsigned int misc) { |
338 | times->times[times->current].miscdata = misc; | | 332 | times->times[times->current].miscdata = misc; |
339 | slhci_cc_set(times->times[times->current].start); | | 333 | slhci_cc_set(times->times[times->current].start); |
340 | } | | 334 | } |
341 | static inline void | | 335 | static inline void |
342 | stop_cc_time(struct slhci_cc_times *times) { | | 336 | stop_cc_time(struct slhci_cc_times *times) { |
343 | slhci_cc_set(times->times[times->current].stop); | | 337 | slhci_cc_set(times->times[times->current].stop); |
344 | if (++times->current >= SLHCI_N_TIMES) { | | 338 | if (++times->current >= SLHCI_N_TIMES) { |
345 | times->current = 0; | | 339 | times->current = 0; |
346 | times->wraparound = 1; | | 340 | times->wraparound = 1; |
347 | } | | 341 | } |
348 | } | | 342 | } |
349 | | | 343 | |
350 | void slhci_dump_cc_times(int); | | 344 | void slhci_dump_cc_times(int); |
351 | | | 345 | |
352 | void | | 346 | void |
353 | slhci_dump_cc_times(int n) { | | 347 | slhci_dump_cc_times(int n) { |
354 | struct slhci_cc_times *times; | | 348 | struct slhci_cc_times *times; |
355 | int i; | | 349 | int i; |
356 | | | 350 | |
357 | switch (n) { | | 351 | switch (n) { |
358 | default: | | 352 | default: |
359 | case 0: | | 353 | case 0: |
360 | printf("USBA start transfer to intr:\n"); | | 354 | printf("USBA start transfer to intr:\n"); |
361 | times = &t_ab[A]; | | 355 | times = &t_ab[A]; |
362 | break; | | 356 | break; |
363 | case 1: | | 357 | case 1: |
364 | printf("USBB start transfer to intr:\n"); | | 358 | printf("USBB start transfer to intr:\n"); |
365 | times = &t_ab[B]; | | 359 | times = &t_ab[B]; |
366 | break; | | 360 | break; |
367 | case 2: | | 361 | case 2: |
368 | printf("abdone:\n"); | | 362 | printf("abdone:\n"); |
369 | times = &t_abdone; | | 363 | times = &t_abdone; |
370 | break; | | 364 | break; |
371 | case 3: | | 365 | case 3: |
372 | printf("copy to device:\n"); | | 366 | printf("copy to device:\n"); |
373 | times = &t_copy_to_dev; | | 367 | times = &t_copy_to_dev; |
374 | break; | | 368 | break; |
375 | case 4: | | 369 | case 4: |
376 | printf("copy from device:\n"); | | 370 | printf("copy from device:\n"); |
377 | times = &t_copy_from_dev; | | 371 | times = &t_copy_from_dev; |
378 | break; | | 372 | break; |
379 | case 5: | | 373 | case 5: |
380 | printf("intr to intr:\n"); | | 374 | printf("intr to intr:\n"); |
381 | times = &t_intr; | | 375 | times = &t_intr; |
382 | break; | | 376 | break; |
383 | case 6: | | 377 | case 6: |
384 | printf("lock to release:\n"); | | 378 | printf("lock to release:\n"); |
385 | times = &t_lock; | | 379 | times = &t_lock; |
386 | break; | | 380 | break; |
387 | case 7: | | 381 | case 7: |
388 | printf("delay time:\n"); | | 382 | printf("delay time:\n"); |
389 | times = &t_delay; | | 383 | times = &t_delay; |
390 | break; | | 384 | break; |
391 | case 8: | | 385 | case 8: |
392 | printf("hard interrupt enter to exit:\n"); | | 386 | printf("hard interrupt enter to exit:\n"); |
393 | times = &t_hard_int; | | 387 | times = &t_hard_int; |
394 | break; | | 388 | break; |
395 | case 9: | | 389 | case 9: |
396 | printf("callback:\n"); | | 390 | printf("callback:\n"); |
397 | times = &t_callback; | | 391 | times = &t_callback; |
398 | break; | | 392 | break; |
399 | } | | 393 | } |
400 | | | 394 | |
401 | if (times->wraparound) | | 395 | if (times->wraparound) |
402 | for (i = times->current + 1; i < SLHCI_N_TIMES; i++) | | 396 | for (i = times->current + 1; i < SLHCI_N_TIMES; i++) |
403 | printf("start " CC_TYPE_FMT " stop " CC_TYPE_FMT | | 397 | printf("start " CC_TYPE_FMT " stop " CC_TYPE_FMT |
404 | " difference %8i miscdata %#x\n", | | 398 | " difference %8i miscdata %#x\n", |
405 | times->times[i].start, times->times[i].stop, | | 399 | times->times[i].start, times->times[i].stop, |
406 | (int)(times->times[i].stop - | | 400 | (int)(times->times[i].stop - |
407 | times->times[i].start), times->times[i].miscdata); | | 401 | times->times[i].start), times->times[i].miscdata); |
408 | | | 402 | |
409 | for (i = 0; i < times->current; i++) | | 403 | for (i = 0; i < times->current; i++) |
410 | printf("start " CC_TYPE_FMT " stop " CC_TYPE_FMT | | 404 | printf("start " CC_TYPE_FMT " stop " CC_TYPE_FMT |
411 | " difference %8i miscdata %#x\n", times->times[i].start, | | 405 | " difference %8i miscdata %#x\n", times->times[i].start, |
412 | times->times[i].stop, (int)(times->times[i].stop - | | 406 | times->times[i].stop, (int)(times->times[i].stop - |
413 | times->times[i].start), times->times[i].miscdata); | | 407 | times->times[i].start), times->times[i].miscdata); |
414 | } | | 408 | } |
415 | #else | | 409 | #else |
416 | #define start_cc_time(x, y) | | 410 | #define start_cc_time(x, y) |
417 | #define stop_cc_time(x) | | 411 | #define stop_cc_time(x) |
418 | #endif /* SLHCI_PROFILE_TRANSFER */ | | 412 | #endif /* SLHCI_PROFILE_TRANSFER */ |
419 | | | 413 | |
420 | typedef usbd_status (*LockCallFunc)(struct slhci_softc *, struct slhci_pipe | | 414 | typedef usbd_status (*LockCallFunc)(struct slhci_softc *, struct slhci_pipe |
421 | *, struct usbd_xfer *); | | 415 | *, struct usbd_xfer *); |
422 | | | 416 | |
423 | struct usbd_xfer * slhci_allocx(struct usbd_bus *, unsigned int); | | 417 | struct usbd_xfer * slhci_allocx(struct usbd_bus *, unsigned int); |
424 | void slhci_freex(struct usbd_bus *, struct usbd_xfer *); | | 418 | void slhci_freex(struct usbd_bus *, struct usbd_xfer *); |
425 | static void slhci_get_lock(struct usbd_bus *, kmutex_t **); | | 419 | static void slhci_get_lock(struct usbd_bus *, kmutex_t **); |
426 | | | 420 | |
427 | usbd_status slhci_transfer(struct usbd_xfer *); | | 421 | usbd_status slhci_transfer(struct usbd_xfer *); |
428 | usbd_status slhci_start(struct usbd_xfer *); | | 422 | usbd_status slhci_start(struct usbd_xfer *); |
429 | usbd_status slhci_root_start(struct usbd_xfer *); | | 423 | usbd_status slhci_root_start(struct usbd_xfer *); |
430 | usbd_status slhci_open(struct usbd_pipe *); | | 424 | usbd_status slhci_open(struct usbd_pipe *); |
431 | | | 425 | |
432 | static int slhci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *, | | 426 | static int slhci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *, |
433 | void *, int); | | 427 | void *, int); |
434 | | | 428 | |
435 | /* | | 429 | /* |
436 | * slhci_supported_rev, slhci_preinit, slhci_attach, slhci_detach, | | 430 | * slhci_supported_rev, slhci_preinit, slhci_attach, slhci_detach, |
437 | * slhci_activate | | 431 | * slhci_activate |
438 | */ | | 432 | */ |
439 | | | 433 | |
440 | void slhci_abort(struct usbd_xfer *); | | 434 | void slhci_abort(struct usbd_xfer *); |
441 | void slhci_close(struct usbd_pipe *); | | 435 | void slhci_close(struct usbd_pipe *); |
442 | void slhci_clear_toggle(struct usbd_pipe *); | | 436 | void slhci_clear_toggle(struct usbd_pipe *); |
443 | void slhci_poll(struct usbd_bus *); | | 437 | void slhci_poll(struct usbd_bus *); |
444 | void slhci_done(struct usbd_xfer *); | | 438 | void slhci_done(struct usbd_xfer *); |
445 | void slhci_void(void *); | | 439 | void slhci_void(void *); |
446 | | | 440 | |
447 | /* lock entry functions */ | | 441 | /* lock entry functions */ |
448 | | | 442 | |
449 | #ifdef SLHCI_MEM_ACCOUNTING | | 443 | #ifdef SLHCI_MEM_ACCOUNTING |
450 | void slhci_mem_use(struct usbd_bus *, int); | | 444 | void slhci_mem_use(struct usbd_bus *, int); |
451 | #endif | | 445 | #endif |
452 | | | 446 | |
453 | void slhci_reset_entry(void *); | | 447 | void slhci_reset_entry(void *); |
454 | usbd_status slhci_lock_call(struct slhci_softc *, LockCallFunc, | | 448 | usbd_status slhci_lock_call(struct slhci_softc *, LockCallFunc, |
455 | struct slhci_pipe *, struct usbd_xfer *); | | 449 | struct slhci_pipe *, struct usbd_xfer *); |
456 | void slhci_start_entry(struct slhci_softc *, struct slhci_pipe *); | | 450 | void slhci_start_entry(struct slhci_softc *, struct slhci_pipe *); |
457 | void slhci_callback_entry(void *arg); | | 451 | void slhci_callback_entry(void *arg); |
458 | void slhci_do_callback(struct slhci_softc *, struct usbd_xfer *); | | 452 | void slhci_do_callback(struct slhci_softc *, struct usbd_xfer *); |
459 | | | 453 | |
460 | /* slhci_intr */ | | 454 | /* slhci_intr */ |
461 | | | 455 | |
462 | void slhci_main(struct slhci_softc *); | | 456 | void slhci_main(struct slhci_softc *); |
463 | | | 457 | |
464 | /* in lock functions */ | | 458 | /* in lock functions */ |
465 | | | 459 | |
466 | static void slhci_write(struct slhci_softc *, uint8_t, uint8_t); | | 460 | static void slhci_write(struct slhci_softc *, uint8_t, uint8_t); |
467 | static uint8_t slhci_read(struct slhci_softc *, uint8_t); | | 461 | static uint8_t slhci_read(struct slhci_softc *, uint8_t); |
468 | static void slhci_write_multi(struct slhci_softc *, uint8_t, uint8_t *, int); | | 462 | static void slhci_write_multi(struct slhci_softc *, uint8_t, uint8_t *, int); |
469 | static void slhci_read_multi(struct slhci_softc *, uint8_t, uint8_t *, int); | | 463 | static void slhci_read_multi(struct slhci_softc *, uint8_t, uint8_t *, int); |
470 | | | 464 | |
471 | static void slhci_waitintr(struct slhci_softc *, int); | | 465 | static void slhci_waitintr(struct slhci_softc *, int); |
472 | static int slhci_dointr(struct slhci_softc *); | | 466 | static int slhci_dointr(struct slhci_softc *); |
473 | static void slhci_abdone(struct slhci_softc *, int); | | 467 | static void slhci_abdone(struct slhci_softc *, int); |
474 | static void slhci_tstart(struct slhci_softc *); | | 468 | static void slhci_tstart(struct slhci_softc *); |
475 | static void slhci_dotransfer(struct slhci_softc *); | | 469 | static void slhci_dotransfer(struct slhci_softc *); |
476 | | | 470 | |
477 | static void slhci_callback(struct slhci_softc *); | | 471 | static void slhci_callback(struct slhci_softc *); |
478 | static void slhci_enter_xfer(struct slhci_softc *, struct slhci_pipe *); | | 472 | static void slhci_enter_xfer(struct slhci_softc *, struct slhci_pipe *); |
479 | static void slhci_enter_xfers(struct slhci_softc *); | | 473 | static void slhci_enter_xfers(struct slhci_softc *); |
480 | static void slhci_queue_timed(struct slhci_softc *, struct slhci_pipe *); | | 474 | static void slhci_queue_timed(struct slhci_softc *, struct slhci_pipe *); |
481 | static void slhci_xfer_timer(struct slhci_softc *, struct slhci_pipe *); | | 475 | static void slhci_xfer_timer(struct slhci_softc *, struct slhci_pipe *); |
482 | | | 476 | |
483 | static void slhci_callback_schedule(struct slhci_softc *); | | 477 | static void slhci_callback_schedule(struct slhci_softc *); |
484 | static void slhci_do_callback_schedule(struct slhci_softc *); | | 478 | static void slhci_do_callback_schedule(struct slhci_softc *); |
485 | #if 0 | | 479 | #if 0 |
486 | void slhci_pollxfer(struct slhci_softc *, struct usbd_xfer *); /* XXX */ | | 480 | void slhci_pollxfer(struct slhci_softc *, struct usbd_xfer *); /* XXX */ |
487 | #endif | | 481 | #endif |
488 | | | 482 | |
489 | static usbd_status slhci_do_poll(struct slhci_softc *, struct slhci_pipe *, | | 483 | static usbd_status slhci_do_poll(struct slhci_softc *, struct slhci_pipe *, |
490 | struct usbd_xfer *); | | 484 | struct usbd_xfer *); |
491 | static usbd_status slhci_lsvh_warn(struct slhci_softc *, struct slhci_pipe *, | | 485 | static usbd_status slhci_lsvh_warn(struct slhci_softc *, struct slhci_pipe *, |
492 | struct usbd_xfer *); | | 486 | struct usbd_xfer *); |
493 | static usbd_status slhci_isoc_warn(struct slhci_softc *, struct slhci_pipe *, | | 487 | static usbd_status slhci_isoc_warn(struct slhci_softc *, struct slhci_pipe *, |
494 | struct usbd_xfer *); | | 488 | struct usbd_xfer *); |
495 | static usbd_status slhci_open_pipe(struct slhci_softc *, struct slhci_pipe *, | | 489 | static usbd_status slhci_open_pipe(struct slhci_softc *, struct slhci_pipe *, |
496 | struct usbd_xfer *); | | 490 | struct usbd_xfer *); |
497 | static usbd_status slhci_close_pipe(struct slhci_softc *, struct slhci_pipe *, | | 491 | static usbd_status slhci_close_pipe(struct slhci_softc *, struct slhci_pipe *, |
498 | struct usbd_xfer *); | | 492 | struct usbd_xfer *); |
499 | static usbd_status slhci_do_abort(struct slhci_softc *, struct slhci_pipe *, | | 493 | static usbd_status slhci_do_abort(struct slhci_softc *, struct slhci_pipe *, |
500 | struct usbd_xfer *); | | 494 | struct usbd_xfer *); |
501 | static usbd_status slhci_halt(struct slhci_softc *, struct slhci_pipe *, | | 495 | static usbd_status slhci_halt(struct slhci_softc *, struct slhci_pipe *, |
502 | struct usbd_xfer *); | | 496 | struct usbd_xfer *); |
503 | | | 497 | |
504 | static void slhci_intrchange(struct slhci_softc *, uint8_t); | | 498 | static void slhci_intrchange(struct slhci_softc *, uint8_t); |
505 | static void slhci_drain(struct slhci_softc *); | | 499 | static void slhci_drain(struct slhci_softc *); |
506 | static void slhci_reset(struct slhci_softc *); | | 500 | static void slhci_reset(struct slhci_softc *); |
507 | static int slhci_reserve_bustime(struct slhci_softc *, struct slhci_pipe *, | | 501 | static int slhci_reserve_bustime(struct slhci_softc *, struct slhci_pipe *, |
508 | int); | | 502 | int); |
509 | static void slhci_insert(struct slhci_softc *); | | 503 | static void slhci_insert(struct slhci_softc *); |
510 | | | 504 | |
511 | static usbd_status slhci_clear_feature(struct slhci_softc *, unsigned int); | | 505 | static usbd_status slhci_clear_feature(struct slhci_softc *, unsigned int); |
512 | static usbd_status slhci_set_feature(struct slhci_softc *, unsigned int); | | 506 | static usbd_status slhci_set_feature(struct slhci_softc *, unsigned int); |
513 | static void slhci_get_status(struct slhci_softc *, usb_port_status_t *); | | 507 | static void slhci_get_status(struct slhci_softc *, usb_port_status_t *); |
514 | | | 508 | |
515 | #define SLHCIHIST_FUNC() USBHIST_FUNC() | | 509 | #define SLHCIHIST_FUNC() USBHIST_FUNC() |
516 | #define SLHCIHIST_CALLED() USBHIST_CALLED(slhcidebug) | | 510 | #define SLHCIHIST_CALLED() USBHIST_CALLED(slhcidebug) |
517 | | | 511 | |
518 | #ifdef SLHCI_DEBUG | | 512 | #ifdef SLHCI_DEBUG |
519 | static int slhci_memtest(struct slhci_softc *); | | 513 | static int slhci_memtest(struct slhci_softc *); |
520 | | | 514 | |
521 | void slhci_log_buffer(struct usbd_xfer *); | | 515 | void slhci_log_buffer(struct usbd_xfer *); |
522 | void slhci_log_req(usb_device_request_t *); | | 516 | void slhci_log_req(usb_device_request_t *); |
523 | void slhci_log_dumpreg(void); | | 517 | void slhci_log_dumpreg(void); |
524 | void slhci_log_xfer(struct usbd_xfer *); | | 518 | void slhci_log_xfer(struct usbd_xfer *); |
525 | void slhci_log_spipe(struct slhci_pipe *); | | 519 | void slhci_log_spipe(struct slhci_pipe *); |
526 | void slhci_print_intr(void); | | 520 | void slhci_print_intr(void); |
527 | void slhci_log_sc(void); | | 521 | void slhci_log_sc(void); |
528 | void slhci_log_slreq(struct slhci_pipe *); | | 522 | void slhci_log_slreq(struct slhci_pipe *); |
529 | | | 523 | |
530 | /* Constified so you can read the values from ddb */ | | 524 | /* Constified so you can read the values from ddb */ |
531 | const int SLHCI_D_TRACE = 0x0001; | | 525 | const int SLHCI_D_TRACE = 0x0001; |
532 | const int SLHCI_D_MSG = 0x0002; | | 526 | const int SLHCI_D_MSG = 0x0002; |
533 | const int SLHCI_D_XFER = 0x0004; | | 527 | const int SLHCI_D_XFER = 0x0004; |
534 | const int SLHCI_D_MEM = 0x0008; | | 528 | const int SLHCI_D_MEM = 0x0008; |
535 | const int SLHCI_D_INTR = 0x0010; | | 529 | const int SLHCI_D_INTR = 0x0010; |
536 | const int SLHCI_D_SXFER = 0x0020; | | 530 | const int SLHCI_D_SXFER = 0x0020; |
537 | const int SLHCI_D_ERR = 0x0080; | | 531 | const int SLHCI_D_ERR = 0x0080; |
538 | const int SLHCI_D_BUF = 0x0100; | | 532 | const int SLHCI_D_BUF = 0x0100; |
539 | const int SLHCI_D_SOFT = 0x0200; | | 533 | const int SLHCI_D_SOFT = 0x0200; |
540 | const int SLHCI_D_WAIT = 0x0400; | | 534 | const int SLHCI_D_WAIT = 0x0400; |
541 | const int SLHCI_D_ROOT = 0x0800; | | 535 | const int SLHCI_D_ROOT = 0x0800; |
542 | /* SOF/NAK alone normally ignored, SOF also needs D_INTR */ | | 536 | /* SOF/NAK alone normally ignored, SOF also needs D_INTR */ |
543 | const int SLHCI_D_SOF = 0x1000; | | 537 | const int SLHCI_D_SOF = 0x1000; |
544 | const int SLHCI_D_NAK = 0x2000; | | 538 | const int SLHCI_D_NAK = 0x2000; |
545 | | | 539 | |
546 | int slhcidebug = 0x1cbc; /* 0xc8c; */ /* 0xffff; */ /* 0xd8c; */ | | 540 | int slhcidebug = 0x1cbc; /* 0xc8c; */ /* 0xffff; */ /* 0xd8c; */ |
547 | | | 541 | |
548 | SYSCTL_SETUP(sysctl_hw_slhci_setup, "sysctl hw.slhci setup") | | 542 | SYSCTL_SETUP(sysctl_hw_slhci_setup, "sysctl hw.slhci setup") |
549 | { | | 543 | { |
550 | int err; | | 544 | int err; |
551 | const struct sysctlnode *rnode; | | 545 | const struct sysctlnode *rnode; |
552 | const struct sysctlnode *cnode; | | 546 | const struct sysctlnode *cnode; |
553 | | | 547 | |
554 | err = sysctl_createv(clog, 0, NULL, &rnode, | | 548 | err = sysctl_createv(clog, 0, NULL, &rnode, |
555 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "slhci", | | 549 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "slhci", |
556 | SYSCTL_DESCR("slhci global controls"), | | 550 | SYSCTL_DESCR("slhci global controls"), |
557 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | | 551 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); |
558 | | | 552 | |
559 | if (err) | | 553 | if (err) |
560 | goto fail; | | 554 | goto fail; |
561 | | | 555 | |
562 | /* control debugging printfs */ | | 556 | /* control debugging printfs */ |
563 | err = sysctl_createv(clog, 0, &rnode, &cnode, | | 557 | err = sysctl_createv(clog, 0, &rnode, &cnode, |
564 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | | 558 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
565 | "debug", SYSCTL_DESCR("Enable debugging output"), | | 559 | "debug", SYSCTL_DESCR("Enable debugging output"), |
566 | NULL, 0, &slhcidebug, sizeof(slhcidebug), CTL_CREATE, CTL_EOL); | | 560 | NULL, 0, &slhcidebug, sizeof(slhcidebug), CTL_CREATE, CTL_EOL); |
567 | if (err) | | 561 | if (err) |
568 | goto fail; | | 562 | goto fail; |
569 | | | 563 | |
570 | return; | | 564 | return; |
571 | fail: | | 565 | fail: |
572 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | | 566 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); |
573 | } | | 567 | } |
574 | | | 568 | |
575 | struct slhci_softc *ssc; | | 569 | struct slhci_softc *ssc; |
576 | | | 570 | |
577 | #define SLHCI_DEXEC(x, y) do { if ((slhcidebug & SLHCI_ ## x)) { y; } \ | | 571 | #define SLHCI_DEXEC(x, y) do { if ((slhcidebug & SLHCI_ ## x)) { y; } \ |
578 | } while (/*CONSTCOND*/ 0) | | 572 | } while (/*CONSTCOND*/ 0) |
579 | #define DDOLOG(f, a, b, c, d) do { KERNHIST_LOG(usbhist, f, a, b, c, d); \ | | 573 | #define DDOLOG(f, a, b, c, d) do { KERNHIST_LOG(usbhist, f, a, b, c, d); \ |
580 | } while (/*CONSTCOND*/0) | | 574 | } while (/*CONSTCOND*/0) |
581 | #define DLOG(x, f, a, b, c, d) SLHCI_DEXEC(x, DDOLOG(f, a, b, c, d)) | | 575 | #define DLOG(x, f, a, b, c, d) SLHCI_DEXEC(x, DDOLOG(f, a, b, c, d)) |
582 | | | 576 | |
583 | /* | | 577 | /* |
584 | * DDOLOGBUF logs a buffer up to 8 bytes at a time. No identifier so that we | | 578 | * DDOLOGBUF logs a buffer up to 8 bytes at a time. No identifier so that we |
585 | * can make it a real function. | | 579 | * can make it a real function. |
586 | */ | | 580 | */ |
587 | static void | | 581 | static void |
588 | DDOLOGBUF(uint8_t *buf, unsigned int length) | | 582 | DDOLOGBUF(uint8_t *buf, unsigned int length) |
589 | { | | 583 | { |
590 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); | | 584 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); |
591 | int i; | | 585 | int i; |
592 | | | 586 | |
593 | for(i=0; i+8 <= length; i+=8) | | 587 | for(i=0; i+8 <= length; i+=8) |
594 | DDOLOG("%.4x %.4x %.4x %.4x", (buf[i] << 8) | buf[i+1], | | 588 | DDOLOG("%.4x %.4x %.4x %.4x", (buf[i] << 8) | buf[i+1], |
595 | (buf[i+2] << 8) | buf[i+3], (buf[i+4] << 8) | buf[i+5], | | 589 | (buf[i+2] << 8) | buf[i+3], (buf[i+4] << 8) | buf[i+5], |
596 | (buf[i+6] << 8) | buf[i+7]); | | 590 | (buf[i+6] << 8) | buf[i+7]); |
597 | if (length == i+7) | | 591 | if (length == i+7) |
598 | DDOLOG("%.4x %.4x %.4x %.2x", (buf[i] << 8) | buf[i+1], | | 592 | DDOLOG("%.4x %.4x %.4x %.2x", (buf[i] << 8) | buf[i+1], |
599 | (buf[i+2] << 8) | buf[i+3], (buf[i+4] << 8) | buf[i+5], | | 593 | (buf[i+2] << 8) | buf[i+3], (buf[i+4] << 8) | buf[i+5], |
600 | buf[i+6]); | | 594 | buf[i+6]); |
601 | else if (length == i+6) | | 595 | else if (length == i+6) |
602 | DDOLOG("%.4x %.4x %.4x", (buf[i] << 8) | buf[i+1], | | 596 | DDOLOG("%.4x %.4x %.4x", (buf[i] << 8) | buf[i+1], |
603 | (buf[i+2] << 8) | buf[i+3], (buf[i+4] << 8) | buf[i+5], 0); | | 597 | (buf[i+2] << 8) | buf[i+3], (buf[i+4] << 8) | buf[i+5], 0); |
604 | else if (length == i+5) | | 598 | else if (length == i+5) |
605 | DDOLOG("%.4x %.4x %.2x", (buf[i] << 8) | buf[i+1], | | 599 | DDOLOG("%.4x %.4x %.2x", (buf[i] << 8) | buf[i+1], |
606 | (buf[i+2] << 8) | buf[i+3], buf[i+4], 0); | | 600 | (buf[i+2] << 8) | buf[i+3], buf[i+4], 0); |
607 | else if (length == i+4) | | 601 | else if (length == i+4) |
608 | DDOLOG("%.4x %.4x", (buf[i] << 8) | buf[i+1], | | 602 | DDOLOG("%.4x %.4x", (buf[i] << 8) | buf[i+1], |
609 | (buf[i+2] << 8) | buf[i+3], 0,0); | | 603 | (buf[i+2] << 8) | buf[i+3], 0,0); |
610 | else if (length == i+3) | | 604 | else if (length == i+3) |
611 | DDOLOG("%.4x %.2x", (buf[i] << 8) | buf[i+1], buf[i+2], 0,0); | | 605 | DDOLOG("%.4x %.2x", (buf[i] << 8) | buf[i+1], buf[i+2], 0,0); |
612 | else if (length == i+2) | | 606 | else if (length == i+2) |
613 | DDOLOG("%.4x", (buf[i] << 8) | buf[i+1], 0,0,0); | | 607 | DDOLOG("%.4x", (buf[i] << 8) | buf[i+1], 0,0,0); |
614 | else if (length == i+1) | | 608 | else if (length == i+1) |
615 | DDOLOG("%.2x", buf[i], 0,0,0); | | 609 | DDOLOG("%.2x", buf[i], 0,0,0); |
616 | } | | 610 | } |
617 | #define DLOGBUF(x, b, l) SLHCI_DEXEC(x, DDOLOGBUF(b, l)) | | 611 | #define DLOGBUF(x, b, l) SLHCI_DEXEC(x, DDOLOGBUF(b, l)) |
618 | | | 612 | |
619 | #define DDOLOGCTRL(x) do { \ | | 613 | #define DDOLOGCTRL(x) do { \ |
620 | DDOLOG("CTRL suspend=%d", !!((x) & SL11_CTRL_SUSPEND), 0, 0, 0); \ | | 614 | DDOLOG("CTRL suspend=%d", !!((x) & SL11_CTRL_SUSPEND), 0, 0, 0); \ |
621 | DDOLOG("CTRL ls =%d jk =%d reset =%d sof =%d", \ | | 615 | DDOLOG("CTRL ls =%d jk =%d reset =%d sof =%d", \ |
622 | !!((x) & SL11_CTRL_LOWSPEED), !!((x) & SL11_CTRL_JKSTATE), \ | | 616 | !!((x) & SL11_CTRL_LOWSPEED), !!((x) & SL11_CTRL_JKSTATE), \ |
623 | !!((x) & SL11_CTRL_RESETENGINE), !!((x) & SL11_CTRL_ENABLESOF));\ | | 617 | !!((x) & SL11_CTRL_RESETENGINE), !!((x) & SL11_CTRL_ENABLESOF));\ |
624 | } while (0) | | 618 | } while (0) |
625 | | | 619 | |
626 | #define DDOLOGISR(r) do { \ | | 620 | #define DDOLOGISR(r) do { \ |
627 | DDOLOG("ISR data =%d det/res=%d insert =%d sof =%d", \ | | 621 | DDOLOG("ISR data =%d det/res=%d insert =%d sof =%d", \ |
628 | !!((r) & SL11_ISR_DATA), !!((r) & SL11_ISR_RESUME), \ | | 622 | !!((r) & SL11_ISR_DATA), !!((r) & SL11_ISR_RESUME), \ |
629 | !!((r) & SL11_ISR_INSERT), !!!!((r) & SL11_ISR_SOF)); \ | | 623 | !!((r) & SL11_ISR_INSERT), !!!!((r) & SL11_ISR_SOF)); \ |
630 | DDOLOG("ISR babble =%d usbb =%d usba =%d", \ | | 624 | DDOLOG("ISR babble =%d usbb =%d usba =%d", \ |
631 | !!((r) & SL11_ISR_BABBLE), !!((r) & SL11_ISR_USBB), \ | | 625 | !!((r) & SL11_ISR_BABBLE), !!((r) & SL11_ISR_USBB), \ |
632 | !!((r) & SL11_ISR_USBA), 0); \ | | 626 | !!((r) & SL11_ISR_USBA), 0); \ |
633 | } while (0) | | 627 | } while (0) |
634 | | | 628 | |
635 | #define DDOLOGIER(r) do { \ | | 629 | #define DDOLOGIER(r) do { \ |
636 | DDOLOG("IER det/res=%d insert =%d sof =%d", \ | | 630 | DDOLOG("IER det/res=%d insert =%d sof =%d", \ |
637 | !!((r) & SL11_IER_RESUME), \ | | 631 | !!((r) & SL11_IER_RESUME), \ |
638 | !!((r) & SL11_IER_INSERT), !!!!((r) & SL11_IER_SOF), 0); \ | | 632 | !!((r) & SL11_IER_INSERT), !!!!((r) & SL11_IER_SOF), 0); \ |
639 | DDOLOG("IER babble =%d usbb =%d usba =%d", \ | | 633 | DDOLOG("IER babble =%d usbb =%d usba =%d", \ |
640 | !!((r) & SL11_IER_BABBLE), !!((r) & SL11_IER_USBB), \ | | 634 | !!((r) & SL11_IER_BABBLE), !!((r) & SL11_IER_USBB), \ |
641 | !!((r) & SL11_IER_USBA), 0); \ | | 635 | !!((r) & SL11_IER_USBA), 0); \ |
642 | } while (0) | | 636 | } while (0) |
643 | | | 637 | |
644 | #define DDOLOGSTATUS(s) do { \ | | 638 | #define DDOLOGSTATUS(s) do { \ |
645 | DDOLOG("STAT stall =%d nak =%d overflow =%d setup =%d", \ | | 639 | DDOLOG("STAT stall =%d nak =%d overflow =%d setup =%d", \ |
646 | !!((s) & SL11_EPSTAT_STALL), !!((s) & SL11_EPSTAT_NAK), \ | | 640 | !!((s) & SL11_EPSTAT_STALL), !!((s) & SL11_EPSTAT_NAK), \ |
647 | !!((s) & SL11_EPSTAT_OVERFLOW), !!((s) & SL11_EPSTAT_SETUP)); \ | | 641 | !!((s) & SL11_EPSTAT_OVERFLOW), !!((s) & SL11_EPSTAT_SETUP)); \ |
648 | DDOLOG("STAT sequence=%d timeout =%d error =%d ack =%d", \ | | 642 | DDOLOG("STAT sequence=%d timeout =%d error =%d ack =%d", \ |
649 | !!((s) & SL11_EPSTAT_SEQUENCE), !!((s) & SL11_EPSTAT_TIMEOUT), \ | | 643 | !!((s) & SL11_EPSTAT_SEQUENCE), !!((s) & SL11_EPSTAT_TIMEOUT), \ |
650 | !!((s) & SL11_EPSTAT_ERROR), !!((s) & SL11_EPSTAT_ACK)); \ | | 644 | !!((s) & SL11_EPSTAT_ERROR), !!((s) & SL11_EPSTAT_ACK)); \ |
651 | } while (0) | | 645 | } while (0) |
652 | | | 646 | |
653 | #define DDOLOGEPCTRL(r) do { \ | | 647 | #define DDOLOGEPCTRL(r) do { \ |
654 | DDOLOG("CTRL preamble=%d toggle =%d sof =%d iso =%d", \ | | 648 | DDOLOG("CTRL preamble=%d toggle =%d sof =%d iso =%d", \ |
655 | !!((r) & SL11_EPCTRL_PREAMBLE), !!((r) & SL11_EPCTRL_DATATOGGLE),\ | | 649 | !!((r) & SL11_EPCTRL_PREAMBLE), !!((r) & SL11_EPCTRL_DATATOGGLE),\ |
656 | !!((r) & SL11_EPCTRL_SOF), !!((r) & SL11_EPCTRL_ISO)); \ | | 650 | !!((r) & SL11_EPCTRL_SOF), !!((r) & SL11_EPCTRL_ISO)); \ |
657 | DDOLOG("CTRL out =%d enable =%d arm =%d", \ | | 651 | DDOLOG("CTRL out =%d enable =%d arm =%d", \ |
658 | !!((r) & SL11_EPCTRL_DIRECTION), \ | | 652 | !!((r) & SL11_EPCTRL_DIRECTION), \ |
659 | !!((r) & SL11_EPCTRL_ENABLE), !!((r) & SL11_EPCTRL_ARM), 0); \ | | 653 | !!((r) & SL11_EPCTRL_ENABLE), !!((r) & SL11_EPCTRL_ARM), 0); \ |
660 | } while (0) | | 654 | } while (0) |
661 | | | 655 | |
662 | #define DDOLOGEPSTAT(r) do { \ | | 656 | #define DDOLOGEPSTAT(r) do { \ |
663 | DDOLOG("STAT stall =%d nak =%d overflow =%d setup =%d", \ | | 657 | DDOLOG("STAT stall =%d nak =%d overflow =%d setup =%d", \ |
664 | !!((r) & SL11_EPSTAT_STALL), !!((r) & SL11_EPSTAT_NAK), \ | | 658 | !!((r) & SL11_EPSTAT_STALL), !!((r) & SL11_EPSTAT_NAK), \ |
665 | !!((r) & SL11_EPSTAT_OVERFLOW), !!((r) & SL11_EPSTAT_SETUP)); \ | | 659 | !!((r) & SL11_EPSTAT_OVERFLOW), !!((r) & SL11_EPSTAT_SETUP)); \ |
666 | DDOLOG("STAT sequence=%d timeout =%d error =%d ack =%d", \ | | 660 | DDOLOG("STAT sequence=%d timeout =%d error =%d ack =%d", \ |
667 | !!((r) & SL11_EPSTAT_SEQUENCE), !!((r) & SL11_EPSTAT_TIMEOUT), \ | | 661 | !!((r) & SL11_EPSTAT_SEQUENCE), !!((r) & SL11_EPSTAT_TIMEOUT), \ |
668 | !!((r) & SL11_EPSTAT_ERROR), !!((r) & SL11_EPSTAT_ACK)); \ | | 662 | !!((r) & SL11_EPSTAT_ERROR), !!((r) & SL11_EPSTAT_ACK)); \ |
669 | } while (0) | | 663 | } while (0) |
670 | #else /* now !SLHCI_DEBUG */ | | 664 | #else /* now !SLHCI_DEBUG */ |
671 | #define slhcidebug 0 | | 665 | #define slhcidebug 0 |
672 | #define slhci_log_spipe(spipe) ((void)0) | | 666 | #define slhci_log_spipe(spipe) ((void)0) |
673 | #define slhci_log_xfer(xfer) ((void)0) | | 667 | #define slhci_log_xfer(xfer) ((void)0) |
674 | #define SLHCI_DEXEC(x, y) ((void)0) | | 668 | #define SLHCI_DEXEC(x, y) ((void)0) |
675 | #define DDOLOG(f, a, b, c, d) ((void)0) | | 669 | #define DDOLOG(f, a, b, c, d) ((void)0) |
676 | #define DLOG(x, f, a, b, c, d) ((void)0) | | 670 | #define DLOG(x, f, a, b, c, d) ((void)0) |
677 | #define DDOLOGBUF(b, l) ((void)0) | | 671 | #define DDOLOGBUF(b, l) ((void)0) |
678 | #define DLOGBUF(x, b, l) ((void)0) | | 672 | #define DLOGBUF(x, b, l) ((void)0) |
679 | #define DDOLOGCTRL(x) ((void)0) | | 673 | #define DDOLOGCTRL(x) ((void)0) |
680 | #define DDOLOGISR(r) ((void)0) | | 674 | #define DDOLOGISR(r) ((void)0) |
681 | #define DDOLOGIER(r) ((void)0) | | 675 | #define DDOLOGIER(r) ((void)0) |
682 | #define DDOLOGSTATUS(s) ((void)0) | | 676 | #define DDOLOGSTATUS(s) ((void)0) |
683 | #define DDOLOGEPCTRL(r) ((void)0) | | 677 | #define DDOLOGEPCTRL(r) ((void)0) |
684 | #define DDOLOGEPSTAT(r) ((void)0) | | 678 | #define DDOLOGEPSTAT(r) ((void)0) |
685 | #endif /* SLHCI_DEBUG */ | | 679 | #endif /* SLHCI_DEBUG */ |
686 | | | 680 | |
687 | #ifdef DIAGNOSTIC | | 681 | #ifdef DIAGNOSTIC |
688 | #define LK_SLASSERT(exp, sc, spipe, xfer, ext) do { \ | | 682 | #define LK_SLASSERT(exp, sc, spipe, xfer, ext) do { \ |
689 | if (!(exp)) { \ | | 683 | if (!(exp)) { \ |
690 | printf("%s: assertion %s failed line %u function %s!" \ | | 684 | printf("%s: assertion %s failed line %u function %s!" \ |
691 | " halted\n", SC_NAME(sc), #exp, __LINE__, __func__);\ | | 685 | " halted\n", SC_NAME(sc), #exp, __LINE__, __func__);\ |
692 | slhci_halt(sc, spipe, xfer); \ | | 686 | slhci_halt(sc, spipe, xfer); \ |
693 | ext; \ | | 687 | ext; \ |
694 | } \ | | 688 | } \ |
695 | } while (/*CONSTCOND*/0) | | 689 | } while (/*CONSTCOND*/0) |
696 | #define UL_SLASSERT(exp, sc, spipe, xfer, ext) do { \ | | 690 | #define UL_SLASSERT(exp, sc, spipe, xfer, ext) do { \ |
697 | if (!(exp)) { \ | | 691 | if (!(exp)) { \ |
698 | printf("%s: assertion %s failed line %u function %s!" \ | | 692 | printf("%s: assertion %s failed line %u function %s!" \ |
699 | " halted\n", SC_NAME(sc), #exp, __LINE__, __func__); \ | | 693 | " halted\n", SC_NAME(sc), #exp, __LINE__, __func__); \ |
700 | slhci_lock_call(sc, &slhci_halt, spipe, xfer); \ | | 694 | slhci_lock_call(sc, &slhci_halt, spipe, xfer); \ |
701 | ext; \ | | 695 | ext; \ |
702 | } \ | | 696 | } \ |
703 | } while (/*CONSTCOND*/0) | | 697 | } while (/*CONSTCOND*/0) |
704 | #else | | 698 | #else |
705 | #define LK_SLASSERT(exp, sc, spipe, xfer, ext) ((void)0) | | 699 | #define LK_SLASSERT(exp, sc, spipe, xfer, ext) ((void)0) |
706 | #define UL_SLASSERT(exp, sc, spipe, xfer, ext) ((void)0) | | 700 | #define UL_SLASSERT(exp, sc, spipe, xfer, ext) ((void)0) |
707 | #endif | | 701 | #endif |
708 | | | 702 | |
709 | const struct usbd_bus_methods slhci_bus_methods = { | | 703 | const struct usbd_bus_methods slhci_bus_methods = { |
710 | .ubm_open = slhci_open, | | 704 | .ubm_open = slhci_open, |
711 | .ubm_softint= slhci_void, | | 705 | .ubm_softint= slhci_void, |
712 | .ubm_dopoll = slhci_poll, | | 706 | .ubm_dopoll = slhci_poll, |
713 | .ubm_allocx = slhci_allocx, | | 707 | .ubm_allocx = slhci_allocx, |
714 | .ubm_freex = slhci_freex, | | 708 | .ubm_freex = slhci_freex, |
715 | .ubm_getlock = slhci_get_lock, | | 709 | .ubm_getlock = slhci_get_lock, |
716 | .ubm_rhctrl = slhci_roothub_ctrl, | | 710 | .ubm_rhctrl = slhci_roothub_ctrl, |
717 | }; | | 711 | }; |
718 | | | 712 | |
719 | const struct usbd_pipe_methods slhci_pipe_methods = { | | 713 | const struct usbd_pipe_methods slhci_pipe_methods = { |
720 | .upm_transfer = slhci_transfer, | | 714 | .upm_transfer = slhci_transfer, |
721 | .upm_start = slhci_start, | | 715 | .upm_start = slhci_start, |
722 | .upm_abort = slhci_abort, | | 716 | .upm_abort = slhci_abort, |
723 | .upm_close = slhci_close, | | 717 | .upm_close = slhci_close, |
724 | .upm_cleartoggle = slhci_clear_toggle, | | 718 | .upm_cleartoggle = slhci_clear_toggle, |
725 | .upm_done = slhci_done, | | 719 | .upm_done = slhci_done, |
726 | }; | | 720 | }; |
727 | | | 721 | |
728 | const struct usbd_pipe_methods slhci_root_methods = { | | 722 | const struct usbd_pipe_methods slhci_root_methods = { |
729 | .upm_transfer = slhci_transfer, | | 723 | .upm_transfer = slhci_transfer, |
730 | .upm_start = slhci_root_start, | | 724 | .upm_start = slhci_root_start, |
731 | .upm_abort = slhci_abort, | | 725 | .upm_abort = slhci_abort, |
732 | .upm_close = (void (*)(struct usbd_pipe *))slhci_void, /* XXX safe? */ | | 726 | .upm_close = (void (*)(struct usbd_pipe *))slhci_void, /* XXX safe? */ |
733 | .upm_cleartoggle = slhci_clear_toggle, | | 727 | .upm_cleartoggle = slhci_clear_toggle, |
734 | .upm_done = slhci_done, | | 728 | .upm_done = slhci_done, |
735 | }; | | 729 | }; |
736 | | | 730 | |
737 | /* Queue inlines */ | | 731 | /* Queue inlines */ |
738 | | | 732 | |
739 | #define GOT_FIRST_TO(tvar, t) \ | | 733 | #define GOT_FIRST_TO(tvar, t) \ |
740 | GCQ_GOT_FIRST_TYPED(tvar, &(t)->to, struct slhci_pipe, to) | | 734 | GCQ_GOT_FIRST_TYPED(tvar, &(t)->to, struct slhci_pipe, to) |
741 | | | 735 | |
742 | #define FIND_TO(var, t, tvar, cond) \ | | 736 | #define FIND_TO(var, t, tvar, cond) \ |
743 | GCQ_FIND_TYPED(var, &(t)->to, tvar, struct slhci_pipe, to, cond) | | 737 | GCQ_FIND_TYPED(var, &(t)->to, tvar, struct slhci_pipe, to, cond) |
744 | | | 738 | |
745 | #define FOREACH_AP(var, t, tvar) \ | | 739 | #define FOREACH_AP(var, t, tvar) \ |
746 | GCQ_FOREACH_TYPED(var, &(t)->ap, tvar, struct slhci_pipe, ap) | | 740 | GCQ_FOREACH_TYPED(var, &(t)->ap, tvar, struct slhci_pipe, ap) |
747 | | | 741 | |
748 | #define GOT_FIRST_TIMED_COND(tvar, t, cond) \ | | 742 | #define GOT_FIRST_TIMED_COND(tvar, t, cond) \ |
749 | GCQ_GOT_FIRST_COND_TYPED(tvar, &(t)->timed, struct slhci_pipe, xq, cond) | | 743 | GCQ_GOT_FIRST_COND_TYPED(tvar, &(t)->timed, struct slhci_pipe, xq, cond) |
750 | | | 744 | |
751 | #define GOT_FIRST_CB(tvar, t) \ | | 745 | #define GOT_FIRST_CB(tvar, t) \ |
752 | GCQ_GOT_FIRST_TYPED(tvar, &(t)->q[Q_CB], struct slhci_pipe, xq) | | 746 | GCQ_GOT_FIRST_TYPED(tvar, &(t)->q[Q_CB], struct slhci_pipe, xq) |
753 | | | 747 | |
754 | #define DEQUEUED_CALLBACK(tvar, t) \ | | 748 | #define DEQUEUED_CALLBACK(tvar, t) \ |
755 | GCQ_DEQUEUED_FIRST_TYPED(tvar, &(t)->q[Q_CALLBACKS], struct slhci_pipe, xq) | | 749 | GCQ_DEQUEUED_FIRST_TYPED(tvar, &(t)->q[Q_CALLBACKS], struct slhci_pipe, xq) |
756 | | | 750 | |
757 | #define FIND_TIMED(var, t, tvar, cond) \ | | 751 | #define FIND_TIMED(var, t, tvar, cond) \ |
758 | GCQ_FIND_TYPED(var, &(t)->timed, tvar, struct slhci_pipe, xq, cond) | | 752 | GCQ_FIND_TYPED(var, &(t)->timed, tvar, struct slhci_pipe, xq, cond) |
759 | | | 753 | |
760 | #define DEQUEUED_WAITQ(tvar, sc) \ | | 754 | #define DEQUEUED_WAITQ(tvar, sc) \ |
761 | GCQ_DEQUEUED_FIRST_TYPED(tvar, &(sc)->sc_waitq, struct slhci_pipe, xq) | | 755 | GCQ_DEQUEUED_FIRST_TYPED(tvar, &(sc)->sc_waitq, struct slhci_pipe, xq) |
762 | | | 756 | |
763 | static inline void | | 757 | static inline void |
764 | enter_waitq(struct slhci_softc *sc, struct slhci_pipe *spipe) | | 758 | enter_waitq(struct slhci_softc *sc, struct slhci_pipe *spipe) |
765 | { | | 759 | { |
766 | gcq_insert_tail(&sc->sc_waitq, &spipe->xq); | | 760 | gcq_insert_tail(&sc->sc_waitq, &spipe->xq); |
767 | } | | 761 | } |
768 | | | 762 | |
769 | static inline void | | 763 | static inline void |
770 | enter_q(struct slhci_transfers *t, struct slhci_pipe *spipe, int i) | | 764 | enter_q(struct slhci_transfers *t, struct slhci_pipe *spipe, int i) |
771 | { | | 765 | { |
772 | gcq_insert_tail(&t->q[i], &spipe->xq); | | 766 | gcq_insert_tail(&t->q[i], &spipe->xq); |
773 | } | | 767 | } |
774 | | | 768 | |
775 | static inline void | | 769 | static inline void |
776 | enter_callback(struct slhci_transfers *t, struct slhci_pipe *spipe) | | 770 | enter_callback(struct slhci_transfers *t, struct slhci_pipe *spipe) |
777 | { | | 771 | { |
778 | gcq_insert_tail(&t->q[Q_CALLBACKS], &spipe->xq); | | 772 | gcq_insert_tail(&t->q[Q_CALLBACKS], &spipe->xq); |
779 | } | | 773 | } |
780 | | | 774 | |
781 | static inline void | | 775 | static inline void |
782 | enter_all_pipes(struct slhci_transfers *t, struct slhci_pipe *spipe) | | 776 | enter_all_pipes(struct slhci_transfers *t, struct slhci_pipe *spipe) |
783 | { | | 777 | { |
784 | gcq_insert_tail(&t->ap, &spipe->ap); | | 778 | gcq_insert_tail(&t->ap, &spipe->ap); |
785 | } | | 779 | } |
786 | | | 780 | |
787 | /* Start out of lock functions. */ | | 781 | /* Start out of lock functions. */ |
788 | | | 782 | |
789 | struct usbd_xfer * | | 783 | struct usbd_xfer * |
790 | slhci_allocx(struct usbd_bus *bus, unsigned int nframes) | | 784 | slhci_allocx(struct usbd_bus *bus, unsigned int nframes) |
791 | { | | 785 | { |
792 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); | | 786 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); |
793 | struct usbd_xfer *xfer; | | 787 | struct usbd_xfer *xfer; |
794 | | | 788 | |
795 | xfer = kmem_zalloc(sizeof(*xfer), KM_SLEEP); | | 789 | xfer = kmem_zalloc(sizeof(*xfer), KM_SLEEP); |
796 | | | 790 | |
797 | DLOG(D_MEM, "allocx %p", xfer, 0,0,0); | | 791 | DLOG(D_MEM, "allocx %p", xfer, 0,0,0); |
798 | | | 792 | |
799 | #ifdef SLHCI_MEM_ACCOUNTING | | 793 | #ifdef SLHCI_MEM_ACCOUNTING |
800 | slhci_mem_use(bus, 1); | | 794 | slhci_mem_use(bus, 1); |
801 | #endif | | 795 | #endif |
802 | #ifdef DIAGNOSTIC | | 796 | #ifdef DIAGNOSTIC |
803 | if (xfer != NULL) | | 797 | if (xfer != NULL) |
804 | xfer->ux_state = XFER_BUSY; | | 798 | xfer->ux_state = XFER_BUSY; |
805 | #endif | | 799 | #endif |
806 | return xfer; | | 800 | return xfer; |
807 | } | | 801 | } |
808 | | | 802 | |
809 | void | | 803 | void |
810 | slhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | | 804 | slhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) |
811 | { | | 805 | { |
812 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); | | 806 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); |
813 | DLOG(D_MEM, "freex xfer %p spipe %p", xfer, xfer->ux_pipe,0,0); | | 807 | DLOG(D_MEM, "freex xfer %p spipe %p", xfer, xfer->ux_pipe,0,0); |
814 | | | 808 | |
815 | #ifdef SLHCI_MEM_ACCOUNTING | | 809 | #ifdef SLHCI_MEM_ACCOUNTING |
816 | slhci_mem_use(bus, -1); | | 810 | slhci_mem_use(bus, -1); |
817 | #endif | | 811 | #endif |
818 | #ifdef DIAGNOSTIC | | 812 | #ifdef DIAGNOSTIC |
819 | if (xfer->ux_state != XFER_BUSY) { | | 813 | if (xfer->ux_state != XFER_BUSY) { |
820 | struct slhci_softc *sc = SLHCI_BUS2SC(bus); | | 814 | struct slhci_softc *sc = SLHCI_BUS2SC(bus); |
821 | printf("%s: slhci_freex: xfer=%p not busy, %#08x halted\n", | | 815 | printf("%s: slhci_freex: xfer=%p not busy, %#08x halted\n", |
822 | SC_NAME(sc), xfer, xfer->ux_state); | | 816 | SC_NAME(sc), xfer, xfer->ux_state); |
823 | DDOLOG("xfer=%p not busy, %#08x halted\n", xfer, | | 817 | DDOLOG("xfer=%p not busy, %#08x halted\n", xfer, |
824 | xfer->ux_state, 0, 0); | | 818 | xfer->ux_state, 0, 0); |
825 | slhci_lock_call(sc, &slhci_halt, NULL, NULL); | | 819 | slhci_lock_call(sc, &slhci_halt, NULL, NULL); |
826 | return; | | 820 | return; |
827 | } | | 821 | } |
828 | xfer->ux_state = XFER_FREE; | | 822 | xfer->ux_state = XFER_FREE; |
829 | #endif | | 823 | #endif |
830 | | | 824 | |
831 | kmem_free(xfer, sizeof(*xfer)); | | 825 | kmem_free(xfer, sizeof(*xfer)); |
832 | } | | 826 | } |
833 | | | 827 | |
834 | static void | | 828 | static void |
835 | slhci_get_lock(struct usbd_bus *bus, kmutex_t **lock) | | 829 | slhci_get_lock(struct usbd_bus *bus, kmutex_t **lock) |
836 | { | | 830 | { |
837 | struct slhci_softc *sc = SLHCI_BUS2SC(bus); | | 831 | struct slhci_softc *sc = SLHCI_BUS2SC(bus); |
838 | | | 832 | |
839 | *lock = &sc->sc_lock; | | 833 | *lock = &sc->sc_lock; |
840 | } | | 834 | } |
841 | | | 835 | |
842 | usbd_status | | 836 | usbd_status |
843 | slhci_transfer(struct usbd_xfer *xfer) | | 837 | slhci_transfer(struct usbd_xfer *xfer) |
844 | { | | 838 | { |
845 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); | | 839 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); |
846 | struct slhci_softc *sc = SLHCI_XFER2SC(xfer); | | 840 | struct slhci_softc *sc = SLHCI_XFER2SC(xfer); |
847 | usbd_status error; | | 841 | usbd_status error; |
848 | | | 842 | |
849 | DLOG(D_TRACE, "transfer type %d xfer %p spipe %p ", | | 843 | DLOG(D_TRACE, "transfer type %d xfer %p spipe %p ", |
850 | SLHCI_XFER_TYPE(xfer), xfer, xfer->ux_pipe, 0); | | 844 | SLHCI_XFER_TYPE(xfer), xfer, xfer->ux_pipe, 0); |
851 | | | 845 | |
852 | /* Insert last in queue */ | | 846 | /* Insert last in queue */ |
853 | mutex_enter(&sc->sc_lock); | | 847 | mutex_enter(&sc->sc_lock); |
854 | error = usb_insert_transfer(xfer); | | 848 | error = usb_insert_transfer(xfer); |
855 | mutex_exit(&sc->sc_lock); | | 849 | mutex_exit(&sc->sc_lock); |
856 | if (error) { | | 850 | if (error) { |
857 | if (error != USBD_IN_PROGRESS) | | 851 | if (error != USBD_IN_PROGRESS) |
858 | DLOG(D_ERR, "usb_insert_transfer returns %d!", error, | | 852 | DLOG(D_ERR, "usb_insert_transfer returns %d!", error, |
859 | 0,0,0); | | 853 | 0,0,0); |
860 | return error; | | 854 | return error; |
861 | } | | 855 | } |
862 | | | 856 | |
863 | /* | | 857 | /* |
864 | * Pipe isn't running (otherwise error would be USBD_INPROG), | | 858 | * Pipe isn't running (otherwise error would be USBD_INPROG), |
865 | * so start it first. | | 859 | * so start it first. |
866 | */ | | 860 | */ |
867 | | | 861 | |
868 | /* | | 862 | /* |
869 | * Start will take the lock. | | 863 | * Start will take the lock. |
870 | */ | | 864 | */ |
871 | error = xfer->ux_pipe->up_methods->upm_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 865 | error = xfer->ux_pipe->up_methods->upm_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
872 | | | 866 | |
873 | return error; | | 867 | return error; |
874 | } | | 868 | } |
875 | | | 869 | |
876 | /* It is not safe for start to return anything other than USBD_INPROG. */ | | 870 | /* It is not safe for start to return anything other than USBD_INPROG. */ |
877 | usbd_status | | 871 | usbd_status |
878 | slhci_start(struct usbd_xfer *xfer) | | 872 | slhci_start(struct usbd_xfer *xfer) |
879 | { | | 873 | { |
880 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); | | 874 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); |
881 | struct slhci_softc *sc = SLHCI_XFER2SC(xfer); | | 875 | struct slhci_softc *sc = SLHCI_XFER2SC(xfer); |
882 | struct usbd_pipe *pipe = xfer->ux_pipe; | | 876 | struct usbd_pipe *pipe = xfer->ux_pipe; |
883 | struct slhci_pipe *spipe = SLHCI_PIPE2SPIPE(pipe); | | 877 | struct slhci_pipe *spipe = SLHCI_PIPE2SPIPE(pipe); |
884 | struct slhci_transfers *t = &sc->sc_transfers; | | 878 | struct slhci_transfers *t = &sc->sc_transfers; |
885 | usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc; | | 879 | usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc; |
886 | unsigned int max_packet; | | 880 | unsigned int max_packet; |
887 | | | 881 | |
888 | mutex_enter(&sc->sc_lock); | | 882 | mutex_enter(&sc->sc_lock); |
889 | | | 883 | |
890 | max_packet = UGETW(ed->wMaxPacketSize); | | 884 | max_packet = UGETW(ed->wMaxPacketSize); |
891 | | | 885 | |
892 | DLOG(D_TRACE, "transfer type %d start xfer %p spipe %p length %d", | | 886 | DLOG(D_TRACE, "transfer type %d start xfer %p spipe %p length %d", |
893 | spipe->ptype, xfer, spipe, xfer->ux_length); | | 887 | spipe->ptype, xfer, spipe, xfer->ux_length); |
894 | | | 888 | |
895 | /* root transfers use slhci_root_start */ | | 889 | /* root transfers use slhci_root_start */ |
896 | | | 890 | |
897 | KASSERT(spipe->xfer == NULL); /* not SLASSERT */ | | 891 | KASSERT(spipe->xfer == NULL); /* not SLASSERT */ |
898 | | | 892 | |
899 | xfer->ux_actlen = 0; | | 893 | xfer->ux_actlen = 0; |
900 | xfer->ux_status = USBD_IN_PROGRESS; | | 894 | xfer->ux_status = USBD_IN_PROGRESS; |
901 | | | 895 | |
902 | spipe->xfer = xfer; | | 896 | spipe->xfer = xfer; |
903 | | | 897 | |
904 | spipe->nerrs = 0; | | 898 | spipe->nerrs = 0; |
905 | spipe->frame = t->frame; | | 899 | spipe->frame = t->frame; |
906 | spipe->control = SL11_EPCTRL_ARM_ENABLE; | | 900 | spipe->control = SL11_EPCTRL_ARM_ENABLE; |
907 | spipe->tregs[DEV] = pipe->up_dev->ud_addr; | | 901 | spipe->tregs[DEV] = pipe->up_dev->ud_addr; |
908 | spipe->tregs[PID] = spipe->newpid = UE_GET_ADDR(ed->bEndpointAddress) | | 902 | spipe->tregs[PID] = spipe->newpid = UE_GET_ADDR(ed->bEndpointAddress) |
909 | | (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? SL11_PID_IN : | | 903 | | (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? SL11_PID_IN : |
910 | SL11_PID_OUT); | | 904 | SL11_PID_OUT); |
911 | spipe->newlen[0] = xfer->ux_length % max_packet; | | 905 | spipe->newlen[0] = xfer->ux_length % max_packet; |
912 | spipe->newlen[1] = min(xfer->ux_length, max_packet); | | 906 | spipe->newlen[1] = min(xfer->ux_length, max_packet); |
913 | | | 907 | |
914 | if (spipe->ptype == PT_BULK || spipe->ptype == PT_INTR) { | | 908 | if (spipe->ptype == PT_BULK || spipe->ptype == PT_INTR) { |
915 | if (spipe->pflags & PF_TOGGLE) | | 909 | if (spipe->pflags & PF_TOGGLE) |
916 | spipe->control |= SL11_EPCTRL_DATATOGGLE; | | 910 | spipe->control |= SL11_EPCTRL_DATATOGGLE; |
917 | spipe->tregs[LEN] = spipe->newlen[1]; | | 911 | spipe->tregs[LEN] = spipe->newlen[1]; |
918 | if (spipe->tregs[LEN]) | | 912 | if (spipe->tregs[LEN]) |
919 | spipe->buffer = xfer->ux_buf; | | 913 | spipe->buffer = xfer->ux_buf; |
920 | else | | 914 | else |
921 | spipe->buffer = NULL; | | 915 | spipe->buffer = NULL; |
922 | spipe->lastframe = t->frame; | | 916 | spipe->lastframe = t->frame; |
923 | if (spipe->ptype == PT_INTR) { | | 917 | if (spipe->ptype == PT_INTR) { |
924 | spipe->frame = spipe->lastframe + | | 918 | spipe->frame = spipe->lastframe + |
925 | spipe->pipe.up_interval; | | 919 | spipe->pipe.up_interval; |
926 | } | | 920 | } |
927 | | | 921 | |
928 | #if defined(DEBUG) || defined(SLHCI_DEBUG) | | 922 | #if defined(DEBUG) || defined(SLHCI_DEBUG) |
929 | if (__predict_false(spipe->ptype == PT_INTR && | | 923 | if (__predict_false(spipe->ptype == PT_INTR && |
930 | xfer->ux_length > spipe->tregs[LEN])) { | | 924 | xfer->ux_length > spipe->tregs[LEN])) { |
931 | printf("%s: Long INTR transfer not supported!\n", | | 925 | printf("%s: Long INTR transfer not supported!\n", |
932 | SC_NAME(sc)); | | 926 | SC_NAME(sc)); |
933 | DDOLOG("Long INTR transfer not supported!", 0, 0, 0, 0); | | 927 | DDOLOG("Long INTR transfer not supported!", 0, 0, 0, 0); |
934 | xfer->ux_status = USBD_INVAL; | | 928 | xfer->ux_status = USBD_INVAL; |
935 | } | | 929 | } |
936 | #endif | | 930 | #endif |
937 | } else { | | 931 | } else { |
938 | /* ptype may be currently set to any control transfer type. */ | | 932 | /* ptype may be currently set to any control transfer type. */ |
939 | SLHCI_DEXEC(D_TRACE, slhci_log_xfer(xfer)); | | 933 | SLHCI_DEXEC(D_TRACE, slhci_log_xfer(xfer)); |
940 | | | 934 | |
941 | /* SETUP contains IN/OUT bits also */ | | 935 | /* SETUP contains IN/OUT bits also */ |
942 | spipe->tregs[PID] |= SL11_PID_SETUP; | | 936 | spipe->tregs[PID] |= SL11_PID_SETUP; |
943 | spipe->tregs[LEN] = 8; | | 937 | spipe->tregs[LEN] = 8; |
944 | spipe->buffer = (uint8_t *)&xfer->ux_request; | | 938 | spipe->buffer = (uint8_t *)&xfer->ux_request; |
945 | DLOGBUF(D_XFER, spipe->buffer, spipe->tregs[LEN]); | | 939 | DLOGBUF(D_XFER, spipe->buffer, spipe->tregs[LEN]); |
946 | spipe->ptype = PT_CTRL_SETUP; | | 940 | spipe->ptype = PT_CTRL_SETUP; |
947 | spipe->newpid &= ~SL11_PID_BITS; | | 941 | spipe->newpid &= ~SL11_PID_BITS; |
948 | if (xfer->ux_length == 0 || | | 942 | if (xfer->ux_length == 0 || |
949 | (xfer->ux_request.bmRequestType & UT_READ)) | | 943 | (xfer->ux_request.bmRequestType & UT_READ)) |
950 | spipe->newpid |= SL11_PID_IN; | | 944 | spipe->newpid |= SL11_PID_IN; |
951 | else | | 945 | else |
952 | spipe->newpid |= SL11_PID_OUT; | | 946 | spipe->newpid |= SL11_PID_OUT; |
953 | } | | 947 | } |
954 | | | 948 | |
955 | if (xfer->ux_flags & USBD_FORCE_SHORT_XFER && | | 949 | if (xfer->ux_flags & USBD_FORCE_SHORT_XFER && |
956 | spipe->tregs[LEN] == max_packet && | | 950 | spipe->tregs[LEN] == max_packet && |
957 | (spipe->newpid & SL11_PID_BITS) == SL11_PID_OUT) | | 951 | (spipe->newpid & SL11_PID_BITS) == SL11_PID_OUT) |
958 | spipe->wantshort = 1; | | 952 | spipe->wantshort = 1; |
959 | else | | 953 | else |
960 | spipe->wantshort = 0; | | 954 | spipe->wantshort = 0; |
961 | | | 955 | |
962 | /* | | 956 | /* |
963 | * The goal of newbustime and newlen is to avoid bustime calculation | | 957 | * The goal of newbustime and newlen is to avoid bustime calculation |
964 | * in the interrupt. The calculations are not too complex, but they | | 958 | * in the interrupt. The calculations are not too complex, but they |
965 | * complicate the conditional logic somewhat and doing them all in the | | 959 | * complicate the conditional logic somewhat and doing them all in the |
966 | * same place shares constants. Index 0 is "short length" for bulk and | | 960 | * same place shares constants. Index 0 is "short length" for bulk and |
967 | * ctrl data and 1 is "full length" for ctrl data (bulk/intr are | | 961 | * ctrl data and 1 is "full length" for ctrl data (bulk/intr are |
968 | * already set to full length). | | 962 | * already set to full length). |
969 | */ | | 963 | */ |
970 | if (spipe->pflags & PF_LS) { | | 964 | if (spipe->pflags & PF_LS) { |
971 | /* | | 965 | /* |
972 | * Setting PREAMBLE for directly connected LS devices will | | 966 | * Setting PREAMBLE for directly connected LS devices will |
973 | * lock up the chip. | | 967 | * lock up the chip. |
974 | */ | | 968 | */ |
975 | if (spipe->pflags & PF_PREAMBLE) | | 969 | if (spipe->pflags & PF_PREAMBLE) |
976 | spipe->control |= SL11_EPCTRL_PREAMBLE; | | 970 | spipe->control |= SL11_EPCTRL_PREAMBLE; |
977 | if (max_packet <= 8) { | | 971 | if (max_packet <= 8) { |
978 | spipe->bustime = SLHCI_LS_CONST + | | 972 | spipe->bustime = SLHCI_LS_CONST + |
979 | SLHCI_LS_DATA_TIME(spipe->tregs[LEN]); | | 973 | SLHCI_LS_DATA_TIME(spipe->tregs[LEN]); |
980 | spipe->newbustime[0] = SLHCI_LS_CONST + | | 974 | spipe->newbustime[0] = SLHCI_LS_CONST + |
981 | SLHCI_LS_DATA_TIME(spipe->newlen[0]); | | 975 | SLHCI_LS_DATA_TIME(spipe->newlen[0]); |
982 | spipe->newbustime[1] = SLHCI_LS_CONST + | | 976 | spipe->newbustime[1] = SLHCI_LS_CONST + |
983 | SLHCI_LS_DATA_TIME(spipe->newlen[1]); | | 977 | SLHCI_LS_DATA_TIME(spipe->newlen[1]); |
984 | } else | | 978 | } else |
985 | xfer->ux_status = USBD_INVAL; | | 979 | xfer->ux_status = USBD_INVAL; |
986 | } else { | | 980 | } else { |
987 | UL_SLASSERT(pipe->up_dev->ud_speed == USB_SPEED_FULL, sc, | | 981 | UL_SLASSERT(pipe->up_dev->ud_speed == USB_SPEED_FULL, sc, |
988 | spipe, xfer, return USBD_IN_PROGRESS); | | 982 | spipe, xfer, return USBD_IN_PROGRESS); |
989 | if (max_packet <= SL11_MAX_PACKET_SIZE) { | | 983 | if (max_packet <= SL11_MAX_PACKET_SIZE) { |
990 | spipe->bustime = SLHCI_FS_CONST + | | 984 | spipe->bustime = SLHCI_FS_CONST + |
991 | SLHCI_FS_DATA_TIME(spipe->tregs[LEN]); | | 985 | SLHCI_FS_DATA_TIME(spipe->tregs[LEN]); |
992 | spipe->newbustime[0] = SLHCI_FS_CONST + | | 986 | spipe->newbustime[0] = SLHCI_FS_CONST + |
993 | SLHCI_FS_DATA_TIME(spipe->newlen[0]); | | 987 | SLHCI_FS_DATA_TIME(spipe->newlen[0]); |
994 | spipe->newbustime[1] = SLHCI_FS_CONST + | | 988 | spipe->newbustime[1] = SLHCI_FS_CONST + |
995 | SLHCI_FS_DATA_TIME(spipe->newlen[1]); | | 989 | SLHCI_FS_DATA_TIME(spipe->newlen[1]); |
996 | } else | | 990 | } else |
997 | xfer->ux_status = USBD_INVAL; | | 991 | xfer->ux_status = USBD_INVAL; |
998 | } | | 992 | } |
999 | | | 993 | |
1000 | /* | | 994 | /* |
1001 | * The datasheet incorrectly indicates that DIRECTION is for | | 995 | * The datasheet incorrectly indicates that DIRECTION is for |
1002 | * "transmit to host". It is for OUT and SETUP. The app note | | 996 | * "transmit to host". It is for OUT and SETUP. The app note |
1003 | * describes its use correctly. | | 997 | * describes its use correctly. |
1004 | */ | | 998 | */ |
1005 | if ((spipe->tregs[PID] & SL11_PID_BITS) != SL11_PID_IN) | | 999 | if ((spipe->tregs[PID] & SL11_PID_BITS) != SL11_PID_IN) |
1006 | spipe->control |= SL11_EPCTRL_DIRECTION; | | 1000 | spipe->control |= SL11_EPCTRL_DIRECTION; |
1007 | | | 1001 | |
1008 | slhci_start_entry(sc, spipe); | | 1002 | slhci_start_entry(sc, spipe); |
1009 | | | 1003 | |
1010 | mutex_exit(&sc->sc_lock); | | 1004 | mutex_exit(&sc->sc_lock); |
1011 | | | 1005 | |
1012 | return USBD_IN_PROGRESS; | | 1006 | return USBD_IN_PROGRESS; |
1013 | } | | 1007 | } |
1014 | | | 1008 | |
1015 | usbd_status | | 1009 | usbd_status |
1016 | slhci_root_start(struct usbd_xfer *xfer) | | 1010 | slhci_root_start(struct usbd_xfer *xfer) |
1017 | { | | 1011 | { |
1018 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); | | 1012 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); |
1019 | struct slhci_softc *sc; | | 1013 | struct slhci_softc *sc; |
1020 | struct slhci_pipe *spipe __diagused; | | 1014 | struct slhci_pipe *spipe __diagused; |
1021 | | | 1015 | |
1022 | spipe = SLHCI_PIPE2SPIPE(xfer->ux_pipe); | | 1016 | spipe = SLHCI_PIPE2SPIPE(xfer->ux_pipe); |
1023 | sc = SLHCI_XFER2SC(xfer); | | 1017 | sc = SLHCI_XFER2SC(xfer); |
1024 | | | 1018 | |
1025 | struct slhci_transfers *t = &sc->sc_transfers; | | 1019 | struct slhci_transfers *t = &sc->sc_transfers; |
1026 | | | 1020 | |
1027 | LK_SLASSERT(spipe != NULL && xfer != NULL, sc, spipe, xfer, return | | 1021 | LK_SLASSERT(spipe != NULL && xfer != NULL, sc, spipe, xfer, return |
1028 | USBD_CANCELLED); | | 1022 | USBD_CANCELLED); |
1029 | | | 1023 | |
1030 | DLOG(D_TRACE, "transfer type %d start", SLHCI_XFER_TYPE(xfer), 0, 0, 0); | | 1024 | DLOG(D_TRACE, "transfer type %d start", SLHCI_XFER_TYPE(xfer), 0, 0, 0); |
1031 | | | 1025 | |
1032 | KASSERT(spipe->ptype == PT_ROOT_INTR); | | 1026 | KASSERT(spipe->ptype == PT_ROOT_INTR); |
1033 | | | 1027 | |
1034 | mutex_enter(&sc->sc_intr_lock); | | 1028 | mutex_enter(&sc->sc_intr_lock); |
1035 | t->rootintr = xfer; | | 1029 | t->rootintr = xfer; |
1036 | mutex_exit(&sc->sc_intr_lock); | | 1030 | mutex_exit(&sc->sc_intr_lock); |
1037 | | | 1031 | |
1038 | return USBD_IN_PROGRESS; | | 1032 | return USBD_IN_PROGRESS; |
1039 | } | | 1033 | } |
1040 | | | 1034 | |
1041 | usbd_status | | 1035 | usbd_status |
1042 | slhci_open(struct usbd_pipe *pipe) | | 1036 | slhci_open(struct usbd_pipe *pipe) |
1043 | { | | 1037 | { |
1044 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); | | 1038 | SLHCIHIST_FUNC(); SLHCIHIST_CALLED(); |
1045 | struct usbd_device *dev; | | 1039 | struct usbd_device *dev; |
1046 | struct slhci_softc *sc; | | 1040 | struct slhci_softc *sc; |
1047 | struct slhci_pipe *spipe; | | 1041 | struct slhci_pipe *spipe; |
1048 | usb_endpoint_descriptor_t *ed; | | 1042 | usb_endpoint_descriptor_t *ed; |
1049 | unsigned int max_packet, pmaxpkt; | | 1043 | unsigned int max_packet, pmaxpkt; |
1050 | uint8_t rhaddr; | | 1044 | uint8_t rhaddr; |
1051 | | | 1045 | |
1052 | dev = pipe->up_dev; | | 1046 | dev = pipe->up_dev; |
1053 | sc = SLHCI_PIPE2SC(pipe); | | 1047 | sc = SLHCI_PIPE2SC(pipe); |
1054 | spipe = SLHCI_PIPE2SPIPE(pipe); | | 1048 | spipe = SLHCI_PIPE2SPIPE(pipe); |
1055 | ed = pipe->up_endpoint->ue_edesc; | | 1049 | ed = pipe->up_endpoint->ue_edesc; |
1056 | rhaddr = dev->ud_bus->ub_rhaddr; | | 1050 | rhaddr = dev->ud_bus->ub_rhaddr; |
1057 | | | 1051 | |
1058 | DLOG(D_TRACE, "slhci_open(addr=%d,ep=%d,rootaddr=%d)", | | 1052 | DLOG(D_TRACE, "slhci_open(addr=%d,ep=%d,rootaddr=%d)", |
1059 | dev->ud_addr, ed->bEndpointAddress, rhaddr, 0); | | 1053 | dev->ud_addr, ed->bEndpointAddress, rhaddr, 0); |
1060 | | | 1054 | |
1061 | spipe->pflags = 0; | | 1055 | spipe->pflags = 0; |
1062 | spipe->frame = 0; | | 1056 | spipe->frame = 0; |
1063 | spipe->lastframe = 0; | | 1057 | spipe->lastframe = 0; |
1064 | spipe->xfer = NULL; | | 1058 | spipe->xfer = NULL; |
1065 | spipe->buffer = NULL; | | 1059 | spipe->buffer = NULL; |
1066 | | | 1060 | |
1067 | gcq_init(&spipe->ap); | | 1061 | gcq_init(&spipe->ap); |
1068 | gcq_init(&spipe->to); | | 1062 | gcq_init(&spipe->to); |
1069 | gcq_init(&spipe->xq); | | 1063 | gcq_init(&spipe->xq); |
1070 | | | 1064 | |
1071 | /* | | 1065 | /* |
1072 | * The endpoint descriptor will not have been set up yet in the case | | 1066 | * The endpoint descriptor will not have been set up yet in the case |
1073 | * of the standard control pipe, so the max packet checks are also | | 1067 | * of the standard control pipe, so the max packet checks are also |
1074 | * necessary in start. | | 1068 | * necessary in start. |
1075 | */ | | 1069 | */ |
1076 | | | 1070 | |
1077 | max_packet = UGETW(ed->wMaxPacketSize); | | 1071 | max_packet = UGETW(ed->wMaxPacketSize); |
1078 | | | 1072 | |
1079 | if (dev->ud_speed == USB_SPEED_LOW) { | | 1073 | if (dev->ud_speed == USB_SPEED_LOW) { |
1080 | spipe->pflags |= PF_LS; | | 1074 | spipe->pflags |= PF_LS; |
1081 | if (dev->ud_myhub->ud_addr != rhaddr) { | | 1075 | if (dev->ud_myhub->ud_addr != rhaddr) { |
1082 | spipe->pflags |= PF_PREAMBLE; | | 1076 | spipe->pflags |= PF_PREAMBLE; |
1083 | if (!slhci_try_lsvh) | | 1077 | if (!slhci_try_lsvh) |
1084 | return slhci_lock_call(sc, &slhci_lsvh_warn, | | 1078 | return slhci_lock_call(sc, &slhci_lsvh_warn, |
1085 | spipe, NULL); | | 1079 | spipe, NULL); |
1086 | } | | 1080 | } |
1087 | pmaxpkt = 8; | | 1081 | pmaxpkt = 8; |
1088 | } else | | 1082 | } else |
1089 | pmaxpkt = SL11_MAX_PACKET_SIZE; | | 1083 | pmaxpkt = SL11_MAX_PACKET_SIZE; |
1090 | | | 1084 | |
1091 | if (max_packet > pmaxpkt) { | | 1085 | if (max_packet > pmaxpkt) { |
1092 | DLOG(D_ERR, "packet too large! size %d spipe %p", max_packet, | | 1086 | DLOG(D_ERR, "packet too large! size %d spipe %p", max_packet, |
1093 | spipe, 0,0); | | 1087 | spipe, 0,0); |
1094 | return USBD_INVAL; | | 1088 | return USBD_INVAL; |
1095 | } | | 1089 | } |
1096 | | | 1090 | |
1097 | if (dev->ud_addr == rhaddr) { | | 1091 | if (dev->ud_addr == rhaddr) { |
1098 | switch (ed->bEndpointAddress) { | | 1092 | switch (ed->bEndpointAddress) { |
1099 | case USB_CONTROL_ENDPOINT: | | 1093 | case USB_CONTROL_ENDPOINT: |
1100 | spipe->ptype = PT_ROOT_CTRL; | | 1094 | spipe->ptype = PT_ROOT_CTRL; |
1101 | pipe->up_interval = 0; | | 1095 | pipe->up_interval = 0; |
1102 | pipe->up_methods = &roothub_ctrl_methods; | | 1096 | pipe->up_methods = &roothub_ctrl_methods; |
1103 | break; | | 1097 | break; |
1104 | case UE_DIR_IN | USBROOTHUB_INTR_ENDPT: | | 1098 | case UE_DIR_IN | USBROOTHUB_INTR_ENDPT: |
1105 | spipe->ptype = PT_ROOT_INTR; | | 1099 | spipe->ptype = PT_ROOT_INTR; |
1106 | pipe->up_interval = 1; | | 1100 | pipe->up_interval = 1; |
1107 | pipe->up_methods = &slhci_root_methods; | | 1101 | pipe->up_methods = &slhci_root_methods; |
1108 | break; | | 1102 | break; |
1109 | default: | | 1103 | default: |
1110 | printf("%s: Invalid root endpoint!\n", SC_NAME(sc)); | | 1104 | printf("%s: Invalid root endpoint!\n", SC_NAME(sc)); |
1111 | DDOLOG("Invalid root endpoint", 0, 0, 0, 0); | | 1105 | DDOLOG("Invalid root endpoint", 0, 0, 0, 0); |
1112 | return USBD_INVAL; | | 1106 | return USBD_INVAL; |
1113 | } | | 1107 | } |
1114 | return USBD_NORMAL_COMPLETION; | | 1108 | return USBD_NORMAL_COMPLETION; |
1115 | } else { | | 1109 | } else { |
1116 | switch (ed->bmAttributes & UE_XFERTYPE) { | | 1110 | switch (ed->bmAttributes & UE_XFERTYPE) { |
1117 | case UE_CONTROL: | | 1111 | case UE_CONTROL: |
1118 | spipe->ptype = PT_CTRL_SETUP; | | 1112 | spipe->ptype = PT_CTRL_SETUP; |
1119 | pipe->up_interval = 0; | | 1113 | pipe->up_interval = 0; |
1120 | break; | | 1114 | break; |
1121 | case UE_INTERRUPT: | | 1115 | case UE_INTERRUPT: |
1122 | spipe->ptype = PT_INTR; | | 1116 | spipe->ptype = PT_INTR; |
1123 | if (pipe->up_interval == USBD_DEFAULT_INTERVAL) | | 1117 | if (pipe->up_interval == USBD_DEFAULT_INTERVAL) |
1124 | pipe->up_interval = ed->bInterval; | | 1118 | pipe->up_interval = ed->bInterval; |
1125 | break; | | 1119 | break; |
1126 | case UE_ISOCHRONOUS: | | 1120 | case UE_ISOCHRONOUS: |
1127 | return slhci_lock_call(sc, &slhci_isoc_warn, spipe, | | 1121 | return slhci_lock_call(sc, &slhci_isoc_warn, spipe, |
1128 | NULL); | | 1122 | NULL); |
1129 | case UE_BULK: | | 1123 | case UE_BULK: |
1130 | spipe->ptype = PT_BULK; | | 1124 | spipe->ptype = PT_BULK; |
1131 | pipe->up_interval = 0; | | 1125 | pipe->up_interval = 0; |
1132 | break; | | 1126 | break; |
1133 | } | | 1127 | } |
1134 | | | 1128 | |
1135 | DLOG(D_MSG, "open pipe type %d interval %d", spipe->ptype, | | 1129 | DLOG(D_MSG, "open pipe type %d interval %d", spipe->ptype, |
1136 | pipe->up_interval, 0,0); | | 1130 | pipe->up_interval, 0,0); |
1137 | | | 1131 | |
1138 | pipe->up_methods = __UNCONST(&slhci_pipe_methods); | | 1132 | pipe->up_methods = __UNCONST(&slhci_pipe_methods); |
1139 | | | 1133 | |
1140 | return slhci_lock_call(sc, &slhci_open_pipe, spipe, NULL); | | 1134 | return slhci_lock_call(sc, &slhci_open_pipe, spipe, NULL); |
1141 | } | | 1135 | } |
1142 | } | | 1136 | } |
1143 | | | 1137 | |
1144 | int | | 1138 | int |
1145 | slhci_supported_rev(uint8_t rev) | | 1139 | slhci_supported_rev(uint8_t rev) |
1146 | { | | 1140 | { |
1147 | return rev >= SLTYPE_SL811HS_R12 && rev <= SLTYPE_SL811HS_R15; | | 1141 | return rev >= SLTYPE_SL811HS_R12 && rev <= SLTYPE_SL811HS_R15; |
1148 | } | | 1142 | } |
1149 | | | 1143 | |
1150 | /* | | 1144 | /* |
1151 | * Must be called before the ISR is registered. Interrupts can be shared so | | 1145 | * Must be called before the ISR is registered. Interrupts can be shared so |
1152 | * slhci_intr could be called as soon as the ISR is registered. | | 1146 | * slhci_intr could be called as soon as the ISR is registered. |
1153 | * Note max_current argument is actual current, but stored as current/2 | | 1147 | * Note max_current argument is actual current, but stored as current/2 |
1154 | */ | | 1148 | */ |
1155 | void | | 1149 | void |
1156 | slhci_preinit(struct slhci_softc *sc, PowerFunc pow, bus_space_tag_t iot, | | 1150 | slhci_preinit(struct slhci_softc *sc, PowerFunc pow, bus_space_tag_t iot, |
1157 | bus_space_handle_t ioh, uint16_t max_current, uint32_t stride) | | 1151 | bus_space_handle_t ioh, uint16_t max_current, uint32_t stride) |
1158 | { | | 1152 | { |
1159 | struct slhci_transfers *t; | | 1153 | struct slhci_transfers *t; |
1160 | int i; | | 1154 | int i; |
1161 | | | 1155 | |
1162 | t = &sc->sc_transfers; | | 1156 | t = &sc->sc_transfers; |
1163 | | | 1157 | |
1164 | #ifdef SLHCI_DEBUG | | 1158 | #ifdef SLHCI_DEBUG |
1165 | ssc = sc; | | 1159 | ssc = sc; |
1166 | #endif | | 1160 | #endif |
1167 | | | 1161 | |
1168 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 1162 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); |
1169 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | | 1163 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); |
1170 | | | 1164 | |
1171 | /* sc->sc_ier = 0; */ | | 1165 | /* sc->sc_ier = 0; */ |
1172 | /* t->rootintr = NULL; */ | | 1166 | /* t->rootintr = NULL; */ |
1173 | t->flags = F_NODEV|F_UDISABLED; | | 1167 | t->flags = F_NODEV|F_UDISABLED; |
1174 | t->pend = INT_MAX; | | 1168 | t->pend = INT_MAX; |
1175 | KASSERT(slhci_wait_time != INT_MAX); | | 1169 | KASSERT(slhci_wait_time != INT_MAX); |
1176 | t->len[0] = t->len[1] = -1; | | 1170 | t->len[0] = t->len[1] = -1; |
1177 | if (max_current > 500) | | 1171 | if (max_current > 500) |
1178 | max_current = 500; | | 1172 | max_current = 500; |
1179 | t->max_current = (uint8_t)(max_current / 2); | | 1173 | t->max_current = (uint8_t)(max_current / 2); |
1180 | sc->sc_enable_power = pow; | | 1174 | sc->sc_enable_power = pow; |
1181 | sc->sc_iot = iot; | | 1175 | sc->sc_iot = iot; |
1182 | sc->sc_ioh = ioh; | | 1176 | sc->sc_ioh = ioh; |
1183 | sc->sc_stride = stride; | | 1177 | sc->sc_stride = stride; |
1184 | | | 1178 | |
1185 | KASSERT(Q_MAX+1 == sizeof(t->q) / sizeof(t->q[0])); | | 1179 | KASSERT(Q_MAX+1 == sizeof(t->q) / sizeof(t->q[0])); |
1186 | | | 1180 | |
1187 | for (i = 0; i <= Q_MAX; i++) | | 1181 | for (i = 0; i <= Q_MAX; i++) |
1188 | gcq_init_head(&t->q[i]); | | 1182 | gcq_init_head(&t->q[i]); |
1189 | gcq_init_head(&t->timed); | | 1183 | gcq_init_head(&t->timed); |
1190 | gcq_init_head(&t->to); | | 1184 | gcq_init_head(&t->to); |
1191 | gcq_init_head(&t->ap); | | 1185 | gcq_init_head(&t->ap); |
1192 | gcq_init_head(&sc->sc_waitq); | | 1186 | gcq_init_head(&sc->sc_waitq); |