[USBDRIVER]
[reactos.git] / reactos / drivers / usb / nt4compat / usbdriver / uhci.c
1 /**
2 * uhci.c - USB driver stack project for Windows NT 4.0
3 *
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
5 *
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program (in the main directory of the distribution, the file
18 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "usbdriver.h"
23
24 //----------------------------------------------------------
25 // uhci routines
26 //#define DEMO
27
28 #ifdef INCLUDE_EHCI
29
30 #define rh_port1_status rh_port_status[ 1 ]
31 #define rh_port2_status rh_port_status[ 2 ]
32
33 extern PDEVICE_OBJECT ehci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr);
34
35 #endif
36
37 #define DEFAULT_ENDP( enDP ) \
38 ( enDP->flags & USB_ENDP_FLAG_DEFAULT_ENDP )
39
40 #define dev_from_endp( enDP ) \
41 ( DEFAULT_ENDP( enDP )\
42 ? ( ( PUSB_DEV )( enDP )->pusb_if )\
43 : ( ( enDP )->pusb_if->pusb_config->pusb_dev ) )
44
45 #define endp_state( enDP ) ( ( enDP )->flags & USB_ENDP_FLAG_STAT_MASK )
46
47 #define endp_num( enDP ) \
48 ( DEFAULT_ENDP( enDP )\
49 ? 0 \
50 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & 0x0f ) )
51
52 #define endp_dir( enDP ) \
53 ( DEFAULT_ENDP( enDP )\
54 ? 0L\
55 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & USB_DIR_IN ) )
56
57 #define dev_set_state( pdEV, staTE ) \
58 ( pdEV->flags = ( ( pdEV )->flags & ( ~USB_DEV_STATE_MASK ) ) | ( staTE ) )
59
60 #define endp_max_packet_size( enDP ) \
61 ( DEFAULT_ENDP( enDP )\
62 ? ( ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc ? \
63 ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc->bMaxPacketSize0\
64 : 8 )\
65 : enDP->pusb_endp_desc->wMaxPacketSize )
66
67
68 #if 0
69 /* WTF?! */
70 #define release_adapter( padapTER ) \
71 {\
72 ( ( padapTER ) ); \
73 }
74 #else
75 #define release_adapter( padapTER ) (void)(padapTER)
76 #endif
77
78 #define get_int_idx( _urb, _idx ) \
79 {\
80 UCHAR interVAL;\
81 interVAL = ( UCHAR )( ( _urb )->pipe >> 24 );\
82 for( _idx = 1; _idx < 9; _idx++ )\
83 {\
84 interVAL >>= 1;\
85 if( !interVAL )\
86 break;\
87 }\
88 _idx --;\
89 }
90
91 #define uhci_insert_urb_to_schedule( uHCI, pURB, rET ) \
92 {\
93 SYNC_PARAM sync_param;\
94 sync_param.uhci = uHCI;\
95 sync_param.context = pURB;\
96 \
97 rET = KeSynchronizeExecution( uHCI->pdev_ext->uhci_int, uhci_sync_insert_urb_schedule, &sync_param );\
98 }
99
100 //declarations
101 typedef struct
102 {
103 PUHCI_DEV uhci;
104 PVOID context;
105 ULONG ret;
106 } SYNC_PARAM, *PSYNC_PARAM;
107
108 PDEVICE_OBJECT
109 uhci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr);
110
111 BOOLEAN uhci_init_schedule(PUHCI_DEV uhci, PADAPTER_OBJECT padapter);
112
113 BOOLEAN uhci_release(PDEVICE_OBJECT pdev);
114
115 static VOID uhci_stop(PUHCI_DEV uhci);
116
117 BOOLEAN uhci_destroy_schedule(PUHCI_DEV uhci);
118
119 BOOLEAN NTAPI uhci_sync_insert_urb_schedule(PVOID context);
120
121 VOID uhci_init_hcd_interface(PUHCI_DEV uhci);
122
123 NTSTATUS uhci_rh_submit_urb(PUSB_DEV rh, PURB purb);
124
125 NTSTATUS uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
126
127 extern VOID rh_timer_svc_reset_port_completion(PUSB_DEV dev, PVOID context);
128
129 extern VOID rh_timer_svc_int_completion(PUSB_DEV dev, PVOID context);
130
131 ULONG debug_level = DBGLVL_MINIMUM;//DBGLVL_MAXIMUM;
132 PDRIVER_OBJECT usb_driver_obj = NULL;
133 extern USB_DEV_MANAGER g_dev_mgr;
134
135 //pending endpoint pool funcs
136 VOID
137 uhci_wait_ms(PUHCI_DEV uhci, LONG ms)
138 {
139 LARGE_INTEGER lms;
140 if (ms <= 0)
141 return;
142
143 lms.QuadPart = -10 * ms;
144 KeSetTimer(&uhci->reset_timer, lms, NULL);
145
146 KeWaitForSingleObject(&uhci->reset_timer, Executive, KernelMode, FALSE, NULL);
147
148 return;
149 }
150
151 BOOLEAN
152 init_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
153 {
154 int i;
155 if (pool == NULL)
156 return FALSE;
157
158 pool->pending_endp_array =
159 usb_alloc_mem(NonPagedPool, sizeof(UHCI_PENDING_ENDP) * UHCI_MAX_PENDING_ENDPS);
160 InitializeListHead(&pool->free_que);
161 pool->free_count = 0;
162 pool->total_count = UHCI_MAX_PENDING_ENDPS;
163 KeInitializeSpinLock(&pool->pool_lock);
164
165 for(i = 0; i < MAX_TIMER_SVCS; i++)
166 {
167 free_pending_endp(pool, &pool->pending_endp_array[i]);
168 }
169
170 return TRUE;
171
172 }
173
174 BOOLEAN
175 free_pending_endp(PUHCI_PENDING_ENDP_POOL pool, PUHCI_PENDING_ENDP pending_endp)
176 {
177 if (pool == NULL || pending_endp == NULL)
178 {
179 return FALSE;
180 }
181
182 RtlZeroMemory(pending_endp, sizeof(UHCI_PENDING_ENDP));
183 InsertTailList(&pool->free_que, &pending_endp->endp_link);
184 pool->free_count++;
185
186 return TRUE;
187 }
188
189 PUHCI_PENDING_ENDP
190 alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool, LONG count)
191 {
192 PUHCI_PENDING_ENDP new_endp;
193 if (pool == NULL || count != 1)
194 return NULL;
195
196 if (pool->free_count <= 0)
197 return NULL;
198
199 new_endp = (PUHCI_PENDING_ENDP) RemoveHeadList(&pool->free_que);
200 pool->free_count--;
201 return new_endp;
202 }
203
204 BOOLEAN
205 destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
206 {
207 if (pool == NULL)
208 return FALSE;
209
210 InitializeListHead(&pool->free_que);
211 pool->free_count = pool->total_count = 0;
212 usb_free_mem(pool->pending_endp_array);
213 pool->pending_endp_array = NULL;
214
215 return TRUE;
216
217 }
218
219
220 //end of pending endpoint pool funcs
221
222 static void
223 uhci_fill_td(PUHCI_TD td, ULONG status, ULONG info, ULONG buffer)
224 {
225 td->status = status;
226 td->info = info;
227 td->buffer = buffer;
228 }
229
230 BOOLEAN
231 uhci_insert_td_fl(PUHCI_TD prev_td, PUHCI_TD ptd)
232 {
233 PLIST_ENTRY temp_entry;
234
235 if (prev_td == NULL || ptd == NULL)
236 return FALSE;
237
238 temp_entry = &prev_td->ptde->hori_link;
239
240 ptd->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
241 prev_td->link = ptd->phy_addr;
242
243 InsertHeadList(&prev_td->ptde->hori_link, &ptd->ptde->hori_link);
244 return TRUE;
245 }
246
247 BOOLEAN
248 uhci_remove_td_fl(PUHCI_TD ptd)
249 {
250 PUHCI_TD prev_td;
251
252 if (ptd == NULL)
253 return FALSE;
254
255 prev_td = (struct_ptr(ptd->ptde->hori_link.Blink, TD_EXTENSION, hori_link))->ptd;
256 prev_td->link = ptd->link;
257 ptd->link = UHCI_PTR_TERM;
258
259 RemoveEntryList(&ptd->ptde->hori_link);
260
261 return FALSE;
262 }
263
264 BOOLEAN
265 uhci_insert_qh_fl(PVOID prev_item, PUHCI_QH pqh)
266 {
267 //only horizontal link allowed
268 PUHCI_QH pprev_qh;
269 PUHCI_TD pprev_td;
270 PLIST_ENTRY temp_entry;
271
272 if (prev_item == NULL || pqh == NULL)
273 return FALSE;
274
275 if ((((PUHCI_TD) prev_item)->ptde->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
276 {
277 pprev_qh = (PUHCI_QH) prev_item;
278 temp_entry = pprev_qh->pqhe->hori_link.Flink;
279 pqh->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
280 pprev_qh->link = pqh->phy_addr;
281
282 InsertHeadList(&pprev_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
283 }
284 else
285 {
286 pprev_td = ((PUHCI_TD) prev_item);
287
288 temp_entry = pprev_td->ptde->hori_link.Flink;
289 pprev_td->link = pqh->phy_addr;
290 pqh->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
291
292 InsertHeadList(&pprev_td->ptde->hori_link, &pqh->pqhe->hori_link);
293 }
294
295 return FALSE;
296 }
297
298 BOOLEAN
299 uhci_remove_qh_fl(PUHCI_QH pqh)
300 {
301 PVOID prev_item;
302 PUHCI_QH pprevqh;
303 PUHCI_TD pprevtd;
304
305 if (pqh == NULL)
306 return FALSE;
307
308 prev_item = (struct_ptr(pqh->pqhe->hori_link.Blink, TD_EXTENSION, hori_link))->ptd;
309
310 if ((((PUHCI_TD) prev_item)->ptde->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
311 {
312 pprevqh = (PUHCI_QH) prev_item;
313 pprevqh->link = pqh->link;
314 }
315 else
316 {
317 pprevtd = ((PUHCI_TD) prev_item);
318 pprevtd->link = pqh->link;
319 }
320
321 RemoveEntryList(&pqh->pqhe->hori_link);
322
323 pqh->link = UHCI_PTR_TERM;
324 pqh->pqhe->hori_link.Flink = pqh->pqhe->hori_link.Blink = NULL;
325
326 return TRUE;
327 }
328
329 BOOLEAN
330 uhci_init_frame_list(PUHCI_DEV uhci, PADAPTER_OBJECT padapter)
331 {
332 int i;
333 if (uhci == NULL || padapter == NULL)
334 return FALSE;
335
336 //note: frame_list_lock will be connected to interrupt
337 KeInitializeSpinLock(&uhci->frame_list_lock);
338
339 uhci->io_buf = HalAllocateCommonBuffer(padapter, 4096, &uhci->io_buf_logic_addr, FALSE);
340
341 if (uhci->io_buf == NULL)
342 return FALSE;
343
344 uhci->frame_list =
345 HalAllocateCommonBuffer(padapter,
346 sizeof(ULONG) * UHCI_MAX_FRAMES, &uhci->frame_list_logic_addr, FALSE);
347
348 if (uhci->frame_list == NULL)
349 return FALSE;
350
351 RtlZeroMemory(uhci->frame_list, sizeof(ULONG) * UHCI_MAX_FRAMES);
352
353 uhci->frame_list_cpu = usb_alloc_mem(NonPagedPool, sizeof(FRAME_LIST_CPU_ENTRY) * UHCI_MAX_FRAMES);
354
355 if (uhci->frame_list_cpu == NULL)
356 return FALSE;
357
358 for(i = 0; i < UHCI_MAX_FRAMES; i++)
359 InitializeListHead(&uhci->frame_list_cpu[i].td_link);
360
361 uhci->frame_bw = usb_alloc_mem(NonPagedPool, sizeof(LONG) * UHCI_MAX_FRAMES);
362
363 if (uhci->frame_bw == NULL)
364 return FALSE;
365
366 for(i = 0; i < UHCI_MAX_FRAMES; i++)
367 {
368 uhci->frame_bw[i] = FRAME_TIME_MAX_USECS_ALLOC;
369 }
370 uhci->fsbr_cnt = 0;
371
372 return TRUE;
373
374 }
375
376 BOOLEAN
377 uhci_destroy_frame_list(PUHCI_DEV uhci)
378 {
379 if (uhci == NULL)
380 return FALSE;
381
382 if (uhci->frame_list)
383 HalFreeCommonBuffer(uhci->pdev_ext->padapter,
384 sizeof(ULONG) * UHCI_MAX_FRAMES,
385 uhci->frame_list_logic_addr, uhci->frame_list, FALSE);
386
387 uhci->frame_list = NULL;
388 uhci->frame_list_logic_addr.LowPart = 0;
389 uhci->frame_list_logic_addr.HighPart = 0;
390
391 if (uhci->frame_list_cpu)
392 usb_free_mem(uhci->frame_list_cpu);
393
394 uhci->frame_list_cpu = NULL;
395
396 if (uhci->frame_bw)
397 usb_free_mem(uhci->frame_bw);
398
399 uhci->frame_bw = NULL;
400
401 return TRUE;
402 }
403
404 PDEVICE_OBJECT
405 uhci_create_device(PDRIVER_OBJECT drvr_obj, PUSB_DEV_MANAGER dev_mgr)
406 {
407 NTSTATUS status;
408 PDEVICE_OBJECT pdev;
409 PDEVICE_EXTENSION pdev_ext;
410
411 UNICODE_STRING dev_name;
412 UNICODE_STRING symb_name;
413
414 STRING string, another_string;
415 CHAR str_dev_name[64], str_symb_name[64];
416 UCHAR hcd_id;
417
418 if (drvr_obj == NULL)
419 return NULL;
420
421 ASSERT(dev_mgr != NULL);
422
423 //note: hcd count wont increment till the hcd is registered in dev_mgr
424 sprintf(str_dev_name, "%s%d", UHCI_DEVICE_NAME, dev_mgr->hcd_count);
425 sprintf(str_symb_name, "%s%d", DOS_DEVICE_NAME, dev_mgr->hcd_count);
426
427 RtlInitString(&string, str_dev_name);
428 RtlAnsiStringToUnicodeString(&dev_name, &string, TRUE);
429
430 pdev = NULL;
431 status = IoCreateDevice(drvr_obj,
432 sizeof(DEVICE_EXTENSION) + sizeof(UHCI_DEV),
433 &dev_name, FILE_UHCI_DEV_TYPE, 0, FALSE, &pdev);
434
435 if (status != STATUS_SUCCESS || pdev == NULL)
436 {
437 RtlFreeUnicodeString(&dev_name);
438 return NULL;
439 }
440
441 pdev_ext = pdev->DeviceExtension;
442 RtlZeroMemory(pdev_ext, sizeof(DEVICE_EXTENSION) + sizeof(UHCI_DEV));
443
444 pdev_ext->dev_ext_hdr.type = NTDEV_TYPE_HCD;
445 pdev_ext->dev_ext_hdr.dispatch = uhci_dispatch_irp;
446 pdev_ext->dev_ext_hdr.start_io = NULL; //we do not support startio
447 pdev_ext->dev_ext_hdr.dev_mgr = dev_mgr;
448
449 pdev_ext->pdev_obj = pdev;
450 pdev_ext->pdrvr_obj = drvr_obj;
451
452 pdev_ext->uhci = (PUHCI_DEV) & (pdev_ext[1]);
453
454 RtlInitString(&another_string, str_symb_name);
455 RtlAnsiStringToUnicodeString(&symb_name, &another_string, TRUE);
456
457 IoCreateSymbolicLink(&symb_name, &dev_name);
458
459 uhci_dbg_print(DBGLVL_MAXIMUM,
460 ("uhci_create_device(): dev=0x%x\n, pdev_ext= 0x%x, uhci=0x%x, dev_mgr=0x%x\n", pdev,
461 pdev_ext, pdev_ext->uhci, dev_mgr));
462
463 RtlFreeUnicodeString(&dev_name);
464 RtlFreeUnicodeString(&symb_name);
465
466 //register with dev_mgr though it is not initilized
467 uhci_init_hcd_interface(pdev_ext->uhci);
468 hcd_id = dev_mgr_register_hcd(dev_mgr, &pdev_ext->uhci->hcd_interf);
469
470 pdev_ext->uhci->hcd_interf.hcd_set_id(&pdev_ext->uhci->hcd_interf, hcd_id);
471 pdev_ext->uhci->hcd_interf.hcd_set_dev_mgr(&pdev_ext->uhci->hcd_interf, dev_mgr);
472 return pdev;
473 }
474
475 BOOLEAN
476 uhci_delete_device(PDEVICE_OBJECT pdev)
477 {
478 STRING string;
479 UNICODE_STRING symb_name;
480 PDEVICE_EXTENSION pdev_ext;
481 CHAR str_symb_name[64];
482
483
484 if (pdev == NULL)
485 return FALSE;
486
487 pdev_ext = pdev->DeviceExtension;
488
489 sprintf(str_symb_name,
490 "%s%d", DOS_DEVICE_NAME, pdev_ext->uhci->hcd_interf.hcd_get_id(&pdev_ext->uhci->hcd_interf));
491 RtlInitString(&string, str_symb_name);
492 RtlAnsiStringToUnicodeString(&symb_name, &string, TRUE);
493 IoDeleteSymbolicLink(&symb_name);
494 RtlFreeUnicodeString(&symb_name);
495
496 if (pdev_ext->res_list)
497 ExFreePool(pdev_ext->res_list); // not allocated by usb_alloc_mem
498
499 IoDeleteDevice(pdev);
500 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_delete_device(): device deleted\n"));
501 return TRUE;
502 }
503
504 // we can not use endp here for it is within the dev scope, and
505 // we can not acquire the dev-lock, fortunately we saved some
506 // info in urb->pipe in uhci_internal_submit_XXX.
507 BOOLEAN NTAPI
508 uhci_isr(PKINTERRUPT interrupt, PVOID context)
509 {
510 PUHCI_DEV uhci;
511 USHORT status;
512 PLIST_ENTRY pthis, pnext;
513 PURB purb;
514
515 UNREFERENCED_PARAMETER(interrupt);
516 UNREFERENCED_PARAMETER(context);
517
518 uhci_dbg_print(DBGLVL_ULTRA, ("uhci_isr(): context=0x%x\n", context));
519
520 /*
521 * Read the interrupt status, and write it back to clear the
522 * interrupt cause
523 */
524 uhci = (PUHCI_DEV) context;
525 if (uhci == NULL)
526 return FALSE;
527
528 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS));
529 if (!status) /* shared interrupt, not mine */
530 return FALSE;
531
532 if (status != 1)
533 {
534 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr(): current uhci status=0x%x\n", status));
535 }
536 else
537 {
538 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr(): congratulations, no error occurs\n"));
539 }
540
541 /* clear it */
542 WRITE_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS), status);
543
544 if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD))
545 {
546 if (status & USBSTS_HSE)
547 {
548 DbgPrint("uhci_isr(): host system error, PCI problems?\n");
549 //for( ; ; );
550 }
551 if (status & USBSTS_HCPE)
552 {
553 DbgPrint("uhci_isr(): host controller process error. something bad happened\n");
554 //for( ; ; );
555 //for( ; ; );
556 }
557 if ((status & USBSTS_HCH)) //&& !uhci->is_suspended
558 {
559 DbgPrint("uhci_isr(): host controller halted. very bad\n");
560 /* FIXME: Reset the controller, fix the offending TD */
561 }
562 }
563
564 // don't no how to handle it yet
565 //if (status & USBSTS_RD)
566 //{
567 //uhci_wakeup(uhci);
568 //}*/
569
570 //let's remove those force-cancel urbs from the schedule first
571 ListFirst(&uhci->urb_list, pthis);
572 while (pthis)
573 {
574 purb = (PURB) pthis;
575 if (purb->flags & URB_FLAG_FORCE_CANCEL)
576 {
577 uhci_remove_urb_from_schedule(uhci, purb);
578 }
579 ListNext(&uhci->urb_list, pthis, pnext);
580 pthis = pnext;
581 }
582
583 //clear the interrupt if the urb is force canceled
584 uhci->skel_term_td->status &= ~TD_CTRL_IOC;
585
586 //next we need to find if anything fininshed
587 ListFirst(&uhci->urb_list, pthis);
588 while (pthis)
589 {
590 purb = (PURB) pthis;
591 if (purb->flags & URB_FLAG_IN_SCHEDULE)
592 {
593 if (uhci_is_xfer_finished(purb))
594 uhci_remove_urb_from_schedule(uhci, purb);
595 }
596 ListNext(&uhci->urb_list, pthis, pnext);
597 pthis = pnext;
598 }
599
600 KeInsertQueueDpc(&uhci->pdev_ext->uhci_dpc, uhci, 0);
601 return TRUE;
602 }
603
604 BOOLEAN NTAPI
605 uhci_cal_cpu_freq(PVOID context)
606 {
607 UNREFERENCED_PARAMETER(context);
608
609 usb_cal_cpu_freq();
610 return TRUE;
611 }
612
613 PDEVICE_OBJECT
614 uhci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr)
615 {
616 LONG bus, i, j, ret = 0;
617 PCI_SLOT_NUMBER slot_num;
618 PPCI_COMMON_CONFIG pci_config;
619 PDEVICE_OBJECT pdev;
620 BYTE buffer[sizeof(PCI_COMMON_CONFIG)];
621 LONG count;
622 PDEVICE_EXTENSION pdev_ext;
623
624 slot_num.u.AsULONG = 0;
625 pci_config = (PPCI_COMMON_CONFIG) buffer;
626 count = 0;
627 pdev = NULL;
628
629 //scan the PCI buses to find uhci controller
630 for (bus = 0; bus <= PCI_MAX_BRIDGE_NUMBER; bus++)
631 {
632 for(i = 0; i <= PCI_MAX_DEVICES; i++)
633 {
634 slot_num.u.bits.DeviceNumber = i;
635 for(j = 0; j <= PCI_MAX_FUNCTION; j++)
636 {
637 slot_num.u.bits.FunctionNumber = j;
638
639 ret = HalGetBusData(PCIConfiguration,
640 bus, slot_num.u.AsULONG, pci_config, PCI_COMMON_HDR_LENGTH);
641
642 if (ret == 0) /*no this bus */
643 break;
644
645 if (ret == 2) /*no device on the slot */
646 break;
647
648 if (pci_config->BaseClass == 0x0c && pci_config->SubClass == 0x03 &&
649 pci_config->ProgIf == 0x00)
650 {
651 // well, we find our usb host controller, create device
652 pdev = uhci_alloc(drvr_obj, reg_path, ((bus << 8) | (i << 3) | j), dev_mgr);
653 if (pdev)
654 #ifdef _MULTI_UHCI
655 count++;
656 #else
657 goto LBL_LOOPOUT;
658 #endif
659 }
660 }
661 if (ret == 0)
662 break;
663 }
664 }
665
666 #ifndef _MULTI_UHCI
667 LBL_LOOPOUT:
668 #endif
669 DbgPrint("Found %d UHCI controllers\n", count);
670
671 if (pdev)
672 {
673 pdev_ext = pdev->DeviceExtension;
674 if (pdev_ext)
675 {
676 // acquire higher irql to eliminate pre-empty
677 KeSynchronizeExecution(pdev_ext->uhci_int, uhci_cal_cpu_freq, NULL);
678 }
679 }
680 return pdev;
681 }
682
683 PDEVICE_OBJECT
684 uhci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr)
685 {
686 LONG frd_num, prd_num;
687 PDEVICE_OBJECT pdev;
688 PDEVICE_EXTENSION pdev_ext;
689 ULONG vector, addr_space;
690 LONG bus;
691 KIRQL irql;
692 KAFFINITY affinity;
693
694 DEVICE_DESCRIPTION dev_desc;
695 CM_PARTIAL_RESOURCE_DESCRIPTOR *pprd;
696 PCI_SLOT_NUMBER slot_num;
697 NTSTATUS status;
698
699
700 pdev = uhci_create_device(drvr_obj, dev_mgr);
701 if (pdev == NULL)
702 return pdev;
703 pdev_ext = pdev->DeviceExtension;
704
705 pdev_ext->pci_addr = bus_addr;
706 bus = (bus_addr >> 8);
707
708 slot_num.u.AsULONG = 0;
709 slot_num.u.bits.DeviceNumber = ((bus_addr & 0xff) >> 3);
710 slot_num.u.bits.FunctionNumber = (bus_addr & 0x07);
711
712 //now create adapter object
713 RtlZeroMemory(&dev_desc, sizeof(dev_desc));
714
715 dev_desc.Version = DEVICE_DESCRIPTION_VERSION;
716 dev_desc.Master = TRUE;
717 dev_desc.ScatterGather = TRUE;
718 dev_desc.Dma32BitAddresses = TRUE;
719 dev_desc.BusNumber = bus;
720 dev_desc.InterfaceType = PCIBus;
721 dev_desc.MaximumLength =
722 UHCI_MAX_POOL_TDS * sizeof(UHCI_TD) * UHCI_MAX_TD_POOLS
723 + sizeof(UHCI_QH) * UHCI_MAX_POOL_QHS + sizeof(ULONG) * UHCI_MAX_FRAMES;
724
725 pdev_ext->map_regs = 2; // UHCI_MAX_TD_POOLS +
726 //+ BYTES_TO_PAGES( ( UHCI_MAX_POOL_TDS * 64 ) * UHCI_MAX_TD_POOLS ) ;
727
728 pdev_ext->padapter = HalGetAdapter(&dev_desc, &pdev_ext->map_regs);
729
730 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_alloc(): padapter=0x%x\n", pdev_ext->padapter));
731 if (pdev_ext->padapter == NULL)
732 {
733 //fatal error
734 uhci_delete_device(pdev);
735 return NULL;
736 }
737
738 DbgPrint("uhci_alloc(): reg_path=%p, \n \
739 uhci_alloc(): PCIBus=0x%x, bus=0x%x, bus_addr=0x%x \n \
740 uhci_alloc(): slot_num=0x%x, &res_list=%p \n", reg_path, (DWORD) PCIBus, (DWORD) bus,
741 (DWORD) bus_addr, (DWORD) slot_num.u.AsULONG, & pdev_ext->res_list);
742
743 //let's allocate resources for this device
744 DbgPrint("uhci_alloc(): about to assign slot res\n");
745 if ((status = HalAssignSlotResources(reg_path, NULL, //no class name yet
746 drvr_obj, NULL, //no support of another uhci controller
747 PCIBus,
748 bus, slot_num.u.AsULONG, &pdev_ext->res_list)) != STATUS_SUCCESS)
749 {
750 DbgPrint("uhci_alloc(): error assign slot res, 0x%x\n", status);
751 release_adapter(pdev_ext->padapter);
752 pdev_ext->padapter = NULL;
753 uhci_delete_device(pdev);
754 return NULL;
755 }
756
757 //parse the resource list
758 for(frd_num = 0; frd_num < (LONG) pdev_ext->res_list->Count; frd_num++)
759 {
760 for(prd_num = 0; prd_num < (LONG) pdev_ext->res_list->List[frd_num].PartialResourceList.Count;
761 prd_num++)
762 {
763 pprd = &pdev_ext->res_list->List[frd_num].PartialResourceList.PartialDescriptors[prd_num];
764 if (pprd->Type == CmResourceTypePort)
765 {
766 RtlCopyMemory(&pdev_ext->res_port, &pprd->u.Port, sizeof(pprd->u.Port));
767 }
768 else if (pprd->Type == CmResourceTypeInterrupt)
769 {
770 RtlCopyMemory(&pdev_ext->res_interrupt, &pprd->u.Interrupt, sizeof(pprd->u.Interrupt));
771 }
772 }
773 }
774
775 //for port, translate them to system address
776 addr_space = 1;
777 if (HalTranslateBusAddress(PCIBus, bus, pdev_ext->res_port.Start, &addr_space, //io space
778 &pdev_ext->uhci->uhci_reg_base) != (BOOLEAN) TRUE)
779 {
780 DbgPrint("uhci_alloc(): error, can not translate bus address\n");
781 release_adapter(pdev_ext->padapter);
782 pdev_ext->padapter = NULL;
783 uhci_delete_device(pdev);
784 return NULL;
785 }
786
787 DbgPrint("uhci_alloc(): address space=0x%x\n, reg_base=0x%x\n",
788 addr_space, pdev_ext->uhci->uhci_reg_base.u.LowPart);
789
790 if (addr_space == 0)
791 {
792 //port has been mapped to memory space
793 pdev_ext->uhci->port_mapped = TRUE;
794 pdev_ext->uhci->port_base = (PBYTE) MmMapIoSpace(pdev_ext->uhci->uhci_reg_base,
795 pdev_ext->res_port.Length, FALSE);
796
797 //fatal error can not map the registers
798 if (pdev_ext->uhci->port_base == NULL)
799 {
800 release_adapter(pdev_ext->padapter);
801 pdev_ext->padapter = NULL;
802 uhci_delete_device(pdev);
803 return NULL;
804 }
805 }
806 else
807 {
808 //io space
809 pdev_ext->uhci->port_mapped = FALSE;
810 pdev_ext->uhci->port_base = (PBYTE) pdev_ext->uhci->uhci_reg_base.LowPart;
811 }
812
813 //before we connect the interrupt, we have to init uhci
814 pdev_ext->uhci->fsbr_cnt = 0;
815 pdev_ext->uhci->pdev_ext = pdev_ext;
816
817 if (uhci_init_schedule(pdev_ext->uhci, pdev_ext->padapter) == FALSE)
818 {
819 release_adapter(pdev_ext->padapter);
820 pdev_ext->padapter = NULL;
821 uhci_delete_device(pdev);
822 return NULL;
823 }
824
825 InitializeListHead(&pdev_ext->uhci->urb_list);
826 KeInitializeSpinLock(&pdev_ext->uhci->pending_endp_list_lock);
827 InitializeListHead(&pdev_ext->uhci->pending_endp_list);
828
829 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_alloc(): pending_endp_list=0x%x\n",
830 &pdev_ext->uhci->pending_endp_list));
831
832 init_pending_endp_pool(&pdev_ext->uhci->pending_endp_pool);
833 KeInitializeTimer(&pdev_ext->uhci->reset_timer);
834
835 vector = HalGetInterruptVector(PCIBus,
836 bus,
837 pdev_ext->res_interrupt.level,
838 pdev_ext->res_interrupt.vector,
839 &irql,
840 &affinity);
841
842 KeInitializeDpc(&pdev_ext->uhci_dpc, uhci_dpc_callback, (PVOID) pdev_ext->uhci);
843
844 //connect the interrupt
845 DbgPrint("uhci_alloc(): the int=0x%x\n", vector);
846 if (IoConnectInterrupt(&pdev_ext->uhci_int,
847 uhci_isr,
848 pdev_ext->uhci,
849 NULL, //&pdev_ext->uhci->frame_list_lock,
850 vector,
851 irql,
852 irql,
853 LevelSensitive,
854 TRUE, //share the vector
855 affinity,
856 FALSE) //No float save
857 != STATUS_SUCCESS)
858 {
859 uhci_release(pdev);
860 return NULL;
861 }
862
863 return pdev;
864 }
865
866 BOOLEAN
867 uhci_release(PDEVICE_OBJECT pdev)
868 {
869 PDEVICE_EXTENSION pdev_ext;
870 PUHCI_DEV uhci;
871
872 if (pdev == NULL)
873 return FALSE;
874
875 pdev_ext = pdev->DeviceExtension;
876
877 if (pdev_ext == NULL)
878 return FALSE;
879
880 uhci = pdev_ext->uhci;
881 if (uhci == NULL)
882 return FALSE;
883
884 uhci_stop(uhci);
885 //pdev_ext->uhci->conn_count = 0;
886 pdev_ext->uhci->fsbr_cnt = 0;
887
888 if (pdev_ext->uhci_int)
889 {
890 IoDisconnectInterrupt(pdev_ext->uhci_int);
891 pdev_ext->uhci_int = NULL;
892 }
893 else
894 TRAP();
895 destroy_pending_endp_pool(&pdev_ext->uhci->pending_endp_pool);
896 //pdev_ext->uhci->pending_endp_pool = NULL;
897
898 uhci_destroy_schedule(uhci);
899
900 release_adapter(pdev_ext->padapter);
901 pdev_ext->padapter = NULL;
902
903 uhci_delete_device(pdev);
904
905 return FALSE;
906
907 }
908
909 // send cmds to start the uhc
910 // shamelessly copied from linux's uhci.c (reset_hc(), configure_hc() routines)
911 BOOLEAN
912 uhci_start(PHCD hcd)
913 {
914 PUHCI_DEV uhci;
915 PBYTE io_addr;
916 USHORT pirq;
917 PCI_SLOT_NUMBER SlotNum;
918 int timeout = 10000;
919
920 uhci = uhci_from_hcd(hcd);
921 io_addr = uhci->port_base;
922
923 /*
924 * Reset the HC - this will force us to get a
925 * new notification of any already connected
926 * ports due to the virtual disconnect that it
927 * implies.
928 */
929 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_HCRESET);
930 while (READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD)) & USBCMD_HCRESET)
931 {
932 if (!--timeout)
933 {
934 break;
935 }
936 }
937
938 /* Turn on all interrupts */
939 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR),
940 USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP);
941
942 /* Start at frame 0 */
943 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBFRNUM), 0);
944 WRITE_PORT_ULONG((PULONG) (io_addr + USBFLBASEADD), uhci->frame_list_logic_addr.LowPart);
945
946 /* Run and mark it configured with a 64-byte max packet */
947 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
948
949 DbgPrint("uhci_start(): current uhci status=0x%x\n", uhci_status(uhci));
950
951 /* Enable PIRQ */
952 pirq = USBLEGSUP_DEFAULT;
953 SlotNum.u.AsULONG = 0;
954 SlotNum.u.bits.DeviceNumber = ((uhci->pdev_ext->pci_addr & 0xff) >> 3);
955 SlotNum.u.bits.FunctionNumber = (uhci->pdev_ext->pci_addr & 0x07);
956
957 DbgPrint("uhci_start(): set bus %d data at slot 0x%x\n", (uhci->pdev_ext->pci_addr >> 8),
958 SlotNum.u.AsULONG);
959
960 HalSetBusDataByOffset(PCIConfiguration, (uhci->pdev_ext->pci_addr >> 8), SlotNum.u.AsULONG,
961 &pirq, USBLEGSUP, sizeof(pirq));
962
963 return TRUE;
964 }
965
966 VOID
967 uhci_stop(PUHCI_DEV uhci)
968 {
969 PBYTE io_addr = uhci->port_base;
970 // turn off all the interrupt
971 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR), 0);
972 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
973 }
974
975 static VOID
976 uhci_reset(PUHCI_DEV uhci)
977 {
978 PBYTE io_addr = uhci->port_base;
979
980 uhci_stop(uhci);
981 /* Global reset for 50ms */
982 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_GRESET);
983 //uhci_wait_ms( uhci, 50 );
984 usb_wait_ms_dpc(50);
985
986 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
987 //uhci_wait_ms( uhci, 10 );
988 usb_wait_ms_dpc(10);
989 }
990
991 VOID
992 uhci_suspend(PUHCI_DEV uhci)
993 {
994 PBYTE io_addr = uhci->port_base;
995
996 //uhci->is_suspended = 1;
997 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_EGSM);
998
999 }
1000
1001 VOID
1002 uhci_wakeup(PUHCI_DEV uhci)
1003 {
1004 PBYTE io_addr;
1005 unsigned int status;
1006
1007 io_addr = uhci->port_base;
1008
1009 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
1010
1011 /* wait for EOP to be sent */
1012 status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));
1013 while (status & USBCMD_FGR)
1014 status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));
1015
1016 //uhci->is_suspended = 0;
1017
1018 /* Run and mark it configured with a 64-byte max packet */
1019 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
1020
1021 }
1022
1023 BOOLEAN
1024 uhci_init_schedule(PUHCI_DEV uhci, PADAPTER_OBJECT padapter)
1025 {
1026 int i, irq;
1027
1028 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_init_schedule(): entering..., uhci=0x%x\n", uhci));
1029 if (uhci == NULL || padapter == NULL)
1030 return FALSE;
1031
1032 if (init_td_pool_list(&uhci->td_pool, padapter) == FALSE)
1033 {
1034 return FALSE;
1035 }
1036 if (init_qh_pool(&uhci->qh_pool, padapter) == FALSE)
1037 {
1038 return FALSE;
1039 }
1040
1041 //since uhci is not started we can freely access all resources.
1042 for(i = 0; i < UHCI_MAX_SKELTDS; i++)
1043 {
1044 uhci->skel_td[i] = alloc_td(&uhci->td_pool);
1045 uhci_fill_td(uhci->skel_td[i], 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
1046
1047 if (i > 0)
1048 {
1049 uhci->skel_td[i]->link = uhci->skel_td[i - 1]->phy_addr;
1050 }
1051 }
1052
1053 /*for( i = UHCI_MAX_SKELTDS - 3; i >= 0; i-- )
1054 {
1055 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1056 &uhci->skel_td[ i ]->ptde->hori_link );
1057 } */
1058
1059 for(i = 0; i < UHCI_MAX_SKELQHS; i++)
1060 {
1061 uhci->skel_qh[i] = alloc_qh(&uhci->qh_pool);
1062 if (i > 0)
1063 {
1064 uhci->skel_qh[i - 1]->link = uhci->skel_qh[i]->phy_addr;
1065 }
1066
1067 uhci->skel_qh[i]->element = UHCI_PTR_TERM;
1068 }
1069
1070 uhci->skel_int1_td->link = uhci->skel_ls_control_qh->phy_addr;
1071
1072 // Hack for PIIX
1073 uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
1074 uhci->skel_term_td->link = uhci->skel_term_td->phy_addr;
1075
1076 uhci->skel_term_qh->link = UHCI_PTR_TERM;
1077 uhci->skel_term_qh->element = uhci->skel_term_td->phy_addr;
1078
1079 InsertTailList(&uhci->skel_term_qh->pqhe->vert_link, &uhci->skel_term_td->ptde->vert_link);
1080
1081 /*for( i = 0; i < UHCI_MAX_SKELQHS; i++ )
1082 {
1083 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1084 &uhci->skel_qh[ i ]->pqhe->hori_link );
1085 } */
1086
1087 if (uhci_init_frame_list(uhci, uhci->pdev_ext->padapter) == FALSE)
1088 uhci_destroy_frame_list(uhci);
1089
1090 //well all have been chained, now scatter the int tds to frame-list
1091 //shamelessly pasted from linux's uhci.c :-)
1092 for(i = 0; i < UHCI_MAX_FRAMES; i++)
1093 {
1094 irq = 0;
1095 if (i & 1)
1096 {
1097 irq++;
1098 if (i & 2)
1099 {
1100 irq++;
1101 if (i & 4)
1102 {
1103 irq++;
1104 if (i & 8)
1105 {
1106 irq++;
1107 if (i & 16)
1108 {
1109 irq++;
1110 if (i & 32)
1111 {
1112 irq++;
1113 if (i & 64)
1114 irq++;
1115 }
1116 }
1117 }
1118 }
1119 }
1120 }
1121
1122 /* Only place we don't use the frame list routines */
1123 uhci->frame_list[i] = uhci->skel_td[irq]->phy_addr;
1124 }
1125 return TRUE;
1126 }
1127
1128 BOOLEAN
1129 uhci_destroy_schedule(PUHCI_DEV uhci)
1130 {
1131 BOOLEAN ret;
1132
1133 ret = uhci_destroy_frame_list(uhci);
1134 ret = destroy_qh_pool(&uhci->qh_pool);
1135 ret = destroy_td_pool_list(&uhci->td_pool);
1136
1137 return ret;
1138
1139 }
1140
1141 VOID NTAPI
1142 uhci_cancel_pending_endp_urb(IN PVOID Parameter)
1143 {
1144 PLIST_ENTRY abort_list;
1145 PUSB_DEV pdev;
1146 PURB purb;
1147 USE_BASIC_NON_PENDING_IRQL;
1148
1149 abort_list = (PLIST_ENTRY) Parameter;
1150
1151 if (abort_list == NULL)
1152 return;
1153
1154 while (IsListEmpty(abort_list) == FALSE)
1155 {
1156 //these devs are protected by urb's ref-count
1157 purb = (PURB) RemoveHeadList(abort_list);
1158 pdev = purb->pdev;
1159 // purb->status is set when they are added to abort_list
1160
1161 uhci_generic_urb_completion(purb, purb->context);
1162
1163 lock_dev(pdev, FALSE);
1164 pdev->ref_count--;
1165 unlock_dev(pdev, FALSE);
1166 }
1167 usb_free_mem(abort_list);
1168 return;
1169 }
1170
1171 BOOLEAN
1172 uhci_process_pending_endp(PUHCI_DEV uhci)
1173 {
1174 PUSB_DEV pdev;
1175 LIST_ENTRY temp_list, abort_list;
1176 PLIST_ENTRY pthis;
1177 PURB purb;
1178 PUSB_ENDPOINT pendp;
1179 NTSTATUS can_submit = STATUS_UNSUCCESSFUL;
1180 PWORK_QUEUE_ITEM pwork_item;
1181 PLIST_ENTRY cancel_list;
1182 USE_BASIC_IRQL;
1183
1184 if (uhci == NULL)
1185 return FALSE;
1186
1187 InitializeListHead(&temp_list);
1188 InitializeListHead(&abort_list);
1189
1190 purb = NULL;
1191 uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): entering..., uhci=0x%x\n", uhci));
1192
1193 lock_pending_endp_list(&uhci->pending_endp_list_lock);
1194 while (IsListEmpty(&uhci->pending_endp_list) == FALSE)
1195 {
1196
1197 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): pending_endp_list=0x%x\n",
1198 &uhci->pending_endp_list));
1199
1200 pthis = RemoveHeadList(&uhci->pending_endp_list);
1201 pendp = ((PUHCI_PENDING_ENDP) pthis)->pendp;
1202 pdev = dev_from_endp(pendp);
1203
1204 lock_dev(pdev, TRUE);
1205
1206 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1207 {
1208 unlock_dev(pdev, TRUE);
1209 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1210 //delegate to uhci_remove_device for removing the urb queue on the endpoint
1211 continue;
1212 }
1213
1214 if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
1215 {
1216 while (IsListEmpty(&pendp->urb_list) == FALSE)
1217 {
1218 purb = (PURB) RemoveHeadList(&pendp->urb_list);
1219 purb->status = USB_STATUS_ENDPOINT_HALTED;
1220 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
1221 }
1222 InitializeListHead(&pendp->urb_list);
1223 unlock_dev(pdev, TRUE);
1224 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1225 continue;
1226 }
1227
1228
1229 if (IsListEmpty(&pendp->urb_list) == FALSE)
1230 {
1231 purb = (PURB) RemoveHeadList(&pendp->urb_list);
1232 ASSERT(purb);
1233 }
1234 else
1235 {
1236 InitializeListHead(&pendp->urb_list);
1237 unlock_dev(pdev, TRUE);
1238 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1239 continue;
1240 }
1241
1242 // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
1243 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): endp_type=0x%x\n",
1244 endp_type(pendp)));
1245 switch (endp_type(pendp))
1246 {
1247 case USB_ENDPOINT_XFER_BULK:
1248 {
1249 #ifdef DEMO
1250 can_submit = STATUS_UNSUCCESSFUL;
1251 #else
1252 can_submit = uhci_internal_submit_bulk(uhci, purb);
1253 #endif
1254 break;
1255 }
1256 case USB_ENDPOINT_XFER_CONTROL:
1257 {
1258 can_submit = uhci_internal_submit_ctrl(uhci, purb);
1259 break;
1260 }
1261 case USB_ENDPOINT_XFER_INT:
1262 {
1263 can_submit = uhci_internal_submit_int(uhci, purb);
1264 break;
1265 }
1266 case USB_ENDPOINT_XFER_ISOC:
1267 {
1268 can_submit = uhci_internal_submit_iso(uhci, purb);
1269 break;
1270 }
1271 }
1272
1273 if (can_submit == STATUS_NO_MORE_ENTRIES)
1274 {
1275 //no enough bandwidth or tds
1276 InsertHeadList(&pendp->urb_list, &purb->urb_link);
1277 InsertTailList(&temp_list, pthis);
1278 }
1279 else
1280 {
1281 // other error or success
1282 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1283
1284 if (can_submit != STATUS_SUCCESS)
1285 {
1286 //abort these URBs
1287 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
1288 uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): unable to submit urb 0x%x, "
1289 "with status=0x%x\n", purb, can_submit));
1290 purb->status = can_submit;
1291 }
1292
1293 }
1294 unlock_dev(pdev, TRUE);
1295 }
1296
1297 if (IsListEmpty(&temp_list) == FALSE)
1298 {
1299 //re-append them to the pending_endp_list
1300 ListFirst(&temp_list, pthis);
1301 RemoveEntryList(&temp_list);
1302 MergeList(&uhci->pending_endp_list, pthis);
1303 }
1304 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1305
1306 if (IsListEmpty(&abort_list) == FALSE)
1307 {
1308 PLIST_ENTRY pthis;
1309 cancel_list = (PLIST_ENTRY) usb_alloc_mem(NonPagedPool, sizeof(WORK_QUEUE_ITEM) + sizeof(LIST_ENTRY));
1310 ASSERT(cancel_list);
1311
1312 ListFirst(&abort_list, pthis);
1313 RemoveEntryList(&abort_list);
1314 InsertTailList(pthis, cancel_list);
1315
1316 pwork_item = (PWORK_QUEUE_ITEM) (cancel_list + 1);
1317
1318 // we do not need to worry the uhci_cancel_pending_endp_urb running when the
1319 // driver is unloading since it will prevent the dev_mgr to quit till all the
1320 // reference count to the dev drop to zero.
1321 ExInitializeWorkItem(pwork_item, uhci_cancel_pending_endp_urb, (PVOID) cancel_list);
1322 ExQueueWorkItem(pwork_item, DelayedWorkQueue);
1323 }
1324 return TRUE;
1325 }
1326
1327 NTSTATUS
1328 uhci_submit_urb(PUHCI_DEV uhci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
1329 {
1330 int i;
1331 PUHCI_PENDING_ENDP pending_endp;
1332 NTSTATUS status;
1333 USE_BASIC_IRQL;
1334
1335 if (uhci == NULL || pdev == NULL || pendp == NULL || purb == NULL)
1336 {
1337 uhci_dbg_print(DBGLVL_MEDIUM,
1338 ("uhci_submit_urb(): uhci=0x%x, pdev=0x%x, pendp=0x%x, purb=0x%x "
1339 "called with invalid param!\n", uhci, pdev, pendp, purb));
1340 return STATUS_INVALID_PARAMETER;
1341 }
1342
1343 lock_pending_endp_list(&uhci->pending_endp_list_lock);
1344 lock_dev(pdev, TRUE);
1345
1346 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1347 {
1348 status = purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1349 goto LBL_OUT;
1350 }
1351
1352 if (dev_class(pdev) == USB_DEV_CLASS_ROOT_HUB)
1353 {
1354 unlock_dev(pdev, TRUE);
1355 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1356 status = uhci_rh_submit_urb(pdev, purb);
1357 return status;
1358 }
1359
1360 if (pendp)
1361 purb->pendp = pendp;
1362 else
1363 purb->pendp = &pdev->default_endp;
1364
1365 if (dev_from_endp(purb->pendp) != pdev)
1366 {
1367 uhci_dbg_print(DBGLVL_MEDIUM,
1368 ("uhci_submit_urb(): dev_from_endp=0x%x\n, pdev=0x%x, pendp=0x%x "
1369 "devices mismatch!\n", dev_from_endp(purb->pendp), pdev, pendp));
1370
1371 status = purb->status = STATUS_INVALID_PARAMETER;
1372 goto LBL_OUT;
1373 }
1374
1375 if (endp_state(purb->pendp) == USB_ENDP_FLAG_STALL)
1376 {
1377 status = purb->status = USB_STATUS_ENDPOINT_HALTED;
1378 goto LBL_OUT;
1379 }
1380
1381 purb->pdev = pdev;
1382 purb->rest_bytes = purb->data_length;
1383
1384 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_BULK)
1385 purb->bytes_to_transfer = (purb->data_length > purb->pendp->pusb_endp_desc->wMaxPacketSize * UHCI_MAX_TDS_PER_TRANSFER ? purb->pendp->pusb_endp_desc->wMaxPacketSize * UHCI_MAX_TDS_PER_TRANSFER : purb->data_length); //multiple transfer for large data block
1386 else
1387 purb->bytes_to_transfer = purb->data_length;
1388
1389 uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_submit_urb(): bytes_to_transfer=0x%x\n", purb->bytes_to_transfer));
1390
1391 purb->bytes_transfered = 0;
1392 InitializeListHead(&purb->trasac_list);
1393 purb->last_finished_td = &purb->trasac_list;
1394 purb->flags &= ~(URB_FLAG_STATE_MASK | URB_FLAG_IN_SCHEDULE | URB_FLAG_FORCE_CANCEL);
1395 purb->flags |= URB_FLAG_STATE_PENDING;
1396
1397
1398 i = IsListEmpty(&pendp->urb_list);
1399 InsertTailList(&pendp->urb_list, &purb->urb_link);
1400
1401 pdev->ref_count++; //for urb reference
1402
1403 if (i == FALSE)
1404 {
1405 //there is urb pending, simply queue it and return
1406 status = purb->status = STATUS_PENDING;
1407 goto LBL_OUT;
1408 }
1409 else if (usb_endp_busy_count(purb->pendp) && endp_type(purb->pendp) != USB_ENDPOINT_XFER_ISOC)
1410 {
1411 //
1412 //No urb waiting but urb overlap not allowed,
1413 //so leave it in queue and return, will be scheduled
1414 //later
1415 //
1416 status = purb->status = STATUS_PENDING;
1417 goto LBL_OUT;
1418 }
1419
1420 pending_endp = alloc_pending_endp(&uhci->pending_endp_pool, 1);
1421 if (pending_endp == NULL)
1422 {
1423 //panic
1424 status = purb->status = STATUS_UNSUCCESSFUL;
1425 goto LBL_OUT2;
1426 }
1427
1428 pending_endp->pendp = purb->pendp;
1429 InsertTailList(&uhci->pending_endp_list, &pending_endp->endp_link );
1430
1431 unlock_dev(pdev, TRUE);
1432 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1433
1434 uhci_process_pending_endp(uhci);
1435 return STATUS_PENDING;
1436
1437 LBL_OUT2:
1438 pdev->ref_count--;
1439 RemoveEntryList(&purb->urb_link);
1440
1441 LBL_OUT:
1442 unlock_dev(pdev, TRUE);
1443 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1444 return status;
1445 }
1446
1447 NTSTATUS
1448 uhci_set_error_code(PURB urb, ULONG raw_status)
1449 {
1450 if ((raw_status & TD_CTRL_ANY_ERROR) == 0)
1451 {
1452 //test if the urb is canceled
1453 if (urb->flags & URB_FLAG_FORCE_CANCEL)
1454 urb->status = STATUS_CANCELLED;
1455 else
1456 urb->status = STATUS_SUCCESS;
1457 }
1458
1459 else if (raw_status & TD_CTRL_BABBLE)
1460 urb->status = USB_STATUS_DATA_OVERRUN;
1461
1462 else if (raw_status & TD_CTRL_STALLED)
1463 urb->status = USB_STATUS_STALL_PID;
1464
1465 else if (raw_status & TD_CTRL_DBUFERR)
1466 urb->status = USB_STATUS_BUFFER_OVERRUN;
1467
1468 else if (raw_status & TD_CTRL_CRCTIMEO)
1469 urb->status = USB_STATUS_CRC;
1470
1471 else if (raw_status & TD_CTRL_BITSTUFF)
1472 urb->status = USB_STATUS_BTSTUFF;
1473
1474 else
1475 urb->status = STATUS_UNSUCCESSFUL;
1476
1477 return urb->status;
1478 }
1479
1480 BOOLEAN NTAPI
1481 uhci_sync_remove_urb_finished(PVOID context)
1482 {
1483 PUHCI_DEV uhci;
1484 PLIST_ENTRY pthis, pnext, ptemp;
1485 PURB purb;
1486 PSYNC_PARAM pparam;
1487
1488 pparam = (PSYNC_PARAM) context;
1489 uhci = pparam->uhci;
1490 ptemp = (PLIST_ENTRY) pparam->context;
1491
1492 if (uhci == NULL)
1493 {
1494 return (UCHAR) (pparam->ret = FALSE);
1495 }
1496
1497 ListFirst(&uhci->urb_list, pthis);
1498 while (pthis)
1499 {
1500 //remove urbs not in the schedule
1501 ListNext(&uhci->urb_list, pthis, pnext);
1502 purb = (PURB) pthis;
1503
1504 if ((purb->flags & URB_FLAG_IN_SCHEDULE) == 0)
1505 {
1506 //finished or canceled( not apply for split bulk ).
1507 purb->flags &= ~URB_FLAG_STATE_MASK;
1508 purb->flags |= URB_FLAG_STATE_FINISHED;
1509 RemoveEntryList(pthis);
1510 InsertTailList(ptemp, pthis);
1511 }
1512 pthis = pnext;
1513 }
1514 pparam->ret = TRUE;
1515 return (UCHAR) TRUE;
1516 }
1517
1518 BOOLEAN
1519 uhci_drop_fsbr(PUHCI_DEV uhci)
1520 {
1521 if (uhci == NULL)
1522 return (UCHAR) FALSE;
1523
1524 uhci->fsbr_cnt--;
1525
1526 if (uhci->fsbr_cnt <= 0)
1527 {
1528 uhci->skel_term_qh->link = UHCI_PTR_TERM;
1529 uhci->fsbr_cnt = 0;
1530 }
1531
1532 return (UCHAR) TRUE;
1533 }
1534
1535 VOID NTAPI
1536 uhci_dpc_callback(PKDPC dpc, PVOID context, PVOID sysarg1, PVOID sysarg2)
1537 {
1538 PUHCI_DEV uhci;
1539
1540 LIST_HEAD temp_list;
1541 PLIST_ENTRY pthis, pnext;
1542 PURB purb;
1543 PQH_EXTENSION pqhe;
1544 PUHCI_PENDING_ENDP pending_endp;
1545 PUSB_DEV pdev;
1546 PUSB_ENDPOINT pendp;
1547
1548 BOOLEAN finished;
1549 LONG i, j;
1550 ULONG uhci_status, urb_status, toggle = 0;
1551
1552 SYNC_PARAM sync_param;
1553 USE_BASIC_NON_PENDING_IRQL;
1554
1555 UNREFERENCED_PARAMETER(dpc);
1556 UNREFERENCED_PARAMETER(sysarg2);
1557
1558 uhci = (PUHCI_DEV) context;
1559 if (uhci == NULL)
1560 return;
1561
1562 uhci_status = (ULONG) sysarg1;
1563
1564 InitializeListHead(&temp_list);
1565
1566 sync_param.uhci = uhci;
1567 sync_param.context = (PVOID) & temp_list;
1568
1569 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_dpc_callback(): entering..., uhci=0x%x\n", uhci));
1570 //remove finished urb from uhci's urb-list
1571 KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_remove_urb_finished, &sync_param);
1572
1573 //release resources( tds, and qhs ) the urb occupied
1574 while (IsListEmpty(&temp_list) == FALSE)
1575 {
1576 //not in any public queue, if do not access into dev, no race
1577 //condition will occur
1578 purb = (PURB) RemoveHeadList(&temp_list);
1579 urb_status = purb->status;
1580
1581 //the only place we do not use this lock on non-pending-endp-list data ops
1582 KeAcquireSpinLockAtDpcLevel(&uhci->pending_endp_list_lock);
1583 while (IsListEmpty(&purb->trasac_list) == FALSE)
1584 {
1585 pthis = RemoveHeadList(&purb->trasac_list);
1586
1587 if ((((PTD_EXTENSION) pthis)->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
1588 {
1589 pqhe = (PQH_EXTENSION) pthis;
1590 lock_qh_pool(&uhci->qh_pool, TRUE);
1591 free_qh(&uhci->qh_pool, pqhe->pqh);
1592 unlock_qh_pool(&uhci->qh_pool, TRUE);
1593 }
1594 else
1595 {
1596 //must be a td chain
1597 InsertHeadList(&purb->trasac_list, pthis);
1598 for(i = 0, purb->bytes_transfered = 0; i < purb->td_count; i++)
1599 {
1600 PUHCI_TD ptd;
1601 // accumulate data transfered in tds
1602 ptd = ((PTD_EXTENSION) pthis)->ptd;
1603 if ((ptd->status & TD_CTRL_ACTIVE) == 0 && (ptd->status & TD_CTRL_ANY_ERROR) == 0)
1604 {
1605 j = ptd->status & 0x7ff;
1606 purb->bytes_transfered += ((j == 0x7ff) ? 0 : (j + 1));
1607
1608 }
1609 ListNext(&purb->trasac_list, pthis, pnext);
1610 pthis = pnext;
1611 }
1612
1613 if (urb_status & TD_CTRL_ANY_ERROR)
1614 {
1615 if (purb->last_finished_td != NULL && purb->last_finished_td != &purb->trasac_list)
1616 toggle = (((PTD_EXTENSION) purb->last_finished_td)->ptd->info & (1 << 19));
1617 }
1618 //trick, remove trasac_list
1619 ListFirst(&purb->trasac_list, pthis);
1620 RemoveEntryList(&purb->trasac_list);
1621 lock_td_pool(&uhci->td_pool, TRUE);
1622 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
1623 unlock_td_pool(&uhci->td_pool, TRUE);
1624 //termination condition
1625 InitializeListHead(&purb->trasac_list);
1626 purb->last_finished_td = NULL;
1627 }
1628 }
1629
1630 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_ISOC
1631 || endp_type(purb->pendp) == USB_ENDPOINT_XFER_INT)
1632 uhci_claim_bandwidth(uhci, purb, FALSE); //release band-width
1633
1634 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1635
1636 uhci_set_error_code(purb, urb_status);
1637
1638 finished = TRUE;
1639
1640 //since the ref_count for the urb is not released, we can safely have one
1641 //pointer to dev
1642 pdev = dev_from_endp(purb->pendp);
1643 pendp = purb->pendp;
1644
1645 if (purb->status == USB_STATUS_BABBLE_DETECTED)
1646 {
1647 usb_dbg_print(DBGLVL_MEDIUM,
1648 ("uhci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus\n"));
1649 uhci_reset(uhci);
1650 uhci_start(&uhci->hcd_interf);
1651 }
1652
1653 //this will let the new request in uhci_generic_urb_completion to this endp
1654 //be processed rather than queued in the pending_endp_list
1655 lock_dev(pdev, TRUE);
1656 usb_endp_busy_count_dec(pendp);
1657 unlock_dev(pdev, TRUE);
1658
1659 if (usb_success(purb->status) == FALSE)
1660 {
1661 // set error code and complete the urb and purb is invalid from this point
1662 uhci_generic_urb_completion(purb, purb->context);
1663 }
1664 else
1665 {
1666 if ((purb->pipe & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
1667 {
1668 purb->rest_bytes -= purb->bytes_transfered;
1669 if (purb->rest_bytes)
1670 {
1671 finished = FALSE;
1672 }
1673 else
1674 {
1675 uhci_generic_urb_completion(purb, purb->context);
1676 }
1677 }
1678 else
1679 {
1680 uhci_generic_urb_completion(purb, purb->context);
1681 //purb is now invalid
1682 }
1683 }
1684
1685 KeAcquireSpinLockAtDpcLevel(&uhci->pending_endp_list_lock);
1686 lock_dev(pdev, TRUE);
1687
1688 if (finished)
1689 pdev->ref_count--;
1690
1691 if (urb_status & TD_CTRL_ANY_ERROR && endp_type(pendp) != USB_ENDPOINT_XFER_CONTROL)
1692 {
1693 pendp->flags &= ~USB_ENDP_FLAG_STAT_MASK;
1694 pendp->flags |= USB_ENDP_FLAG_STALL;
1695 }
1696
1697 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1698 {
1699 unlock_dev(pdev, TRUE);
1700 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1701 if (finished == FALSE)
1702 {
1703
1704 purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1705 uhci_generic_urb_completion(purb, purb->context);
1706
1707 lock_dev(pdev, TRUE);
1708 pdev->ref_count--;
1709 unlock_dev(pdev, TRUE);
1710 }
1711 continue;
1712 }
1713
1714 if (finished && IsListEmpty(&pendp->urb_list) == TRUE)
1715 {
1716 unlock_dev(pdev, TRUE);
1717 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1718 continue;
1719 }
1720 else if (finished == TRUE)
1721 {
1722 //has urb in the endp's urb-list
1723 if (usb_endp_busy_count(pendp) > 0)
1724 {
1725 //the urbs still have chance to be sheduled but not this time
1726 unlock_dev(pdev, TRUE);
1727 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1728 continue;
1729 }
1730 }
1731
1732 if (finished == FALSE)
1733 {
1734 //a split bulk transfer
1735 purb->bytes_transfered = 0;
1736 purb->bytes_to_transfer =
1737 UHCI_MAX_TDS_PER_TRANSFER * purb->pendp->pusb_endp_desc->wMaxPacketSize
1738 > purb->rest_bytes
1739 ? purb->rest_bytes : UHCI_MAX_TDS_PER_TRANSFER * purb->pendp->pusb_endp_desc->wMaxPacketSize;
1740
1741 //the urb is not finished
1742 purb->flags &= ~URB_FLAG_STATE_MASK;
1743 purb->flags |= URB_FLAG_STATE_PENDING;
1744
1745 InsertHeadList(&pendp->urb_list, &purb->urb_link);
1746 }
1747
1748 pending_endp = alloc_pending_endp(&uhci->pending_endp_pool, 1);
1749 if (!pending_endp)
1750 {
1751 unlock_dev(pdev, TRUE);
1752 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1753 return;
1754 }
1755
1756 pending_endp->pendp = pendp;
1757 InsertTailList(&uhci->pending_endp_list, &pending_endp->endp_link);
1758
1759 unlock_dev(pdev, TRUE);
1760 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1761 }
1762
1763 //ah...exhausted, let's find some in the pending_endp_list to rock
1764 uhci_process_pending_endp(uhci);
1765 return;
1766 }
1767
1768 BOOLEAN
1769 uhci_add_device(PUHCI_DEV uhci, PUSB_DEV dev)
1770 {
1771 if (dev == NULL || uhci == NULL)
1772 return FALSE;
1773
1774 return TRUE;
1775 }
1776
1777 BOOLEAN NTAPI
1778 uhci_sync_cancel_urbs_dev(PVOID context)
1779 {
1780 //cancel all the urbs on one dev
1781 PUHCI_DEV uhci;
1782 PUSB_DEV pdev, dest_dev;
1783 PSYNC_PARAM sync_param;
1784 PLIST_ENTRY pthis, pnext;
1785 LONG count;
1786
1787 sync_param = (PSYNC_PARAM) context;
1788 dest_dev = (PUSB_DEV) sync_param->context;
1789 uhci = sync_param->uhci;
1790
1791 if (uhci == NULL || dest_dev == NULL)
1792 {
1793 return (UCHAR) (sync_param->ret = FALSE);
1794 }
1795 count = 0;
1796 ListFirst(&uhci->urb_list, pthis);
1797 while (pthis)
1798 {
1799 pdev = dev_from_endp(((PURB) pthis)->pendp);
1800 if (pdev == dest_dev)
1801 {
1802 ((PURB) pthis)->flags |= URB_FLAG_FORCE_CANCEL;
1803 }
1804 ListNext(&uhci->urb_list, pthis, pnext);
1805 pthis = pnext;
1806 count++;
1807 }
1808 if (count)
1809 uhci->skel_term_td->status |= TD_CTRL_IOC;
1810
1811 return (UCHAR) (sync_param->ret = TRUE);
1812 }
1813
1814 BOOLEAN
1815 uhci_remove_device(PUHCI_DEV uhci, PUSB_DEV dev)
1816 {
1817 PUHCI_PENDING_ENDP ppending_endp;
1818 PLIST_ENTRY pthis, pnext;
1819 PURB purb;
1820 LIST_HEAD temp_list;
1821 int i, j, k;
1822 SYNC_PARAM sync_param;
1823
1824 USE_BASIC_IRQL;
1825
1826 if (uhci == NULL || dev == NULL)
1827 return FALSE;
1828
1829 InitializeListHead(&temp_list);
1830
1831 //free pending endp that has urb queued from pending endp list
1832 lock_pending_endp_list(&uhci->pending_endp_list_lock);
1833
1834 ListFirst(&uhci->pending_endp_list, pthis);
1835
1836 while (pthis)
1837 {
1838 ppending_endp = (PUHCI_PENDING_ENDP) pthis;
1839 ListNext(&uhci->pending_endp_list, pthis, pnext);
1840 if (dev_from_endp(ppending_endp->pendp) == dev)
1841 {
1842 RemoveEntryList(pthis);
1843 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1844 }
1845 pthis = pnext;
1846 }
1847 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1848
1849 //cancel all the urbs in the urb-list
1850 sync_param.uhci = uhci;
1851 sync_param.context = (PVOID) dev;
1852
1853 KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_cancel_urbs_dev, &sync_param);
1854
1855 //cancel all the urb in the endp's urb-list
1856 k = 0;
1857 lock_dev(dev, FALSE);
1858 if (dev->usb_config)
1859 {
1860 //only for configed dev
1861 for(i = 0; i < dev->usb_config->if_count; i++)
1862 {
1863 for(j = 0; j < dev->usb_config->interf[i].endp_count; j++)
1864 {
1865 ListFirst(&dev->usb_config->interf[i].endp[j].urb_list, pthis);
1866 while (pthis)
1867 {
1868 ListNext(&dev->usb_config->interf[i].endp[j].urb_list, pthis, pnext);
1869
1870 RemoveEntryList(pthis);
1871 InsertHeadList(&temp_list, pthis);
1872 pthis = pnext;
1873 k++;
1874 }
1875
1876 }
1877 }
1878 }
1879 ListFirst(&dev->default_endp.urb_list, pthis);
1880
1881 while (pthis)
1882 {
1883 ListNext(&dev->default_endp.urb_list, pthis, pnext);
1884
1885 RemoveEntryList(pthis);
1886 InsertHeadList(&temp_list, pthis);
1887 pthis = pnext;
1888 k++;
1889 }
1890 unlock_dev(dev, FALSE);
1891
1892 if (IsListEmpty(&temp_list) == FALSE)
1893 {
1894 for(i = 0; i < k; i++)
1895 {
1896 //complete those urbs with error
1897 pthis = RemoveHeadList(&temp_list);
1898 purb = (PURB) pthis;
1899 purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1900 {
1901 uhci_generic_urb_completion(purb, purb->context);
1902 }
1903 }
1904 }
1905
1906 lock_dev(dev, FALSE) dev->ref_count -= k;
1907 unlock_dev(dev, FALSE);
1908
1909 return TRUE;
1910 }
1911
1912
1913 //
1914 // assume that the urb has its rest_bytes and bytes_to_transfer set
1915 // and bytes_transfered is zeroed.
1916 // dev_lock must be acquired outside
1917 // urb comes from dev's endpoint urb-list. it is already removed from
1918 // the endpoint urb-list.
1919 //
1920 NTSTATUS
1921 uhci_internal_submit_bulk(PUHCI_DEV uhci, PURB urb)
1922 {
1923
1924 LONG max_packet_size, td_count, offset, bytes_to_transfer, data_load;
1925 PBYTE start_addr;
1926 PUHCI_TD ptd;
1927 PUHCI_QH pqh;
1928 LIST_ENTRY td_list, *pthis, *pnext;
1929 BOOLEAN old_toggle, toggle, ret;
1930 UCHAR pid;
1931
1932 if (uhci == NULL || urb == NULL)
1933 return STATUS_INVALID_PARAMETER;
1934
1935 max_packet_size = endp_max_packet_size(urb->pendp);
1936 if (urb->bytes_to_transfer == 0)
1937 {
1938 return STATUS_INVALID_PARAMETER;
1939 }
1940
1941 td_count = (urb->bytes_to_transfer + max_packet_size - 1) / max_packet_size;
1942
1943 lock_td_pool(&uhci->td_pool, TRUE);
1944 if (can_transfer(&uhci->td_pool, td_count) == FALSE)
1945 {
1946 unlock_td_pool(&uhci->td_pool, TRUE);
1947 return STATUS_NO_MORE_ENTRIES;
1948 }
1949
1950 ptd = alloc_tds(&uhci->td_pool, td_count);
1951 unlock_td_pool(&uhci->td_pool, TRUE);
1952
1953 if (ptd == NULL)
1954 {
1955 return STATUS_UNSUCCESSFUL;
1956 }
1957
1958 InitializeListHead(&td_list);
1959 InsertTailList(&ptd->ptde->vert_link, &td_list);
1960
1961 ListFirst(&td_list, pthis);
1962 ListNext(&td_list, pthis, pnext);
1963
1964 start_addr = &urb->data_buffer[urb->data_length - urb->rest_bytes];
1965 offset = 0;
1966
1967 old_toggle = toggle = urb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE ? TRUE : FALSE;
1968 bytes_to_transfer = urb->bytes_to_transfer;
1969
1970 urb->pipe = ((max_packet_size - 1) << 21)
1971 | ((ULONG) endp_num(urb->pendp) << 15)
1972 | (dev_from_endp(urb->pendp)->dev_addr << 8)
1973 | ((ULONG) endp_dir(urb->pendp)) | USB_ENDPOINT_XFER_BULK;
1974
1975 pid = (((ULONG) urb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT);
1976 while (pthis)
1977 {
1978 ptd = ((PTD_EXTENSION) pthis)->ptd;
1979
1980 data_load = max_packet_size < bytes_to_transfer ? max_packet_size : bytes_to_transfer;
1981 ptd->purb = urb;
1982 uhci_fill_td(ptd,
1983 (3 << TD_CTRL_C_ERR_SHIFT)
1984 | (TD_CTRL_ACTIVE),
1985 ((data_load - 1) << 21)
1986 | (toggle << 19)
1987 | ((ULONG) endp_num(urb->pendp) << 15)
1988 | (dev_from_endp(urb->pendp)->dev_addr << 8)
1989 | pid, MmGetPhysicalAddress(start_addr + offset).LowPart);
1990
1991 bytes_to_transfer -= data_load;
1992 offset += data_load;
1993
1994 if (pnext)
1995 {
1996 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
1997 }
1998 else
1999 {
2000 //Last one, enable ioc and short packet detect if necessary
2001 ptd->link = UHCI_PTR_TERM;
2002 ptd->status |= TD_CTRL_IOC;
2003 if (bytes_to_transfer < max_packet_size && (pid == USB_PID_IN))
2004 {
2005 //ptd->status |= TD_CTRL_SPD;
2006 }
2007 }
2008
2009 pthis = pnext;
2010 toggle ^= 1;
2011 if (pthis)
2012 ListNext(&td_list, pthis, pnext);
2013
2014 }
2015
2016 ListFirst(&td_list, pthis);
2017 RemoveEntryList(&td_list);
2018
2019 lock_qh_pool(&uhci->qh_pool, TRUE);
2020 pqh = alloc_qh(&uhci->qh_pool);
2021 unlock_qh_pool(&uhci->qh_pool, TRUE);
2022
2023 if (pqh == NULL)
2024 {
2025 lock_td_pool(&uhci->td_pool, TRUE);
2026
2027 if (pthis)
2028 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2029
2030 unlock_td_pool(&uhci->td_pool, TRUE);
2031 return STATUS_NO_MORE_ENTRIES;
2032
2033 }
2034
2035 urb->td_count = td_count;
2036
2037 uhci_insert_tds_qh(pqh, ((PTD_EXTENSION) pthis)->ptd);
2038 uhci_insert_qh_urb(urb, pqh);
2039 urb->pendp->flags =
2040 (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
2041 usb_endp_busy_count_inc(urb->pendp);
2042 uhci_insert_urb_to_schedule(uhci, urb, ret);
2043
2044 if (ret == FALSE)
2045 {
2046 // undo all we have done
2047 RemoveEntryList(&pqh->pqhe->vert_link); //remove qh from td_chain
2048 RemoveEntryList(&urb->trasac_list);
2049
2050 lock_td_pool(&uhci->td_pool, TRUE);
2051 if (pthis)
2052 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2053 unlock_td_pool(&uhci->td_pool, TRUE);
2054
2055 lock_qh_pool(&uhci->qh_pool, TRUE);
2056 if (pqh)
2057 free_qh(&uhci->qh_pool, pqh);
2058 unlock_qh_pool(&uhci->qh_pool, TRUE);
2059
2060 InitializeListHead(&urb->trasac_list);
2061 usb_endp_busy_count_dec(urb->pendp);
2062 urb->pendp->flags =
2063 (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (old_toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
2064 return STATUS_UNSUCCESSFUL;
2065 }
2066 return STATUS_SUCCESS;
2067 }
2068
2069 NTSTATUS
2070 uhci_internal_submit_ctrl(PUHCI_DEV uhci, PURB urb)
2071 {
2072 LIST_ENTRY td_list, *pthis, *pnext;
2073 LONG i, td_count;
2074 LONG toggle;
2075 LONG max_packet_size, bytes_to_transfer, bytes_rest, start_idx;
2076 PUHCI_TD ptd;
2077 PUHCI_QH pqh;
2078 ULONG dev_addr;
2079 PUSB_DEV pdev;
2080 BOOLEAN ret;
2081
2082 if (uhci == NULL || urb == NULL)
2083 return STATUS_INVALID_PARAMETER;
2084
2085 toggle = 0;
2086 bytes_rest = urb->rest_bytes;
2087 bytes_to_transfer = urb->bytes_to_transfer;
2088 max_packet_size = endp_max_packet_size(urb->pendp);
2089 start_idx = urb->data_length - urb->rest_bytes;
2090 td_count = 2 + (urb->bytes_to_transfer + max_packet_size - 1) / max_packet_size;
2091
2092 lock_td_pool(&uhci->td_pool, TRUE);
2093
2094 if (can_transfer(&uhci->td_pool, td_count) == FALSE)
2095 {
2096 unlock_td_pool(&uhci->td_pool, TRUE);
2097 return STATUS_NO_MORE_ENTRIES;
2098 }
2099
2100 ptd = alloc_tds(&uhci->td_pool, td_count);
2101 unlock_td_pool(&uhci->td_pool, TRUE);
2102
2103 if (ptd == NULL)
2104 {
2105 return STATUS_UNSUCCESSFUL;
2106 }
2107
2108 InsertTailList(&ptd->ptde->vert_link, &td_list);
2109
2110 ListFirst(&td_list, pthis);
2111 ListNext(&td_list, pthis, pnext);
2112
2113 ptd = ((PTD_EXTENSION) pthis)->ptd;
2114
2115 pdev = dev_from_endp(urb->pendp);
2116 dev_addr = pdev->dev_addr;
2117
2118 if (dev_state(pdev) <= USB_DEV_STATE_RESET)
2119 dev_addr = 0;
2120
2121 usb_dbg_print(DBGLVL_MAXIMUM, ("uhci_internal_submit_ctrl(): dev_addr =0x%x\n", dev_addr));
2122
2123 RtlCopyMemory(uhci->io_buf, urb->setup_packet, 8);
2124
2125 if ((urb->setup_packet[0] & USB_DIR_IN) == 0) //out
2126 RtlCopyMemory(&uhci->io_buf[8], urb->data_buffer, bytes_to_transfer);
2127 else
2128 RtlZeroMemory(&uhci->io_buf[8], bytes_to_transfer);
2129
2130 uhci_fill_td(ptd,
2131 (3 << TD_CTRL_C_ERR_SHIFT) | (TD_CTRL_ACTIVE),
2132 (7 << 21) | (((ULONG) endp_num(urb->pendp)) << 15) | (dev_addr << 8) | (USB_PID_SETUP),
2133 //uhci->io_buf_logic_addr.LowPart);
2134 MmGetPhysicalAddress(urb->setup_packet).LowPart);
2135
2136 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
2137 pthis = pnext;
2138 ListNext(&td_list, pthis, pnext);
2139
2140 urb->pipe = ((max_packet_size - 1) << 21)
2141 | ((ULONG) endp_num(urb->pendp) << 15)
2142 | (dev_addr << 8) | (pdev->flags & USB_DEV_FLAG_LOW_SPEED) | USB_ENDPOINT_XFER_CONTROL;
2143
2144 for(i = 0, toggle = 1; ((i < td_count - 2) && pthis); i++, toggle ^= 1)
2145 {
2146 //construct tds for DATA packets of data stage.
2147 ptd = ((PTD_EXTENSION) pthis)->ptd;
2148 uhci_fill_td(ptd,
2149 (3 << TD_CTRL_C_ERR_SHIFT)
2150 | (TD_CTRL_ACTIVE),
2151 ((bytes_to_transfer >
2152 max_packet_size ? max_packet_size - 1 : bytes_to_transfer -
2153 1) << 21) | (toggle << 19) | (((ULONG) endp_num(urb->
2154 pendp)) << 15) | (dev_addr << 8) |
2155 ((urb->setup_packet[0] & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT),
2156 //uhci->io_buf_logic_addr.LowPart + 8 + i * max_packet_size );
2157 MmGetPhysicalAddress(&urb->data_buffer[start_idx + i * max_packet_size]).LowPart);
2158
2159 if (pnext)
2160 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
2161
2162 if (i < td_count - 3)
2163 {
2164 bytes_to_transfer -= max_packet_size;
2165 }
2166 else
2167 {
2168 if (bytes_to_transfer > 0)
2169 {
2170 if (bytes_to_transfer < max_packet_size && (urb->setup_packet[0] & USB_DIR_IN))
2171 ptd->status |= TD_CTRL_SPD;
2172 }
2173 }
2174 pthis = pnext;
2175
2176 if (pthis)
2177 ListNext(&td_list, pthis, pnext);
2178 }
2179
2180 if (pnext)
2181 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
2182
2183 ListFirstPrev(&td_list, pthis);
2184 ptd = ((PTD_EXTENSION) pthis)->ptd;
2185
2186 //the last is an IN transaction
2187 uhci_fill_td(ptd,
2188 (3 << TD_CTRL_C_ERR_SHIFT)
2189 | (TD_CTRL_ACTIVE | TD_CTRL_IOC),
2190 (UHCI_NULL_DATA_SIZE << 21)
2191 | (1 << 19)
2192 | (((ULONG) endp_num(urb->pendp)) << 15)
2193 | (dev_addr << 8)
2194 | ((td_count > 2)
2195 ? ((urb->setup_packet[0] & USB_DIR_IN) ? USB_PID_OUT : USB_PID_IN) : USB_PID_IN), 0);
2196
2197 ptd->link = UHCI_PTR_TERM;
2198
2199 ListFirst(&td_list, pthis);
2200 RemoveEntryList(&td_list);
2201
2202 lock_qh_pool(&uhci->qh_pool, TRUE);
2203 pqh = alloc_qh(&uhci->qh_pool);
2204 unlock_qh_pool(&uhci->qh_pool, TRUE);
2205
2206 if (pqh == NULL)
2207 {
2208 lock_td_pool(&uhci->td_pool, TRUE);
2209 if (pthis)
2210 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2211 unlock_td_pool(&uhci->td_pool, TRUE);
2212
2213 return STATUS_NO_MORE_ENTRIES;
2214 }
2215
2216 urb->td_count = td_count;
2217
2218 uhci_insert_tds_qh(pqh, ((PTD_EXTENSION) pthis)->ptd);
2219 uhci_insert_qh_urb(urb, pqh);
2220
2221 usb_endp_busy_count_inc(urb->pendp);
2222 uhci_insert_urb_to_schedule(uhci, urb, ret);
2223 if (ret == FALSE)
2224 {
2225 RemoveEntryList(&pqh->pqhe->vert_link);
2226 RemoveEntryList(&urb->trasac_list);
2227
2228 lock_td_pool(&uhci->td_pool, TRUE);
2229 if (pthis)
2230 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2231 unlock_td_pool(&uhci->td_pool, TRUE);
2232
2233 lock_qh_pool(&uhci->qh_pool, TRUE);
2234 if (pqh)
2235 free_qh(&uhci->qh_pool, pqh);
2236 unlock_qh_pool(&uhci->qh_pool, TRUE);
2237
2238 InitializeListHead(&urb->trasac_list);
2239 usb_endp_busy_count_dec(urb->pendp);
2240 return STATUS_UNSUCCESSFUL;
2241 }
2242
2243 return STATUS_SUCCESS;
2244 }
2245
2246 NTSTATUS
2247 uhci_internal_submit_int(PUHCI_DEV uhci, PURB urb)
2248 {
2249 LONG i;
2250 LONG toggle = 0;
2251 LONG max_packet_size;
2252 PUHCI_TD ptd;
2253 BOOLEAN ret;
2254
2255 if (uhci == NULL || urb == NULL)
2256 {
2257 uhci_dbg_print(DBGLVL_MEDIUM,
2258 ("uhci_internal_submit_int(): uhci=0x%x, urb=0x%x "
2259 "returning STATUS_INVALID_PARAMETER!\n", uhci, urb));
2260 return STATUS_INVALID_PARAMETER;
2261 }
2262
2263 toggle = (urb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE) ? TRUE : FALSE;
2264 max_packet_size = endp_max_packet_size(urb->pendp);
2265
2266 if (max_packet_size < urb->data_length || max_packet_size == 0 || max_packet_size > 64)
2267 {
2268 uhci_dbg_print(DBGLVL_MEDIUM,
2269 ("uhci_internal_submit_int(): max_packet_size=%d, urb->data_length=%d "
2270 "returning STATUS_INVALID_PARAMETER!\n", max_packet_size, urb->data_length));
2271 return STATUS_INVALID_PARAMETER;
2272 }
2273
2274 lock_td_pool(&uhci->td_pool, TRUE);
2275 ptd = alloc_td(&uhci->td_pool);
2276 unlock_td_pool(&uhci->td_pool, TRUE);
2277
2278 if (ptd == NULL)
2279 return STATUS_NO_MORE_ENTRIES;
2280
2281 for(i = 1; i <= 7; i++)
2282 {
2283 if (((ULONG) max_packet_size) >> i)
2284 continue;
2285 else
2286 break;
2287 }
2288
2289 i--;
2290 i &= 7;
2291
2292 urb->pipe = (((ULONG) urb->pendp->pusb_endp_desc->bInterval) << 24)
2293 | (i << 21)
2294 | (toggle << 19)
2295 | ((ULONG) endp_num(urb->pendp) << 15)
2296 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr) << 8)
2297 | USB_DIR_IN | (dev_from_endp(urb->pendp)->flags & USB_DEV_FLAG_LOW_SPEED) | USB_ENDPOINT_XFER_INT;
2298
2299 uhci_fill_td(ptd,
2300 (3 << TD_CTRL_C_ERR_SHIFT)
2301 | (TD_CTRL_ACTIVE)
2302 | ((urb->data_length < max_packet_size ? TD_CTRL_SPD : 0))
2303 | (TD_CTRL_IOC),
2304 (((ULONG) max_packet_size - 1) << 21)
2305 | (toggle << 19)
2306 | ((ULONG) endp_num(urb->pendp) << 15)
2307 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr & 0x7f) << 8)
2308 | USB_PID_IN, MmGetPhysicalAddress(urb->data_buffer).LowPart);
2309
2310 toggle ^= 1;
2311 urb->td_count = 1;
2312
2313 InitializeListHead(&urb->trasac_list);
2314 InsertTailList(&urb->trasac_list, &ptd->ptde->vert_link);
2315
2316 //indirectly guarded by pending_endp_list_lock
2317 if (uhci_claim_bandwidth(uhci, urb, TRUE) == FALSE)
2318 {
2319 InitializeListHead(&urb->trasac_list);
2320
2321 lock_td_pool(&uhci->td_pool, TRUE);
2322 free_td(&uhci->td_pool, ptd);
2323 unlock_td_pool(&uhci->td_pool, TRUE);
2324
2325 return STATUS_NO_MORE_ENTRIES;
2326 }
2327
2328 urb->pendp->flags = (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle << 31);
2329 usb_endp_busy_count_inc(urb->pendp);
2330
2331 uhci_insert_urb_to_schedule(uhci, urb, ret);
2332
2333 if (ret == FALSE)
2334 {
2335 lock_td_pool(&uhci->td_pool, TRUE);
2336 if (ptd)
2337 free_td(&uhci->td_pool, ptd);
2338 unlock_td_pool(&uhci->td_pool, TRUE);
2339
2340 InitializeListHead(&urb->trasac_list);
2341 usb_endp_busy_count_dec(urb->pendp);
2342 urb->pendp->flags = (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | ((toggle ^ 1) << 31);
2343 uhci_claim_bandwidth(uhci, urb, FALSE);
2344 return STATUS_UNSUCCESSFUL;
2345 }
2346
2347 return STATUS_SUCCESS;
2348 }
2349
2350
2351 NTSTATUS
2352 uhci_internal_submit_iso(PUHCI_DEV uhci, PURB urb)
2353 {
2354 PUHCI_TD ptd;
2355 LIST_ENTRY td_list, *pthis, *pnext;
2356 int i;
2357 BOOLEAN toggle = FALSE, ret;
2358
2359 if (uhci == NULL || urb == NULL)
2360 return STATUS_INVALID_PARAMETER;
2361
2362 if (urb->iso_frame_count == 0)
2363 return STATUS_INVALID_PARAMETER;
2364
2365 lock_td_pool(&uhci->td_pool, TRUE);
2366
2367 if (can_transfer(&uhci->td_pool, urb->iso_frame_count) == FALSE)
2368 {
2369 unlock_td_pool(&uhci->td_pool, TRUE);
2370 return STATUS_NO_MORE_ENTRIES;
2371 }
2372
2373 ptd = alloc_tds(&uhci->td_pool, urb->iso_frame_count);
2374 unlock_td_pool(&uhci->td_pool, TRUE);
2375
2376 if (ptd == NULL)
2377 {
2378 return STATUS_UNSUCCESSFUL;
2379 }
2380
2381 InsertTailList(&ptd->ptde->vert_link, &td_list);
2382 ListFirst(&td_list, pthis);
2383
2384 urb->td_count = urb->iso_frame_count;
2385
2386 urb->pipe = (((ULONG) urb->iso_packet_desc[0].length) << 21)
2387 | ((ULONG) endp_num(urb->pendp) << 15)
2388 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr) << 8)
2389 | ((ULONG) endp_dir(urb->pendp)) | USB_ENDPOINT_XFER_ISOC;
2390
2391
2392 for(i = 0; i < urb->iso_frame_count && pthis; i++)
2393 {
2394 ptd = ((PTD_EXTENSION) pthis)->ptd;
2395 uhci_fill_td(ptd,
2396 (3 << TD_CTRL_C_ERR_SHIFT)
2397 | (TD_CTRL_ACTIVE)
2398 | (TD_CTRL_IOS),
2399 (((ULONG) urb->iso_packet_desc[i].length - 1) << 21)
2400 | (0 << 19)
2401 | ((ULONG) endp_num(urb->pendp) << 15)
2402 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr) << 8)
2403 | ((urb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN)
2404 ? USB_PID_OUT : USB_PID_IN),
2405 MmGetPhysicalAddress(&urb->data_buffer[urb->iso_packet_desc[i].offset]).LowPart);
2406
2407 toggle ^= 1;
2408 ListNext(&td_list, pthis, pnext);
2409 pthis = pnext;
2410 }
2411
2412 ptd->status |= TD_CTRL_IOC; //need interrupt
2413
2414 ListFirst(&td_list, pthis);
2415 RemoveEntryList(&td_list);
2416
2417 InsertTailList(pthis, &urb->trasac_list);
2418
2419 //indirectly guarded by pending_endp_list_lock
2420 if (uhci_claim_bandwidth(uhci, urb, TRUE) == FALSE)
2421 {
2422 //bad news: we can not allocate the enough bandwidth for the urb
2423 RemoveEntryList(&urb->trasac_list);
2424 InitializeListHead(&urb->trasac_list);
2425
2426 lock_td_pool(&uhci->td_pool, TRUE);
2427 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2428 unlock_td_pool(&uhci->td_pool, TRUE);
2429 return STATUS_NO_MORE_ENTRIES;
2430
2431 }
2432
2433 usb_endp_busy_count_inc(urb->pendp);
2434 uhci_insert_urb_to_schedule(uhci, urb, ret);
2435 if (ret == FALSE)
2436 {
2437 usb_endp_busy_count_dec(urb->pendp);
2438 RemoveEntryList(&urb->trasac_list);
2439
2440 lock_td_pool(&uhci->td_pool, TRUE);
2441 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2442 unlock_td_pool(&uhci->td_pool, TRUE);
2443 uhci_claim_bandwidth(uhci, urb, FALSE);
2444 return STATUS_UNSUCCESSFUL;
2445 }
2446
2447 return STATUS_SUCCESS;
2448 }
2449
2450 // runs in uhci_isr
2451 BOOLEAN
2452 uhci_is_xfer_finished(PURB urb)
2453 {
2454 PLIST_ENTRY pthis, pnext;
2455 PUHCI_TD ptd;
2456 BOOLEAN ret = TRUE;
2457 PTD_EXTENSION ptde;
2458
2459 if (urb->last_finished_td == NULL)
2460 {
2461 urb->last_finished_td = &urb->trasac_list;
2462 }
2463
2464 if (&urb->trasac_list == urb->last_finished_td)
2465 ListFirst(&urb->trasac_list, pthis)
2466 else
2467 ListNext(&urb->trasac_list, urb->last_finished_td, pthis);
2468
2469 while (pthis)
2470 {
2471 if ((((PTD_EXTENSION) pthis)->flags & UHCI_ITEM_FLAG_TYPE) != UHCI_ITEM_FLAG_TD)
2472 {
2473 ListNext(&urb->trasac_list, pthis, pnext);
2474 pthis = pnext;
2475 continue;
2476 }
2477 else
2478 {
2479 ptde = (PTD_EXTENSION) pthis;
2480 ptd = ptde->ptd;
2481 ASSERT(ptd != NULL);
2482
2483 if (ptd->status & TD_CTRL_ACTIVE)
2484 {
2485 //still active
2486 ret = FALSE;
2487 break;
2488 }
2489 //let's see whether error occured
2490 if ((ptd->status & TD_CTRL_ANY_ERROR) == 0)
2491 {
2492 urb->last_finished_td = pthis;
2493 ListNext(&urb->trasac_list, pthis, pnext);
2494 pthis = pnext;
2495 continue;
2496 }
2497 else
2498 {
2499 urb->status = ptd->status;
2500 pthis = NULL;
2501 continue;
2502 }
2503 }
2504
2505 }
2506
2507 if (pthis == NULL)
2508 ret = TRUE;
2509
2510 return ret;
2511 }
2512
2513 // executed in isr, and have frame_list_lock acquired, so
2514 // never try to acquire any spin-lock
2515 // remove the bulk urb from schedule, and mark it not in
2516 // the schedule
2517 BOOLEAN
2518 uhci_remove_urb_from_schedule(PUHCI_DEV uhci, PURB urb)
2519 {
2520 BOOLEAN ret = FALSE;
2521 {
2522 switch (urb->pipe & USB_ENDPOINT_XFERTYPE_MASK)
2523 {
2524 case USB_ENDPOINT_XFER_BULK:
2525 {
2526 ret = uhci_remove_bulk_from_schedule(uhci, urb);
2527 break;
2528 }
2529 case USB_ENDPOINT_XFER_CONTROL:
2530 {
2531 ret = uhci_remove_ctrl_from_schedule(uhci, urb);
2532 break;
2533 }
2534 case USB_ENDPOINT_XFER_INT:
2535 {
2536 ret = uhci_remove_int_from_schedule(uhci, urb);
2537 break;
2538 }
2539 case USB_ENDPOINT_XFER_ISOC:
2540 {
2541 ret = uhci_remove_iso_from_schedule(uhci, urb);
2542 break;
2543 }
2544 }
2545 }
2546 return ret;
2547 }
2548
2549 // executed in isr, and have frame_list_lock acquired, so
2550 // never try to acquire any spin-lock
2551 // remove the bulk urb from schedule, and mark it not in
2552 // the schedule
2553 BOOLEAN
2554 uhci_remove_bulk_from_schedule(PUHCI_DEV uhci, PURB urb)
2555 {
2556
2557 PUHCI_QH pqh, pnext_qh, pprev_qh;
2558 PLIST_ENTRY pthis, pnext, pprev;
2559 LONG i;
2560
2561 if (uhci == NULL || urb == NULL)
2562 return FALSE;
2563
2564 ListFirst(&urb->trasac_list, pthis);
2565 pqh = ((PQH_EXTENSION) pthis)->pqh;
2566
2567 ListFirst(&pqh->pqhe->hori_link, pnext);
2568 ListFirstPrev(&pqh->pqhe->hori_link, pprev);
2569
2570 if (pprev == NULL || pnext == NULL)
2571 return FALSE;
2572
2573 pnext_qh = struct_ptr(pnext, QH_EXTENSION, hori_link)->pqh;
2574 pprev_qh = struct_ptr(pprev, QH_EXTENSION, hori_link)->pqh;
2575
2576 if (pprev != pnext)
2577 {
2578 //not the last one
2579 pprev_qh->link = pnext_qh->phy_addr;
2580 }
2581 else
2582 {
2583 //only two qhs in the list
2584 for(i = 0; i < UHCI_MAX_SKELQHS; i++)
2585 {
2586 if (pprev_qh == uhci->skel_qh[i])
2587 {
2588 break;
2589 }
2590 }
2591 ASSERT(i < UHCI_MAX_SKELQHS - 1);
2592 pprev_qh->link = uhci->skel_qh[i + 1]->phy_addr;
2593 }
2594 RemoveEntryList(&pqh->pqhe->hori_link);
2595
2596 urb->flags &= ~URB_FLAG_IN_SCHEDULE;
2597
2598 if ((urb->pipe & USB_DEV_FLAG_LOW_SPEED) == 0)
2599 uhci_drop_fsbr(uhci);
2600
2601 return TRUE;
2602 }
2603
2604 BOOLEAN
2605 uhci_remove_iso_from_schedule(PUHCI_DEV uhci, PURB urb)
2606 {
2607 PUHCI_TD ptd, pprev_td;
2608 PLIST_ENTRY pthis, pnext, pprev;
2609 int i, idx;
2610
2611 if (uhci == NULL || urb == NULL)
2612 return FALSE;
2613
2614 ListFirst(&urb->trasac_list, pthis);
2615
2616 for(i = 0; i < urb->iso_frame_count && pthis; i++)
2617 {
2618 ptd = ((PTD_EXTENSION) pthis)->ptd;
2619 idx = (urb->iso_start_frame + i) & (UHCI_MAX_FRAMES - 1);
2620
2621 ListFirstPrev(&ptd->ptde->hori_link, pprev);
2622
2623 if (pprev == NULL)
2624 return FALSE;
2625
2626 if (pprev == &uhci->frame_list_cpu[idx].td_link)
2627 {
2628 uhci->frame_list[idx] = ptd->link;
2629 }
2630 else
2631 {
2632 pprev_td = struct_ptr(pprev, TD_EXTENSION, hori_link)->ptd;
2633 pprev_td->link = ptd->link;
2634 }
2635
2636 RemoveEntryList(&ptd->ptde->hori_link);
2637 ListNext(&urb->trasac_list, pthis, pnext);
2638 pthis = pnext;
2639 }
2640
2641 urb->flags &= ~URB_FLAG_IN_SCHEDULE;
2642 return TRUE;
2643 }
2644
2645 BOOLEAN
2646 uhci_remove_int_from_schedule(PUHCI_DEV uhci, PURB urb)
2647 {
2648 PUHCI_TD ptd, pnext_td, pprev_td;
2649 PLIST_ENTRY pthis, pnext, pprev;
2650 LONG i;
2651
2652 if (uhci == NULL || urb == NULL)
2653 return FALSE;
2654
2655 ListFirst(&urb->trasac_list, pthis);
2656 ptd = ((PTD_EXTENSION) pthis)->ptd;
2657 ListFirst(&ptd->ptde->hori_link, pnext);
2658 ListFirstPrev(&ptd->ptde->hori_link, pprev);
2659
2660 if (pprev == NULL || pnext == NULL)
2661 return FALSE;
2662
2663 pnext_td = struct_ptr(pnext, TD_EXTENSION, hori_link)->ptd;
2664 pprev_td = struct_ptr(pprev, TD_EXTENSION, hori_link)->ptd;
2665
2666 if (pprev_td != pnext_td)
2667 pprev_td->link = pnext_td->phy_addr;
2668 else
2669 {
2670 //the last one
2671 for(i = UHCI_MAX_SKELTDS - 2; i >= 0; i--)
2672 {
2673 //UHCI_MAX_SKELTDS -1 skel tds for int transfer
2674 if (pprev_td == uhci->skel_td[i])
2675 break;
2676 }
2677
2678 ASSERT(i >= 0);
2679 if (i == 0)
2680 {
2681 pprev_td->link = uhci->skel_qh[0]->phy_addr;
2682 }
2683 else
2684 {
2685 pprev_td->link = uhci->skel_td[i - 1]->phy_addr;
2686 }
2687 }
2688 RemoveEntryList(&ptd->ptde->hori_link);
2689
2690 urb->flags &= ~URB_FLAG_IN_SCHEDULE;
2691 return TRUE;
2692 }
2693
2694 BOOLEAN
2695 uhci_insert_tds_qh(PUHCI_QH pqh, PUHCI_TD td_chain)
2696 {
2697 if (pqh == NULL || td_chain == NULL)
2698 return FALSE;
2699
2700 InsertTailList(&td_chain->ptde->vert_link, &pqh->pqhe->vert_link);
2701 pqh->element = td_chain->phy_addr;
2702 return TRUE;
2703 }
2704
2705 BOOLEAN
2706 uhci_insert_qh_urb(PURB urb, PUHCI_QH qh_chain)
2707 {
2708 if (urb == NULL || qh_chain == NULL)
2709 return FALSE;
2710
2711 InsertTailList(&qh_chain->pqhe->vert_link, &urb->trasac_list);
2712 qh_chain->pqhe->purb = urb;
2713 return TRUE;
2714 }
2715
2716 // must have dev_lock and frame_list_lock acquired
2717 BOOLEAN
2718 uhci_insert_urb_schedule(PUHCI_DEV uhci, PURB urb)
2719 {
2720 PUHCI_QH pqh, pskel_qh, pnext_qh;
2721 PUHCI_TD ptd, plast_td;
2722 PLIST_ENTRY pthis, pnext;
2723 int i;
2724
2725 if (uhci == NULL || urb == NULL)
2726 return FALSE;
2727
2728 ListFirst(&urb->trasac_list, pthis);
2729 if (pthis == NULL)
2730 return FALSE;
2731
2732 InsertTailList(&uhci->urb_list, &urb->urb_link);
2733
2734 urb->flags &= ~URB_FLAG_STATE_MASK;
2735 urb->flags |= URB_FLAG_STATE_IN_PROCESS | URB_FLAG_IN_SCHEDULE;
2736
2737
2738 switch (endp_type(urb->pendp))
2739 {
2740 case USB_ENDPOINT_XFER_CONTROL:
2741 {
2742 pqh = ((PQH_EXTENSION) pthis)->pqh;
2743
2744 if ((dev_from_endp(urb->pendp)->flags & USB_DEV_FLAG_LOW_SPEED) == 0)
2745 {
2746 pskel_qh = uhci->skel_hs_control_qh;
2747 pnext_qh = uhci->skel_bulk_qh;
2748 }
2749 else
2750 {
2751 pskel_qh = uhci->skel_ls_control_qh;
2752 pnext_qh = uhci->skel_hs_control_qh;
2753 }
2754
2755 ListFirstPrev(&pskel_qh->pqhe->hori_link, pthis);
2756
2757 if (pthis == NULL)
2758 pthis = &pskel_qh->pqhe->hori_link;
2759
2760 InsertTailList(&pskel_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
2761 pqh->link = pnext_qh->phy_addr;
2762 struct_ptr(pthis, QH_EXTENSION, hori_link)->pqh->link = pqh->phy_addr;
2763
2764 //full speed band reclaimation
2765 if ((urb->pipe & USB_DEV_FLAG_LOW_SPEED) == 0)
2766 {
2767 uhci->fsbr_cnt++;
2768 if (uhci->fsbr_cnt == 1)
2769 {
2770 uhci->skel_term_qh->link = uhci->skel_hs_control_qh->phy_addr;
2771 }
2772 }
2773 return TRUE;
2774 }
2775 case USB_ENDPOINT_XFER_BULK:
2776 {
2777 pqh = ((PQH_EXTENSION) pthis)->pqh;
2778
2779 ListFirstPrev(&uhci->skel_bulk_qh->pqhe->hori_link, pthis);
2780
2781 if (pthis == NULL)
2782 pthis = &uhci->skel_bulk_qh->pqhe->hori_link;
2783
2784 InsertTailList(&uhci->skel_bulk_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
2785
2786 pqh->link = uhci->skel_term_qh->phy_addr;
2787 struct_ptr(pthis, QH_EXTENSION, hori_link)->pqh->link = pqh->phy_addr;
2788
2789 //full speed band reclaimation
2790 uhci->fsbr_cnt++;
2791 if (uhci->fsbr_cnt == 1)
2792 {
2793 uhci->skel_term_qh->link = uhci->skel_hs_control_qh->phy_addr;
2794 }
2795
2796 return TRUE;
2797 }
2798 case USB_ENDPOINT_XFER_INT:
2799 {
2800 //bandwidth claim is done outside
2801 ptd = ((PTD_EXTENSION) pthis)->ptd;
2802
2803 get_int_idx(urb, i);
2804
2805 ListFirstPrev(&uhci->skel_td[i]->ptde->hori_link, pthis);
2806 if (pthis == NULL)
2807 pthis = &uhci->skel_td[i]->ptde->hori_link;
2808
2809 InsertTailList(&uhci->skel_td[i]->ptde->hori_link, &ptd->ptde->hori_link);
2810
2811 if (i > 0)
2812 {
2813 ptd->link = uhci->skel_td[i - 1]->phy_addr;
2814 }
2815 else if (i == 0)
2816 {
2817 ptd->link = uhci->skel_qh[0]->phy_addr;
2818 }
2819 //finally link the previous td to this td
2820 struct_ptr(pthis, TD_EXTENSION, hori_link)->ptd->link = ptd->phy_addr;
2821 return TRUE;
2822 }
2823 case USB_ENDPOINT_XFER_ISOC:
2824 {
2825
2826 for(i = 0; i < urb->iso_frame_count; i++)
2827 {
2828 ptd = ((PTD_EXTENSION) pthis)->ptd;
2829 InsertTailList(&uhci->frame_list_cpu[(urb->iso_start_frame + i) & 0x3ff].td_link,
2830 &ptd->ptde->hori_link);
2831
2832 if (IsListEmpty(&uhci->frame_list_cpu[(urb->iso_start_frame + i) & 0x3ff].td_link) == TRUE)
2833 {
2834 ptd->link = uhci->frame_list[(urb->iso_start_frame + i) & 0x3ff];
2835 uhci->frame_list[i] = ptd->phy_addr;
2836 }
2837 else
2838 {
2839 ListFirstPrev(&uhci->frame_list_cpu[(urb->iso_start_frame + i) & 0x3ff].td_link, pnext);
2840 plast_td = struct_ptr(pnext, TD_EXTENSION, hori_link)->ptd;
2841 ptd->link = plast_td->link;
2842 plast_td->link = ptd->phy_addr;
2843 }
2844
2845 ListNext(&urb->trasac_list, pthis, pnext);
2846 pthis = pnext;
2847 }
2848 return TRUE;
2849
2850 }
2851 }
2852 return FALSE;
2853 }
2854
2855 //this function used as the KeSynchronizeExecution param to delegate control to uhci_insert_urb_schedule
2856 BOOLEAN NTAPI
2857 uhci_sync_insert_urb_schedule(PVOID context)
2858 {
2859 PSYNC_PARAM sync_param;
2860 PUHCI_DEV uhci;
2861 PURB purb;
2862
2863 sync_param = (PSYNC_PARAM) context;
2864 if (sync_param == NULL)
2865 return FALSE;
2866
2867 uhci = sync_param->uhci;
2868 purb = (PURB) sync_param->context;
2869
2870 if (uhci == NULL || purb == NULL)
2871 return (UCHAR) (sync_param->ret = FALSE);
2872
2873 return (UCHAR) (sync_param->ret = uhci_insert_urb_schedule(uhci, purb));
2874 }
2875
2876 // be sure pending_endp_list_lock acquired
2877 BOOLEAN
2878 uhci_claim_bandwidth(PUHCI_DEV uhci,
2879 PURB urb,
2880 BOOLEAN claim_bw //true to claim bandwidth, false to free bandwidth
2881 )
2882 {
2883
2884 UCHAR type;
2885 BOOLEAN ls, can_alloc;
2886 LONG bus_time, us;
2887 LONG i, idx, j, start_frame, interval;
2888
2889 if (urb == NULL)
2890 return FALSE;
2891
2892 can_alloc = TRUE;
2893
2894 type = (UCHAR) (urb->pipe & USB_ENDPOINT_XFERTYPE_MASK);
2895 if (type == USB_ENDPOINT_XFER_BULK || type == USB_ENDPOINT_XFER_CONTROL)
2896 {
2897 return FALSE;
2898 }
2899
2900 ls = (urb->pipe & USB_DEV_FLAG_LOW_SPEED) ? TRUE : FALSE;
2901
2902 if (type == USB_ENDPOINT_XFER_INT)
2903 {
2904 start_frame = 0;
2905 i = urb->data_length;
2906 bus_time = usb_calc_bus_time(ls, FALSE, FALSE, i);
2907 us = ns_to_us(bus_time);
2908
2909 i = (urb->pipe >> 24); //polling interval
2910
2911 for(interval = 0, j = 0; j < 8; j++)
2912 {
2913 if (i & (1 << j))
2914 {
2915 interval = j;
2916 }
2917 }
2918
2919 interval = 1 << interval;
2920 start_frame = interval - 1;
2921
2922 if (claim_bw)
2923 {
2924
2925 for(idx = 0; idx < UHCI_MAX_FRAMES; idx += interval)
2926 {
2927 if (uhci->frame_bw[idx] < us)
2928 {
2929 can_alloc = FALSE;
2930 break;
2931 }
2932 }
2933
2934 if (!can_alloc)
2935 {
2936 return FALSE;
2937 }
2938
2939 for(idx = start_frame; idx < UHCI_MAX_FRAMES; idx += interval)
2940 {
2941 uhci->frame_bw[idx] -= us;
2942 }
2943 }
2944 else
2945 {
2946 for(idx = start_frame; idx < UHCI_MAX_FRAMES; idx += interval)
2947 {
2948 uhci->frame_bw[idx] += us;
2949 }
2950 }
2951
2952 }
2953 else if (type == USB_ENDPOINT_XFER_ISOC)
2954 {
2955 if (claim_bw)
2956 {
2957 for(i = 0; i < urb->iso_frame_count; i++)
2958 {
2959 bus_time = usb_calc_bus_time(FALSE,
2960 (urb->pipe & USB_DIR_IN)
2961 ? TRUE : FALSE, TRUE, urb->iso_packet_desc[i].length);
2962
2963 urb->iso_packet_desc[i].bus_time = ns_to_us(bus_time);
2964 }
2965
2966 for(i = 0; i < urb->iso_frame_count; i++)
2967 {
2968 if (uhci->frame_bw[(urb->iso_start_frame + i) & 0x3ff] < urb->iso_packet_desc[i].bus_time)
2969 {
2970 can_alloc = FALSE;
2971 break;
2972 }
2973 }
2974
2975 if (!can_alloc)
2976 {
2977 return FALSE;
2978 }
2979
2980 for(i = 0; i < urb->iso_frame_count; i++)
2981 {
2982 uhci->frame_bw[(urb->iso_start_frame + i) & 0x3ff] -= urb->iso_packet_desc[i].bus_time;
2983 }
2984 }
2985 else
2986 {
2987 for(i = 0; i < urb->iso_frame_count; i++)
2988 {
2989 uhci->frame_bw[(urb->iso_start_frame + i) & 0x3ff] += urb->iso_packet_desc[i].bus_time;
2990 }
2991 }
2992
2993 }
2994
2995 return TRUE;
2996 }
2997
2998
2999 //cancel a single urb
3000 BOOLEAN NTAPI
3001 uhci_sync_cancel_urb(PVOID context)
3002 {
3003 PUHCI_DEV uhci;
3004 PSYNC_PARAM sync_param;
3005 PURB purb2, dest_urb;
3006 PLIST_ENTRY pthis, pnext;
3007 BOOLEAN found = FALSE;
3008
3009 if (context == NULL)
3010 return FALSE;
3011
3012 sync_param = (PSYNC_PARAM) context;
3013 uhci = sync_param->uhci;
3014 dest_urb = (PURB) sync_param->context;
3015
3016 if (uhci == NULL || dest_urb == NULL)
3017 return (UCHAR) (sync_param->ret = FALSE);
3018
3019 ListFirst(&uhci->urb_list, pthis);
3020 while (pthis)
3021 {
3022 purb2 = (PURB) pthis;
3023 if (purb2 == dest_urb)
3024 {
3025 found = TRUE;
3026 purb2->flags |= URB_FLAG_FORCE_CANCEL;
3027 break;
3028 }
3029 ListNext(&uhci->urb_list, pthis, pnext);
3030 pthis = pnext;
3031 }
3032 if (found)
3033 uhci->skel_term_td->status |= TD_CTRL_IOC;
3034
3035 return (UCHAR) (sync_param->ret = found);
3036 }
3037
3038 //note any fields of the purb can not be referenced unless it is found in some queue
3039 NTSTATUS
3040 uhci_cancel_urb(PUHCI_DEV uhci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
3041 {
3042 PLIST_ENTRY pthis, pnext;
3043 BOOLEAN found;
3044 PURB purb2;
3045
3046 SYNC_PARAM sync_param;
3047
3048 USE_BASIC_NON_PENDING_IRQL;
3049
3050 if (uhci == NULL || purb == NULL || pdev == NULL || pendp == NULL)
3051 return STATUS_INVALID_PARAMETER;
3052
3053 lock_dev(pdev, FALSE);
3054
3055 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
3056 {
3057 unlock_dev(pdev, FALSE);
3058 //delegate to remove device for this job
3059 return STATUS_DEVICE_DOES_NOT_EXIST;
3060 }
3061
3062 if (dev_from_endp(pendp) != pdev)
3063 {
3064 unlock_dev(pdev, FALSE);
3065 return STATUS_INVALID_PARAMETER;
3066 }
3067
3068 if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
3069 {
3070 //it will be canceled in uhci_process_pending_endp
3071 unlock_dev(pdev, FALSE);
3072 return USB_STATUS_ENDPOINT_HALTED;
3073 }
3074
3075 found = FALSE;
3076 ListFirst(&pendp->urb_list, pthis);
3077 while (pthis)
3078 {
3079 purb2 = (PURB) pthis;
3080 if (purb2 == purb)
3081 {
3082 found = TRUE;
3083 RemoveEntryList(pthis);
3084 InitializeListHead(pthis);
3085 break;
3086 }
3087 ListNext(&pendp->urb_list, pthis, pnext);
3088 pthis = pnext;
3089 }
3090 unlock_dev(pdev, FALSE);
3091
3092 if (found)
3093 {
3094 purb->status = STATUS_CANCELLED;
3095
3096 uhci_generic_urb_completion(purb, purb->context);
3097
3098 lock_dev(pdev, FALSE);
3099 pdev->ref_count--;
3100 unlock_dev(pdev, FALSE);
3101 return STATUS_SUCCESS;
3102 }
3103
3104 // search the urb in the urb-list and try to cancel
3105 sync_param.uhci = uhci;
3106 sync_param.context = purb;
3107
3108 KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_cancel_urb, &sync_param);
3109
3110 found = (BOOLEAN) sync_param.ret;
3111
3112 if (found)
3113 return USB_STATUS_CANCELING;
3114
3115 return STATUS_INVALID_PARAMETER;
3116 }
3117
3118 VOID
3119 uhci_generic_urb_completion(PURB purb, PVOID context)
3120 {
3121 PUSB_DEV pdev;
3122 USE_NON_PENDING_IRQL;
3123
3124 old_irql = KeGetCurrentIrql();
3125 if (old_irql > DISPATCH_LEVEL)
3126 TRAP();