3 * Copyright (C) 2008-2010 coresystems GmbH
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, 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
31 #include <arch/virtual.h>
35 #include "uhci_private.h"
37 static void uhci_start(hci_t
*controller
);
38 static void uhci_stop(hci_t
*controller
);
39 static void uhci_reset(hci_t
*controller
);
40 static void uhci_shutdown(hci_t
*controller
);
41 static int uhci_bulk(endpoint_t
*ep
, int size
, u8
*data
, int finalize
);
42 static int uhci_control(usbdev_t
*dev
, direction_t dir
, int drlen
, void *devreq
,
44 static void* uhci_create_intr_queue(endpoint_t
*ep
, int reqsize
, int reqcount
, int reqtiming
);
45 static void uhci_destroy_intr_queue(endpoint_t
*ep
, void *queue
);
46 static u8
* uhci_poll_intr_queue(void *queue
);
51 uhci_dump(hci_t
*controller
)
53 usb_debug("dump:\nUSBCMD: %x\n", uhci_reg_read16(controller
, USBCMD
));
54 usb_debug("USBSTS: %x\n", uhci_reg_read16(controller
, USBSTS
));
55 usb_debug("USBINTR: %x\n", uhci_reg_read16(controller
, USBINTR
));
56 usb_debug("FRNUM: %x\n", uhci_reg_read16(controller
, FRNUM
));
57 usb_debug("FLBASEADD: %x\n", uhci_reg_read32(controller
, FLBASEADD
));
58 usb_debug("SOFMOD: %x\n", uhci_reg_read8(controller
, SOFMOD
));
59 usb_debug("PORTSC1: %x\n", uhci_reg_read16(controller
, PORTSC1
));
60 usb_debug("PORTSC2: %x\n", uhci_reg_read16(controller
, PORTSC2
));
64 static void td_dump(td_t
*td
)
66 usb_debug("+---------------------------------------------------+\n");
67 if ((td
->token
& TD_PID_MASK
) == UHCI_SETUP
)
68 usb_debug("|..[SETUP]..........................................|\n");
69 else if ((td
->token
& TD_PID_MASK
) == UHCI_IN
)
70 usb_debug("|..[IN].............................................|\n");
71 else if ((td
->token
& TD_PID_MASK
) == UHCI_OUT
)
72 usb_debug("|..[OUT]............................................|\n");
74 usb_debug("|..[]...............................................|\n");
75 usb_debug("|:|============ UHCI TD at [0x%08lx] ==========|:|\n", virt_to_phys(td
));
76 usb_debug("|:+-----------------------------------------------+:|\n");
77 usb_debug("|:| Next TD/QH [0x%08lx] |:|\n", td
->ptr
& ~0xFUL
);
78 usb_debug("|:+-----------------------------------------------+:|\n");
79 usb_debug("|:| Depth/Breath [%lx] | QH/TD [%lx] | TERMINATE [%lx] |:|\n",
80 (td
->ptr
& (1UL << 2)) >> 2, (td
->ptr
& (1UL << 1)) >> 1, td
->ptr
& 1UL);
81 usb_debug("|:+-----------------------------------------------+:|\n");
82 usb_debug("|:| T | Maximum Length | [%04lx] |:|\n", (td
->token
& (0x7FFUL
<< 21)) >> 21);
83 usb_debug("|:| O | PID CODE | [%04"PRIx32
"] |:|\n", td
->token
& 0xFF);
84 usb_debug("|:| K | Endpoint | [%04"PRIx32
"] |:|\n", (td
->token
& TD_EP_MASK
) >> TD_EP_SHIFT
);
85 usb_debug("|:| E | Device Address | [%04lx] |:|\n", (td
->token
& (0x7FUL
<< 8)) >> 8);
86 usb_debug("|:| N | Data Toggle | [%lx] |:|\n", (td
->token
& (1UL << 19)) >> 19);
87 usb_debug("|:+-----------------------------------------------+:|\n");
88 usb_debug("|:| C | Short Packet Detector | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 29)) >> 29);
89 usb_debug("|:| O | Error Counter | [%lx] |:|\n",
90 (td
->ctrlsts
& (3UL << TD_COUNTER_SHIFT
)) >> TD_COUNTER_SHIFT
);
91 usb_debug("|:| N | Low Speed Device | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 26)) >> 26);
92 usb_debug("|:| T | Isochronous Select | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 25)) >> 25);
93 usb_debug("|:| R | Interrupt on Complete (IOC) | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 24)) >> 24);
94 usb_debug("|:+ O ----------------------------------------+:|\n");
95 usb_debug("|:| L | Active | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 23)) >> 23);
96 usb_debug("|:| & | Stalled | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 22)) >> 22);
97 usb_debug("|:| S | Data Buffer Error | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 21)) >> 21);
98 usb_debug("|:| T | Bubble Detected | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 20)) >> 20);
99 usb_debug("|:| A | NAK Received | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 19)) >> 19);
100 usb_debug("|:| T | CRC/Timeout Error | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 18)) >> 18);
101 usb_debug("|:| U | Bitstuff Error | [%lx] |:|\n", (td
->ctrlsts
& (1UL << 17)) >> 17);
102 usb_debug("|:| S ----------------------------------------|:|\n");
103 usb_debug("|:| | Actual Length | [%04lx] |:|\n", td
->ctrlsts
& 0x7FFUL
);
104 usb_debug("|:+-----------------------------------------------+:|\n");
105 usb_debug("|:| Buffer pointer [0x%08"PRIx32
"] |:|\n", td
->bufptr
);
106 usb_debug("|:|-----------------------------------------------|:|\n");
107 usb_debug("|...................................................|\n");
108 usb_debug("+---------------------------------------------------+\n");
112 uhci_reset(hci_t
*controller
)
115 uhci_reg_write16(controller
, USBCMD
, 4); /* Global Reset */
116 mdelay(50); /* uhci spec 2.1.1: at least 10ms */
117 uhci_reg_write16(controller
, USBCMD
, 0);
119 uhci_reg_write16(controller
, USBCMD
, 2); /* Host Controller Reset */
120 /* wait for controller to finish reset */
121 /* TOTEST: how long to wait? 100ms for now */
122 int timeout
= 200; /* time out after 200 * 500us == 100ms */
123 while (((uhci_reg_read16(controller
, USBCMD
) & 2) != 0) && timeout
--)
126 usb_debug("Warning: uhci: host controller reset timed out.\n");
130 uhci_reinit(hci_t
*controller
)
132 uhci_reg_write32(controller
, FLBASEADD
,
133 (u32
) virt_to_phys(UHCI_INST(controller
)->
135 //usb_debug ("framelist at %p\n",UHCI_INST(controller)->framelistptr);
138 uhci_reg_write16(controller
, USBINTR
, 0);
140 /* reset framelist index */
141 uhci_reg_write16(controller
, FRNUM
, 0);
143 uhci_reg_write16(controller
, USBCMD
,
144 uhci_reg_read16(controller
, USBCMD
) | 0xc0); // max packets, configure flag
146 uhci_start(controller
);
150 uhci_pci_init(pcidev_t addr
)
155 hci_t
*controller
= new_controller();
156 controller
->pcidev
= addr
;
157 controller
->instance
= xzalloc(sizeof(uhci_t
));
158 controller
->type
= UHCI
;
159 controller
->start
= uhci_start
;
160 controller
->stop
= uhci_stop
;
161 controller
->reset
= uhci_reset
;
162 controller
->init
= uhci_reinit
;
163 controller
->shutdown
= uhci_shutdown
;
164 controller
->bulk
= uhci_bulk
;
165 controller
->control
= uhci_control
;
166 controller
->set_address
= generic_set_address
;
167 controller
->finish_device_config
= NULL
;
168 controller
->destroy_device
= NULL
;
169 controller
->create_intr_queue
= uhci_create_intr_queue
;
170 controller
->destroy_intr_queue
= uhci_destroy_intr_queue
;
171 controller
->poll_intr_queue
= uhci_poll_intr_queue
;
172 init_device_entry(controller
, 0);
173 UHCI_INST(controller
)->roothub
= controller
->devices
[0];
175 /* ~1 clears the register type indicator that is set to 1
177 controller
->reg_base
= pci_read_config32(addr
, 0x20) & ~1;
179 /* kill legacy support handler */
180 uhci_stop(controller
);
182 uhci_reg_write16(controller
, USBSTS
, 0x3f);
183 reg16
= pci_read_config16(addr
, 0xc0);
185 pci_write_config16(addr
, 0xc0, reg16
);
187 UHCI_INST(controller
)->framelistptr
= memalign(0x1000, 1024 * sizeof(flistp_t
)); /* 4kb aligned to 4kb */
188 if (!UHCI_INST (controller
)->framelistptr
)
189 fatal("Not enough memory for USB frame list pointer.\n");
191 memset(UHCI_INST(controller
)->framelistptr
, 0,
192 1024 * sizeof(flistp_t
));
194 /* According to the *BSD UHCI code, this one is needed on some
195 PIIX chips, because otherwise they misbehave. It must be
196 added to the last chain.
198 FIXME: this leaks, if the driver should ever be reinited
199 for some reason. Not a problem now.
201 td_t
*antiberserk
= memalign(16, sizeof(td_t
));
203 fatal("Not enough memory for chipset workaround.\n");
204 memset(antiberserk
, 0, sizeof(td_t
));
206 UHCI_INST(controller
)->qh_prei
= memalign(16, sizeof(qh_t
));
207 UHCI_INST(controller
)->qh_intr
= memalign(16, sizeof(qh_t
));
208 UHCI_INST(controller
)->qh_data
= memalign(16, sizeof(qh_t
));
209 UHCI_INST(controller
)->qh_last
= memalign(16, sizeof(qh_t
));
211 if (!UHCI_INST (controller
)->qh_prei
||
212 !UHCI_INST (controller
)->qh_intr
||
213 !UHCI_INST (controller
)->qh_data
||
214 !UHCI_INST (controller
)->qh_last
)
215 fatal("Not enough memory for USB controller queues.\n");
217 UHCI_INST(controller
)->qh_prei
->headlinkptr
=
218 virt_to_phys(UHCI_INST(controller
)->qh_intr
) | FLISTP_QH
;
219 UHCI_INST(controller
)->qh_prei
->elementlinkptr
= 0 | FLISTP_TERMINATE
;
221 UHCI_INST(controller
)->qh_intr
->headlinkptr
=
222 virt_to_phys(UHCI_INST(controller
)->qh_data
) | FLISTP_QH
;
223 UHCI_INST(controller
)->qh_intr
->elementlinkptr
= 0 | FLISTP_TERMINATE
;
225 UHCI_INST(controller
)->qh_data
->headlinkptr
=
226 virt_to_phys(UHCI_INST(controller
)->qh_last
) | FLISTP_QH
;
227 UHCI_INST(controller
)->qh_data
->elementlinkptr
= 0 | FLISTP_TERMINATE
;
229 UHCI_INST(controller
)->qh_last
->headlinkptr
= virt_to_phys(UHCI_INST(controller
)->qh_data
) | FLISTP_TERMINATE
;
230 UHCI_INST(controller
)->qh_last
->elementlinkptr
= virt_to_phys(antiberserk
) | FLISTP_TERMINATE
;
232 for (i
= 0; i
< 1024; i
++) {
233 UHCI_INST(controller
)->framelistptr
[i
] =
234 virt_to_phys(UHCI_INST(controller
)->qh_prei
) | FLISTP_QH
;
236 controller
->devices
[0]->controller
= controller
;
237 controller
->devices
[0]->init
= uhci_rh_init
;
238 controller
->devices
[0]->init(controller
->devices
[0]);
239 uhci_reset(controller
);
240 uhci_reinit(controller
);
245 uhci_shutdown(hci_t
*controller
)
249 detach_controller(controller
);
250 uhci_reg_write16(controller
, USBCMD
,
251 uhci_reg_read16(controller
, USBCMD
) & 0); // stop work
252 free(UHCI_INST(controller
)->framelistptr
);
253 free(UHCI_INST(controller
)->qh_prei
);
254 free(UHCI_INST(controller
)->qh_intr
);
255 free(UHCI_INST(controller
)->qh_data
);
256 free(UHCI_INST(controller
)->qh_last
);
257 free(UHCI_INST(controller
));
262 uhci_start(hci_t
*controller
)
264 uhci_reg_write16(controller
, USBCMD
,
265 uhci_reg_read16(controller
, USBCMD
) | 1); // start work on schedule
269 uhci_stop(hci_t
*controller
)
271 uhci_reg_write16(controller
, USBCMD
,
272 uhci_reg_read16(controller
, USBCMD
) & ~1); // stop work on schedule
275 #define UHCI_SLEEP_TIME_US 30
276 #define UHCI_TIMEOUT (USB_MAX_PROCESSING_TIME_US / UHCI_SLEEP_TIME_US)
277 #define GET_TD(x) ((void *)(((unsigned long)(x))&~0xf))
280 wait_for_completed_qh(hci_t
*controller
, qh_t
*qh
)
282 int timeout
= UHCI_TIMEOUT
;
283 void *current
= GET_TD(qh
->elementlinkptr
);
284 while (((qh
->elementlinkptr
& FLISTP_TERMINATE
) == 0) && (timeout
-- > 0)) {
285 if (current
!= GET_TD(qh
->elementlinkptr
)) {
286 current
= GET_TD(qh
->elementlinkptr
);
287 timeout
= UHCI_TIMEOUT
;
289 uhci_reg_write16(controller
, USBSTS
,
290 uhci_reg_read16(controller
, USBSTS
) | 0); // clear resettable registers
291 udelay(UHCI_SLEEP_TIME_US
);
293 return (GET_TD(qh
->elementlinkptr
) ==
294 0) ? 0 : GET_TD(phys_to_virt(qh
->elementlinkptr
));
300 return (size
- 1) & 0x7ff;
313 uhci_control(usbdev_t
*dev
, direction_t dir
, int drlen
, void *devreq
, const int dalen
,
316 int endp
= 0; /* this is control: always 0 */
317 int mlen
= dev
->endpoints
[0].maxpacketsize
;
318 int count
= (2 + (dalen
+ mlen
- 1) / mlen
);
319 unsigned short req
= ((unsigned short *) devreq
)[0];
321 td_t
*tds
= memalign(16, sizeof(td_t
) * count
);
323 fatal("Not enough memory for uhci control.\n");
324 memset(tds
, 0, sizeof(td_t
) * count
);
325 count
--; /* to compensate for 0-indexed array */
326 for (i
= 0; i
< count
; i
++) {
327 tds
[i
].ptr
= virt_to_phys(&tds
[i
+ 1]) | TD_DEPTH_FIRST
;
329 tds
[count
].ptr
= 0 | TD_DEPTH_FIRST
| TD_TERMINATE
;
331 tds
[0].token
= UHCI_SETUP
|
332 dev
->address
<< TD_DEVADDR_SHIFT
|
333 endp
<< TD_EP_SHIFT
|
335 maxlen(drlen
) << TD_MAXLEN_SHIFT
;
336 tds
[0].bufptr
= virt_to_phys(devreq
);
337 tds
[0].ctrlsts
= (3 << TD_COUNTER_SHIFT
) |
338 (dev
->speed
?TD_LOWSPEED
:0) |
342 int len_left
= dalen
;
343 for (i
= 1; i
< count
; i
++) {
345 case SETUP
: tds
[i
].token
= UHCI_SETUP
; break;
346 case IN
: tds
[i
].token
= UHCI_IN
; break;
347 case OUT
: tds
[i
].token
= UHCI_OUT
; break;
349 tds
[i
].token
|= dev
->address
<< TD_DEVADDR_SHIFT
|
350 endp
<< TD_EP_SHIFT
|
351 maxlen(min(mlen
, len_left
)) << TD_MAXLEN_SHIFT
|
352 toggle
<< TD_TOGGLE_SHIFT
;
353 tds
[i
].bufptr
= virt_to_phys(data
);
354 tds
[i
].ctrlsts
= (3 << TD_COUNTER_SHIFT
) |
355 (dev
->speed
?TD_LOWSPEED
:0) |
362 tds
[count
].token
= ((dir
== OUT
) ? UHCI_IN
: UHCI_OUT
) |
363 dev
->address
<< TD_DEVADDR_SHIFT
|
364 endp
<< TD_EP_SHIFT
|
365 maxlen(0) << TD_MAXLEN_SHIFT
|
367 tds
[count
].bufptr
= 0;
368 tds
[count
].ctrlsts
= (0 << TD_COUNTER_SHIFT
) | /* as Linux 2.4.10 does */
369 (dev
->speed
?TD_LOWSPEED
:0) |
371 UHCI_INST(dev
->controller
)->qh_data
->elementlinkptr
=
372 virt_to_phys(tds
) & ~(FLISTP_QH
| FLISTP_TERMINATE
);
373 td_t
*td
= wait_for_completed_qh(dev
->controller
,
374 UHCI_INST(dev
->controller
)->
378 result
= dalen
; /* TODO: We should return the actually transferred length. */
380 usb_debug("control packet, req %x\n", req
);
389 create_schedule(int numpackets
)
393 td_t
*tds
= memalign(16, sizeof(td_t
) * numpackets
);
395 fatal("Not enough memory for packets scheduling.\n");
396 memset(tds
, 0, sizeof(td_t
) * numpackets
);
398 for (i
= 0; i
< numpackets
; i
++) {
399 tds
[i
].ptr
= virt_to_phys(&tds
[i
+ 1]) | TD_DEPTH_FIRST
;
401 tds
[numpackets
- 1].ptr
= 0 | TD_TERMINATE
;
406 fill_schedule(td_t
*td
, endpoint_t
*ep
, int length
, unsigned char *data
,
409 switch (ep
->direction
) {
410 case IN
: td
->token
= UHCI_IN
; break;
411 case OUT
: td
->token
= UHCI_OUT
; break;
412 case SETUP
: td
->token
= UHCI_SETUP
; break;
414 td
->token
|= ep
->dev
->address
<< TD_DEVADDR_SHIFT
|
415 (ep
->endpoint
& 0xf) << TD_EP_SHIFT
|
416 maxlen(length
) << TD_MAXLEN_SHIFT
|
417 (*toggle
& 1) << TD_TOGGLE_SHIFT
;
418 td
->bufptr
= virt_to_phys(data
);
419 td
->ctrlsts
= ((ep
->direction
== SETUP
?3:0) << TD_COUNTER_SHIFT
) |
420 (ep
->dev
->speed
?TD_LOWSPEED
:0) |
426 run_schedule(usbdev_t
*dev
, td_t
*td
)
428 UHCI_INST(dev
->controller
)->qh_data
->elementlinkptr
=
429 virt_to_phys(td
) & ~(FLISTP_QH
| FLISTP_TERMINATE
);
430 td
= wait_for_completed_qh(dev
->controller
,
431 UHCI_INST(dev
->controller
)->qh_data
);
440 /* finalize == 1: if data is of packet aligned size, add a zero length packet */
442 uhci_bulk(endpoint_t
*ep
, const int dalen
, u8
*data
, int finalize
)
444 int maxpsize
= ep
->maxpacketsize
;
446 fatal("MaxPacketSize == 0!!!");
447 int numpackets
= (dalen
+ maxpsize
- 1) / maxpsize
;
448 if (finalize
&& ((dalen
% maxpsize
) == 0)) {
453 td_t
*tds
= create_schedule(numpackets
);
454 int i
= 0, toggle
= ep
->toggle
;
455 int len_left
= dalen
;
456 while ((len_left
> 0) || ((len_left
== 0) && (finalize
!= 0))) {
457 fill_schedule(&tds
[i
], ep
, min(len_left
, maxpsize
), data
,
461 len_left
-= maxpsize
;
463 if (run_schedule(ep
->dev
, tds
) == 1) {
469 return dalen
; /* TODO: We should return the actually transferred length. */
482 /* create and hook-up an intr queue into device schedule */
484 uhci_create_intr_queue(endpoint_t
*ep
, int reqsize
, int reqcount
, int reqtiming
)
486 u8
*data
= malloc(reqsize
*reqcount
);
487 td_t
*tds
= memalign(16, sizeof(td_t
) * reqcount
);
488 qh_t
*qh
= memalign(16, sizeof(qh_t
));
490 if (!data
|| !tds
|| !qh
)
491 fatal("Not enough memory to create USB intr queue prerequisites.\n");
493 qh
->elementlinkptr
= virt_to_phys(tds
);
495 intr_q
*q
= malloc(sizeof(intr_q
));
497 fatal("Not enough memory to create USB intr queue.\n");
503 q
->reqsize
= reqsize
;
504 q
->last_td
= &tds
[reqcount
- 1];
506 memset(tds
, 0, sizeof(td_t
) * reqcount
);
508 for (i
= 0; i
< reqcount
; i
++) {
509 tds
[i
].ptr
= virt_to_phys(&tds
[i
+ 1]);
511 switch (ep
->direction
) {
512 case IN
: tds
[i
].token
= UHCI_IN
; break;
513 case OUT
: tds
[i
].token
= UHCI_OUT
; break;
514 case SETUP
: tds
[i
].token
= UHCI_SETUP
; break;
516 tds
[i
].token
|= ep
->dev
->address
<< TD_DEVADDR_SHIFT
|
517 (ep
->endpoint
& 0xf) << TD_EP_SHIFT
|
518 maxlen(reqsize
) << TD_MAXLEN_SHIFT
|
519 (ep
->toggle
& 1) << TD_TOGGLE_SHIFT
;
520 tds
[i
].bufptr
= virt_to_phys(data
);
521 tds
[i
].ctrlsts
= (0 << TD_COUNTER_SHIFT
) |
522 (ep
->dev
->speed
?TD_LOWSPEED
:0) |
527 tds
[reqcount
- 1].ptr
= 0 | TD_TERMINATE
;
529 /* insert QH into framelist */
530 uhci_t
*const uhcic
= UHCI_INST(ep
->dev
->controller
);
531 const u32 def_ptr
= virt_to_phys(uhcic
->qh_prei
) | FLISTP_QH
;
532 int nothing_placed
= 1;
533 qh
->headlinkptr
= def_ptr
;
534 for (i
= 0; i
< 1024; i
+= reqtiming
) {
535 /* advance to the next free position */
536 while ((i
< 1024) && (uhcic
->framelistptr
[i
] != def_ptr
)) ++i
;
538 uhcic
->framelistptr
[i
] = virt_to_phys(qh
) | FLISTP_QH
;
542 if (nothing_placed
) {
543 usb_debug("Error: Failed to place UHCI interrupt queue "
544 "head into framelist: no space left\n");
545 uhci_destroy_intr_queue(ep
, q
);
552 /* remove queue from device schedule, dropping all data that came in */
554 uhci_destroy_intr_queue(endpoint_t
*ep
, void *q_
)
556 intr_q
*const q
= (intr_q
*)q_
;
558 /* remove QH from framelist */
559 uhci_t
*const uhcic
= UHCI_INST(ep
->dev
->controller
);
560 const u32 qh_ptr
= virt_to_phys(q
->qh
) | FLISTP_QH
;
561 const u32 def_ptr
= virt_to_phys(uhcic
->qh_prei
) | FLISTP_QH
;
563 for (i
= 0; i
< 1024; ++i
) {
564 if (uhcic
->framelistptr
[i
] == qh_ptr
)
565 uhcic
->framelistptr
[i
] = def_ptr
;
574 /* read one intr-packet from queue, if available. extend the queue for new input.
575 return NULL if nothing new available.
576 Recommended use: while (data=poll_intr_queue(q)) process(data);
579 uhci_poll_intr_queue(void *q_
)
581 intr_q
*q
= (intr_q
*)q_
;
582 if ((q
->tds
[q
->lastread
].ctrlsts
& TD_STATUS_ACTIVE
) == 0) {
583 int current
= q
->lastread
;
585 if (q
->lastread
== 0) {
586 previous
= q
->total
- 1;
588 previous
= q
->lastread
- 1;
590 q
->tds
[previous
].ctrlsts
&= ~TD_STATUS_MASK
;
591 q
->tds
[previous
].ptr
= 0 | TD_TERMINATE
;
592 if (q
->last_td
!= &q
->tds
[previous
]) {
593 q
->last_td
->ptr
= virt_to_phys(&q
->tds
[previous
]) & ~TD_TERMINATE
;
594 q
->last_td
= &q
->tds
[previous
];
596 q
->tds
[previous
].ctrlsts
|= TD_STATUS_ACTIVE
;
597 q
->lastread
= (q
->lastread
+ 1) % q
->total
;
598 if (!(q
->tds
[current
].ctrlsts
& TD_STATUS_MASK
))
599 return &q
->data
[current
*q
->reqsize
];
601 /* reset queue if we fully processed it after underrun */
602 else if (q
->qh
->elementlinkptr
& FLISTP_TERMINATE
) {
603 usb_debug("resetting underrun uhci interrupt queue.\n");
604 q
->qh
->elementlinkptr
= virt_to_phys(q
->tds
+ q
->lastread
);
610 uhci_reg_write32(hci_t
*ctrl
, usbreg reg
, u32 value
)
612 outl(value
, ctrl
->reg_base
+ reg
);
616 uhci_reg_read32(hci_t
*ctrl
, usbreg reg
)
618 return inl(ctrl
->reg_base
+ reg
);
622 uhci_reg_write16(hci_t
*ctrl
, usbreg reg
, u16 value
)
624 outw(value
, ctrl
->reg_base
+ reg
);
628 uhci_reg_read16(hci_t
*ctrl
, usbreg reg
)
630 return inw(ctrl
->reg_base
+ reg
);
634 uhci_reg_write8(hci_t
*ctrl
, usbreg reg
, u8 value
)
636 outb(value
, ctrl
->reg_base
+ reg
);
640 uhci_reg_read8(hci_t
*ctrl
, usbreg reg
)
642 return inb(ctrl
->reg_base
+ reg
);