[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 #define release_adapter( padapTER ) HalPutDmaAdapter(padapTER)
69
70
71 #define get_int_idx( _urb, _idx ) \
72 {\
73 UCHAR interVAL;\
74 interVAL = ( UCHAR )( ( _urb )->pipe >> 24 );\
75 for( _idx = 1; _idx < 9; _idx++ )\
76 {\
77 interVAL >>= 1;\
78 if( !interVAL )\
79 break;\
80 }\
81 _idx --;\
82 }
83
84 #define uhci_insert_urb_to_schedule( uHCI, pURB, rET ) \
85 {\
86 SYNC_PARAM sync_param;\
87 sync_param.uhci = uHCI;\
88 sync_param.context = pURB;\
89 \
90 rET = KeSynchronizeExecution( uHCI->pdev_ext->uhci_int, uhci_sync_insert_urb_schedule, &sync_param );\
91 }
92
93 //declarations
94 typedef struct
95 {
96 PUHCI_DEV uhci;
97 PVOID context;
98 ULONG ret;
99 } SYNC_PARAM, *PSYNC_PARAM;
100
101 PDEVICE_OBJECT
102 uhci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr);
103
104 BOOLEAN uhci_init_schedule(PUHCI_DEV uhci, PADAPTER_OBJECT padapter);
105
106 BOOLEAN uhci_release(PDEVICE_OBJECT pdev);
107
108 static VOID uhci_stop(PUHCI_DEV uhci);
109
110 BOOLEAN uhci_destroy_schedule(PUHCI_DEV uhci);
111
112 BOOLEAN NTAPI uhci_sync_insert_urb_schedule(PVOID context);
113
114 VOID uhci_init_hcd_interface(PUHCI_DEV uhci);
115
116 NTSTATUS uhci_rh_submit_urb(PUSB_DEV rh, PURB purb);
117
118 NTSTATUS uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
119
120 extern VOID rh_timer_svc_reset_port_completion(PUSB_DEV dev, PVOID context);
121
122 extern VOID rh_timer_svc_int_completion(PUSB_DEV dev, PVOID context);
123
124 ULONG debug_level = DBGLVL_MINIMUM;//DBGLVL_MAXIMUM;
125 PDRIVER_OBJECT usb_driver_obj = NULL;
126 extern USB_DEV_MANAGER g_dev_mgr;
127
128 //pending endpoint pool funcs
129 VOID
130 uhci_wait_ms(PUHCI_DEV uhci, LONG ms)
131 {
132 LARGE_INTEGER lms;
133 if (ms <= 0)
134 return;
135
136 lms.QuadPart = -10 * ms;
137 KeSetTimer(&uhci->reset_timer, lms, NULL);
138
139 KeWaitForSingleObject(&uhci->reset_timer, Executive, KernelMode, FALSE, NULL);
140
141 return;
142 }
143
144 BOOLEAN
145 init_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
146 {
147 int i;
148 if (pool == NULL)
149 return FALSE;
150
151 pool->pending_endp_array =
152 usb_alloc_mem(NonPagedPool, sizeof(UHCI_PENDING_ENDP) * UHCI_MAX_PENDING_ENDPS);
153 InitializeListHead(&pool->free_que);
154 pool->free_count = 0;
155 pool->total_count = UHCI_MAX_PENDING_ENDPS;
156 KeInitializeSpinLock(&pool->pool_lock);
157
158 for(i = 0; i < MAX_TIMER_SVCS; i++)
159 {
160 free_pending_endp(pool, &pool->pending_endp_array[i]);
161 }
162
163 return TRUE;
164
165 }
166
167 BOOLEAN
168 free_pending_endp(PUHCI_PENDING_ENDP_POOL pool, PUHCI_PENDING_ENDP pending_endp)
169 {
170 if (pool == NULL || pending_endp == NULL)
171 {
172 return FALSE;
173 }
174
175 RtlZeroMemory(pending_endp, sizeof(UHCI_PENDING_ENDP));
176 InsertTailList(&pool->free_que, &pending_endp->endp_link);
177 pool->free_count++;
178
179 return TRUE;
180 }
181
182 PUHCI_PENDING_ENDP
183 alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool, LONG count)
184 {
185 PUHCI_PENDING_ENDP new_endp;
186 if (pool == NULL || count != 1)
187 return NULL;
188
189 if (pool->free_count <= 0)
190 return NULL;
191
192 new_endp = (PUHCI_PENDING_ENDP) RemoveHeadList(&pool->free_que);
193 pool->free_count--;
194 return new_endp;
195 }
196
197 BOOLEAN
198 destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
199 {
200 if (pool == NULL)
201 return FALSE;
202
203 InitializeListHead(&pool->free_que);
204 pool->free_count = pool->total_count = 0;
205 usb_free_mem(pool->pending_endp_array);
206 pool->pending_endp_array = NULL;
207
208 return TRUE;
209
210 }
211
212
213 //end of pending endpoint pool funcs
214
215 static void
216 uhci_fill_td(PUHCI_TD td, ULONG status, ULONG info, ULONG buffer)
217 {
218 td->status = status;
219 td->info = info;
220 td->buffer = buffer;
221 }
222
223 BOOLEAN
224 uhci_insert_td_fl(PUHCI_TD prev_td, PUHCI_TD ptd)
225 {
226 PLIST_ENTRY temp_entry;
227
228 if (prev_td == NULL || ptd == NULL)
229 return FALSE;
230
231 temp_entry = &prev_td->ptde->hori_link;
232
233 ptd->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
234 prev_td->link = ptd->phy_addr;
235
236 InsertHeadList(&prev_td->ptde->hori_link, &ptd->ptde->hori_link);
237 return TRUE;
238 }
239
240 BOOLEAN
241 uhci_remove_td_fl(PUHCI_TD ptd)
242 {
243 PUHCI_TD prev_td;
244
245 if (ptd == NULL)
246 return FALSE;
247
248 prev_td = (struct_ptr(ptd->ptde->hori_link.Blink, TD_EXTENSION, hori_link))->ptd;
249 prev_td->link = ptd->link;
250 ptd->link = UHCI_PTR_TERM;
251
252 RemoveEntryList(&ptd->ptde->hori_link);
253
254 return FALSE;
255 }
256
257 BOOLEAN
258 uhci_insert_qh_fl(PVOID prev_item, PUHCI_QH pqh)
259 {
260 //only horizontal link allowed
261 PUHCI_QH pprev_qh;
262 PUHCI_TD pprev_td;
263 PLIST_ENTRY temp_entry;
264
265 if (prev_item == NULL || pqh == NULL)
266 return FALSE;
267
268 if ((((PUHCI_TD) prev_item)->ptde->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
269 {
270 pprev_qh = (PUHCI_QH) prev_item;
271 temp_entry = pprev_qh->pqhe->hori_link.Flink;
272 pqh->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
273 pprev_qh->link = pqh->phy_addr;
274
275 InsertHeadList(&pprev_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
276 }
277 else
278 {
279 pprev_td = ((PUHCI_TD) prev_item);
280
281 temp_entry = pprev_td->ptde->hori_link.Flink;
282 pprev_td->link = pqh->phy_addr;
283 pqh->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
284
285 InsertHeadList(&pprev_td->ptde->hori_link, &pqh->pqhe->hori_link);
286 }
287
288 return FALSE;
289 }
290
291 BOOLEAN
292 uhci_remove_qh_fl(PUHCI_QH pqh)
293 {
294 PVOID prev_item;
295 PUHCI_QH pprevqh;
296 PUHCI_TD pprevtd;
297
298 if (pqh == NULL)
299 return FALSE;
300
301 prev_item = (struct_ptr(pqh->pqhe->hori_link.Blink, TD_EXTENSION, hori_link))->ptd;
302
303 if ((((PUHCI_TD) prev_item)->ptde->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
304 {
305 pprevqh = (PUHCI_QH) prev_item;
306 pprevqh->link = pqh->link;
307 }
308 else
309 {
310 pprevtd = ((PUHCI_TD) prev_item);
311 pprevtd->link = pqh->link;
312 }
313
314 RemoveEntryList(&pqh->pqhe->hori_link);
315
316 pqh->link = UHCI_PTR_TERM;
317 pqh->pqhe->hori_link.Flink = pqh->pqhe->hori_link.Blink = NULL;
318
319 return TRUE;
320 }
321
322 BOOLEAN
323 uhci_init_frame_list(PUHCI_DEV uhci, PADAPTER_OBJECT padapter)
324 {
325 int i;
326 if (uhci == NULL || padapter == NULL)
327 return FALSE;
328
329 //note: frame_list_lock will be connected to interrupt
330 KeInitializeSpinLock(&uhci->frame_list_lock);
331
332 uhci->io_buf = HalAllocateCommonBuffer(padapter, 4096, &uhci->io_buf_logic_addr, FALSE);
333
334 if (uhci->io_buf == NULL)
335 return FALSE;
336
337 uhci->frame_list =
338 HalAllocateCommonBuffer(padapter,
339 sizeof(ULONG) * UHCI_MAX_FRAMES, &uhci->frame_list_logic_addr, FALSE);
340
341 if (uhci->frame_list == NULL)
342 return FALSE;
343
344 RtlZeroMemory(uhci->frame_list, sizeof(ULONG) * UHCI_MAX_FRAMES);
345
346 uhci->frame_list_cpu = usb_alloc_mem(NonPagedPool, sizeof(FRAME_LIST_CPU_ENTRY) * UHCI_MAX_FRAMES);
347
348 if (uhci->frame_list_cpu == NULL)
349 return FALSE;
350
351 for(i = 0; i < UHCI_MAX_FRAMES; i++)
352 InitializeListHead(&uhci->frame_list_cpu[i].td_link);
353
354 uhci->frame_bw = usb_alloc_mem(NonPagedPool, sizeof(LONG) * UHCI_MAX_FRAMES);
355
356 if (uhci->frame_bw == NULL)
357 return FALSE;
358
359 for(i = 0; i < UHCI_MAX_FRAMES; i++)
360 {
361 uhci->frame_bw[i] = FRAME_TIME_MAX_USECS_ALLOC;
362 }
363 uhci->fsbr_cnt = 0;
364
365 return TRUE;
366
367 }
368
369 BOOLEAN
370 uhci_destroy_frame_list(PUHCI_DEV uhci)
371 {
372 if (uhci == NULL)
373 return FALSE;
374
375 if (uhci->frame_list)
376 HalFreeCommonBuffer(uhci->pdev_ext->padapter,
377 sizeof(ULONG) * UHCI_MAX_FRAMES,
378 uhci->frame_list_logic_addr, uhci->frame_list, FALSE);
379
380 uhci->frame_list = NULL;
381 uhci->frame_list_logic_addr.LowPart = 0;
382 uhci->frame_list_logic_addr.HighPart = 0;
383
384 if (uhci->frame_list_cpu)
385 usb_free_mem(uhci->frame_list_cpu);
386
387 uhci->frame_list_cpu = NULL;
388
389 if (uhci->frame_bw)
390 usb_free_mem(uhci->frame_bw);
391
392 uhci->frame_bw = NULL;
393
394 return TRUE;
395 }
396
397 PDEVICE_OBJECT
398 uhci_create_device(PDRIVER_OBJECT drvr_obj, PUSB_DEV_MANAGER dev_mgr)
399 {
400 NTSTATUS status;
401 PDEVICE_OBJECT pdev;
402 PDEVICE_EXTENSION pdev_ext;
403
404 UNICODE_STRING dev_name;
405 UNICODE_STRING symb_name;
406
407 STRING string, another_string;
408 CHAR str_dev_name[64], str_symb_name[64];
409
410 if (drvr_obj == NULL)
411 return NULL;
412
413 ASSERT(dev_mgr != NULL);
414
415 //note: hcd count wont increment till the hcd is registered in dev_mgr
416 sprintf(str_dev_name, "%s%d", UHCI_DEVICE_NAME, dev_mgr->hcd_count);
417 sprintf(str_symb_name, "%s%d", DOS_DEVICE_NAME, dev_mgr->hcd_count);
418
419 RtlInitString(&string, str_dev_name);
420 RtlAnsiStringToUnicodeString(&dev_name, &string, TRUE);
421
422 pdev = NULL;
423 status = IoCreateDevice(drvr_obj,
424 sizeof(DEVICE_EXTENSION) + sizeof(UHCI_DEV),
425 &dev_name, FILE_UHCI_DEV_TYPE, 0, FALSE, &pdev);
426
427 if (status != STATUS_SUCCESS || pdev == NULL)
428 {
429 RtlFreeUnicodeString(&dev_name);
430 return NULL;
431 }
432
433 pdev_ext = pdev->DeviceExtension;
434 RtlZeroMemory(pdev_ext, sizeof(DEVICE_EXTENSION) + sizeof(UHCI_DEV));
435
436 pdev_ext->dev_ext_hdr.type = NTDEV_TYPE_HCD;
437 pdev_ext->dev_ext_hdr.dispatch = uhci_dispatch_irp;
438 pdev_ext->dev_ext_hdr.start_io = NULL; //we do not support startio
439 pdev_ext->dev_ext_hdr.dev_mgr = dev_mgr;
440
441 pdev_ext->pdev_obj = pdev;
442 pdev_ext->pdrvr_obj = drvr_obj;
443
444 pdev_ext->uhci = (PUHCI_DEV) & (pdev_ext[1]);
445
446 RtlInitString(&another_string, str_symb_name);
447 RtlAnsiStringToUnicodeString(&symb_name, &another_string, TRUE);
448
449 IoCreateSymbolicLink(&symb_name, &dev_name);
450
451 uhci_dbg_print(DBGLVL_MAXIMUM,
452 ("uhci_create_device(): dev=0x%x\n, pdev_ext= 0x%x, uhci=0x%x, dev_mgr=0x%x\n", pdev,
453 pdev_ext, pdev_ext->uhci, dev_mgr));
454
455 RtlFreeUnicodeString(&dev_name);
456 RtlFreeUnicodeString(&symb_name);
457
458 return pdev;
459 }
460
461 BOOLEAN
462 uhci_delete_device(PDEVICE_OBJECT pdev)
463 {
464 STRING string;
465 UNICODE_STRING symb_name;
466 PDEVICE_EXTENSION pdev_ext;
467 CHAR str_symb_name[64];
468
469
470 if (pdev == NULL)
471 return FALSE;
472
473 pdev_ext = pdev->DeviceExtension;
474
475 sprintf(str_symb_name,
476 "%s%d", DOS_DEVICE_NAME, pdev_ext->uhci->hcd_interf.hcd_get_id(&pdev_ext->uhci->hcd_interf));
477 RtlInitString(&string, str_symb_name);
478 RtlAnsiStringToUnicodeString(&symb_name, &string, TRUE);
479 IoDeleteSymbolicLink(&symb_name);
480 RtlFreeUnicodeString(&symb_name);
481
482 if (pdev_ext->res_list)
483 ExFreePool(pdev_ext->res_list); // not allocated by usb_alloc_mem
484
485 IoDeleteDevice(pdev);
486 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_delete_device(): device deleted\n"));
487 return TRUE;
488 }
489
490 // we can not use endp here for it is within the dev scope, and
491 // we can not acquire the dev-lock, fortunately we saved some
492 // info in urb->pipe in uhci_internal_submit_XXX.
493 BOOLEAN NTAPI
494 uhci_isr(PKINTERRUPT interrupt, PVOID context)
495 {
496 PUHCI_DEV uhci;
497 USHORT status;
498 PLIST_ENTRY pthis, pnext;
499 PURB purb;
500
501 UNREFERENCED_PARAMETER(interrupt);
502 UNREFERENCED_PARAMETER(context);
503
504 uhci_dbg_print(DBGLVL_ULTRA, ("uhci_isr(): context=0x%x\n", context));
505
506 /*
507 * Read the interrupt status, and write it back to clear the
508 * interrupt cause
509 */
510 uhci = (PUHCI_DEV) context;
511 if (uhci == NULL)
512 return FALSE;
513
514 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS));
515 if (!status) /* shared interrupt, not mine */
516 return FALSE;
517
518 if (status != 1)
519 {
520 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr(): current uhci status=0x%x\n", status));
521 }
522 else
523 {
524 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr(): congratulations, no error occurs\n"));
525 }
526
527 /* clear it */
528 WRITE_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS), status);
529
530 if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD))
531 {
532 if (status & USBSTS_HSE)
533 {
534 DbgPrint("uhci_isr(): host system error, PCI problems?\n");
535 //for( ; ; );
536 }
537 if (status & USBSTS_HCPE)
538 {
539 DbgPrint("uhci_isr(): host controller process error. something bad happened\n");
540 //for( ; ; );
541 //for( ; ; );
542 }
543 if ((status & USBSTS_HCH)) //&& !uhci->is_suspended
544 {
545 DbgPrint("uhci_isr(): host controller halted. very bad\n");
546 /* FIXME: Reset the controller, fix the offending TD */
547 }
548 }
549
550 // don't no how to handle it yet
551 //if (status & USBSTS_RD)
552 //{
553 //uhci_wakeup(uhci);
554 //}*/
555
556 //let's remove those force-cancel urbs from the schedule first
557 ListFirst(&uhci->urb_list, pthis);
558 while (pthis)
559 {
560 purb = (PURB) pthis;
561 if (purb->flags & URB_FLAG_FORCE_CANCEL)
562 {
563 uhci_remove_urb_from_schedule(uhci, purb);
564 }
565 ListNext(&uhci->urb_list, pthis, pnext);
566 pthis = pnext;
567 }
568
569 //clear the interrupt if the urb is force canceled
570 uhci->skel_term_td->status &= ~TD_CTRL_IOC;
571
572 //next we need to find if anything fininshed
573 ListFirst(&uhci->urb_list, pthis);
574 while (pthis)
575 {
576 purb = (PURB) pthis;
577 if (purb->flags & URB_FLAG_IN_SCHEDULE)
578 {
579 if (uhci_is_xfer_finished(purb))
580 uhci_remove_urb_from_schedule(uhci, purb);
581 }
582 ListNext(&uhci->urb_list, pthis, pnext);
583 pthis = pnext;
584 }
585
586 KeInsertQueueDpc(&uhci->pdev_ext->uhci_dpc, uhci, 0);
587 return TRUE;
588 }
589
590 BOOLEAN NTAPI
591 uhci_cal_cpu_freq(PVOID context)
592 {
593 UNREFERENCED_PARAMETER(context);
594
595 usb_cal_cpu_freq();
596 return TRUE;
597 }
598
599 PDEVICE_OBJECT
600 uhci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr)
601 {
602 LONG bus, i, j, ret = 0;
603 PCI_SLOT_NUMBER slot_num;
604 PPCI_COMMON_CONFIG pci_config;
605 PDEVICE_OBJECT pdev;
606 BYTE buffer[sizeof(PCI_COMMON_CONFIG)];
607 LONG count;
608 PDEVICE_EXTENSION pdev_ext;
609
610 slot_num.u.AsULONG = 0;
611 pci_config = (PPCI_COMMON_CONFIG) buffer;
612 count = 0;
613 pdev = NULL;
614
615 //scan the PCI buses to find uhci controller
616 for (bus = 0; bus <= PCI_MAX_BRIDGE_NUMBER; bus++)
617 {
618 for(i = 0; i <= PCI_MAX_DEVICES; i++)
619 {
620 slot_num.u.bits.DeviceNumber = i;
621 for(j = 0; j <= PCI_MAX_FUNCTION; j++)
622 {
623 slot_num.u.bits.FunctionNumber = j;
624
625 ret = HalGetBusData(PCIConfiguration,
626 bus, slot_num.u.AsULONG, pci_config, PCI_COMMON_HDR_LENGTH);
627
628 if (ret == 0) /*no this bus */
629 break;
630
631 if (ret == 2) /*no device on the slot */
632 break;
633
634 if (pci_config->BaseClass == 0x0c && pci_config->SubClass == 0x03 &&
635 pci_config->ProgIf == 0x00)
636 {
637 // well, we find our usb host controller, create device
638 pdev = uhci_alloc(drvr_obj, reg_path, ((bus << 8) | (i << 3) | j), dev_mgr);
639 if (pdev)
640 #ifdef _MULTI_UHCI
641 count++;
642 #else
643 goto LBL_LOOPOUT;
644 #endif
645 }
646 }
647 if (ret == 0)
648 break;
649 }
650 }
651
652 #ifndef _MULTI_UHCI
653 LBL_LOOPOUT:
654 #endif
655 DbgPrint("Found %d UHCI controllers\n", count);
656
657 if (pdev)
658 {
659 pdev_ext = pdev->DeviceExtension;
660 if (pdev_ext)
661 {
662 // acquire higher irql to eliminate pre-empty
663 KeSynchronizeExecution(pdev_ext->uhci_int, uhci_cal_cpu_freq, NULL);
664 }
665 }
666 return pdev;
667 }
668
669 PDEVICE_OBJECT
670 uhci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr)
671 {
672 LONG frd_num, prd_num;
673 PDEVICE_OBJECT pdev;
674 PDEVICE_EXTENSION pdev_ext;
675 ULONG vector, addr_space;
676 LONG bus;
677 KIRQL irql;
678 KAFFINITY affinity;
679
680 DEVICE_DESCRIPTION dev_desc;
681 CM_PARTIAL_RESOURCE_DESCRIPTOR *pprd;
682 PCI_SLOT_NUMBER slot_num;
683 NTSTATUS status;
684 UCHAR hcd_id;
685
686
687 pdev = uhci_create_device(drvr_obj, dev_mgr);
688 if (pdev == NULL)
689 return pdev;
690 pdev_ext = pdev->DeviceExtension;
691
692 pdev_ext->pci_addr = bus_addr;
693 bus = (bus_addr >> 8);
694
695 slot_num.u.AsULONG = 0;
696 slot_num.u.bits.DeviceNumber = ((bus_addr & 0xff) >> 3);
697 slot_num.u.bits.FunctionNumber = (bus_addr & 0x07);
698
699 //now create adapter object
700 RtlZeroMemory(&dev_desc, sizeof(dev_desc));
701
702 dev_desc.Version = DEVICE_DESCRIPTION_VERSION;
703 dev_desc.Master = TRUE;
704 dev_desc.ScatterGather = TRUE;
705 dev_desc.Dma32BitAddresses = TRUE;
706 dev_desc.BusNumber = bus;
707 dev_desc.InterfaceType = PCIBus;
708 dev_desc.MaximumLength =
709 UHCI_MAX_POOL_TDS * sizeof(UHCI_TD) * UHCI_MAX_TD_POOLS
710 + sizeof(UHCI_QH) * UHCI_MAX_POOL_QHS + sizeof(ULONG) * UHCI_MAX_FRAMES;
711
712 pdev_ext->map_regs = 2; // UHCI_MAX_TD_POOLS +
713 //+ BYTES_TO_PAGES( ( UHCI_MAX_POOL_TDS * 64 ) * UHCI_MAX_TD_POOLS ) ;
714
715 pdev_ext->padapter = HalGetAdapter(&dev_desc, &pdev_ext->map_regs);
716
717 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_alloc(): padapter=0x%x\n", pdev_ext->padapter));
718 if (pdev_ext->padapter == NULL)
719 {
720 //fatal error
721 uhci_delete_device(pdev);
722 return NULL;
723 }
724
725 DbgPrint("uhci_alloc(): reg_path=%p, \n \
726 uhci_alloc(): PCIBus=0x%x, bus=0x%x, bus_addr=0x%x \n \
727 uhci_alloc(): slot_num=0x%x, &res_list=%p \n", reg_path, (DWORD) PCIBus, (DWORD) bus,
728 (DWORD) bus_addr, (DWORD) slot_num.u.AsULONG, & pdev_ext->res_list);
729
730 //let's allocate resources for this device
731 DbgPrint("uhci_alloc(): about to assign slot res\n");
732 if ((status = HalAssignSlotResources(reg_path, NULL, //no class name yet
733 drvr_obj, NULL, //no support of another uhci controller
734 PCIBus,
735 bus, slot_num.u.AsULONG, &pdev_ext->res_list)) != STATUS_SUCCESS)
736 {
737 DbgPrint("uhci_alloc(): error assign slot res, 0x%x\n", status);
738 release_adapter(pdev_ext->padapter);
739 pdev_ext->padapter = NULL;
740 uhci_delete_device(pdev);
741 return NULL;
742 }
743
744 //parse the resource list
745 for(frd_num = 0; frd_num < (LONG) pdev_ext->res_list->Count; frd_num++)
746 {
747 for(prd_num = 0; prd_num < (LONG) pdev_ext->res_list->List[frd_num].PartialResourceList.Count;
748 prd_num++)
749 {
750 pprd = &pdev_ext->res_list->List[frd_num].PartialResourceList.PartialDescriptors[prd_num];
751 if (pprd->Type == CmResourceTypePort)
752 {
753 RtlCopyMemory(&pdev_ext->res_port, &pprd->u.Port, sizeof(pprd->u.Port));
754 }
755 else if (pprd->Type == CmResourceTypeInterrupt)
756 {
757 RtlCopyMemory(&pdev_ext->res_interrupt, &pprd->u.Interrupt, sizeof(pprd->u.Interrupt));
758 }
759 }
760 }
761
762 //for port, translate them to system address
763 addr_space = 1;
764 if (HalTranslateBusAddress(PCIBus, bus, pdev_ext->res_port.Start, &addr_space, //io space
765 &pdev_ext->uhci->uhci_reg_base) != (BOOLEAN) TRUE)
766 {
767 DbgPrint("uhci_alloc(): error, can not translate bus address\n");
768 release_adapter(pdev_ext->padapter);
769 pdev_ext->padapter = NULL;
770 uhci_delete_device(pdev);
771 return NULL;
772 }
773
774 DbgPrint("uhci_alloc(): address space=0x%x\n, reg_base=0x%x\n",
775 addr_space, pdev_ext->uhci->uhci_reg_base.u.LowPart);
776
777 if (addr_space == 0)
778 {
779 //port has been mapped to memory space
780 pdev_ext->uhci->port_mapped = TRUE;
781 pdev_ext->uhci->port_base = (PBYTE) MmMapIoSpace(pdev_ext->uhci->uhci_reg_base,
782 pdev_ext->res_port.Length, FALSE);
783
784 //fatal error can not map the registers
785 if (pdev_ext->uhci->port_base == NULL)
786 {
787 release_adapter(pdev_ext->padapter);
788 pdev_ext->padapter = NULL;
789 uhci_delete_device(pdev);
790 return NULL;
791 }
792 }
793 else
794 {
795 //io space
796 pdev_ext->uhci->port_mapped = FALSE;
797 pdev_ext->uhci->port_base = (PBYTE) pdev_ext->uhci->uhci_reg_base.LowPart;
798 }
799
800 //before we connect the interrupt, we have to init uhci
801 pdev_ext->uhci->fsbr_cnt = 0;
802 pdev_ext->uhci->pdev_ext = pdev_ext;
803
804 if (uhci_init_schedule(pdev_ext->uhci, pdev_ext->padapter) == FALSE)
805 {
806 release_adapter(pdev_ext->padapter);
807 pdev_ext->padapter = NULL;
808 uhci_delete_device(pdev);
809 return NULL;
810 }
811
812 InitializeListHead(&pdev_ext->uhci->urb_list);
813 KeInitializeSpinLock(&pdev_ext->uhci->pending_endp_list_lock);
814 InitializeListHead(&pdev_ext->uhci->pending_endp_list);
815
816 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_alloc(): pending_endp_list=0x%x\n",
817 &pdev_ext->uhci->pending_endp_list));
818
819 init_pending_endp_pool(&pdev_ext->uhci->pending_endp_pool);
820 KeInitializeTimer(&pdev_ext->uhci->reset_timer);
821
822 vector = HalGetInterruptVector(PCIBus,
823 bus,
824 pdev_ext->res_interrupt.level,
825 pdev_ext->res_interrupt.vector,
826 &irql,
827 &affinity);
828
829 KeInitializeDpc(&pdev_ext->uhci_dpc, uhci_dpc_callback, (PVOID) pdev_ext->uhci);
830
831 //connect the interrupt
832 DbgPrint("uhci_alloc(): the int=0x%x\n", vector);
833 if (IoConnectInterrupt(&pdev_ext->uhci_int,
834 uhci_isr,
835 pdev_ext->uhci,
836 NULL, //&pdev_ext->uhci->frame_list_lock,
837 vector,
838 irql,
839 irql,
840 LevelSensitive,
841 TRUE, //share the vector
842 affinity,
843 FALSE) //No float save
844 != STATUS_SUCCESS)
845 {
846 uhci_release(pdev);
847 return NULL;
848 }
849
850 //register with dev_mgr
851 uhci_init_hcd_interface(pdev_ext->uhci);
852 hcd_id = dev_mgr_register_hcd(dev_mgr, &pdev_ext->uhci->hcd_interf);
853
854 pdev_ext->uhci->hcd_interf.hcd_set_id(&pdev_ext->uhci->hcd_interf, hcd_id);
855 pdev_ext->uhci->hcd_interf.hcd_set_dev_mgr(&pdev_ext->uhci->hcd_interf, dev_mgr);
856
857 return pdev;
858 }
859
860 BOOLEAN
861 uhci_release(PDEVICE_OBJECT pdev)
862 {
863 PDEVICE_EXTENSION pdev_ext;
864 PUHCI_DEV uhci;
865
866 if (pdev == NULL)
867 return FALSE;
868
869 pdev_ext = pdev->DeviceExtension;
870
871 if (pdev_ext == NULL)
872 return FALSE;
873
874 uhci = pdev_ext->uhci;
875 if (uhci == NULL)
876 return FALSE;
877
878 uhci_stop(uhci);
879 //pdev_ext->uhci->conn_count = 0;
880 pdev_ext->uhci->fsbr_cnt = 0;
881
882 if (pdev_ext->uhci_int)
883 {
884 IoDisconnectInterrupt(pdev_ext->uhci_int);
885 pdev_ext->uhci_int = NULL;
886 }
887 else
888 TRAP();
889 destroy_pending_endp_pool(&pdev_ext->uhci->pending_endp_pool);
890 //pdev_ext->uhci->pending_endp_pool = NULL;
891
892 uhci_destroy_schedule(uhci);
893
894 release_adapter(pdev_ext->padapter);
895 pdev_ext->padapter = NULL;
896
897 uhci_delete_device(pdev);
898
899 return FALSE;
900
901 }
902
903 // send cmds to start the uhc
904 // shamelessly copied from linux's uhci.c (reset_hc(), configure_hc() routines)
905 BOOLEAN
906 uhci_start(PHCD hcd)
907 {
908 PUHCI_DEV uhci;
909 PBYTE io_addr;
910 USHORT pirq;
911 PCI_SLOT_NUMBER SlotNum;
912 int timeout = 10000;
913
914 uhci = uhci_from_hcd(hcd);
915 io_addr = uhci->port_base;
916
917 /*
918 * Reset the HC - this will force us to get a
919 * new notification of any already connected
920 * ports due to the virtual disconnect that it
921 * implies.
922 */
923 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_HCRESET);
924 while (READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD)) & USBCMD_HCRESET)
925 {
926 if (!--timeout)
927 {
928 break;
929 }
930 }
931
932 /* Turn on all interrupts */
933 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR),
934 USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP);
935
936 /* Start at frame 0 */
937 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBFRNUM), 0);
938 WRITE_PORT_ULONG((PULONG) (io_addr + USBFLBASEADD), uhci->frame_list_logic_addr.LowPart);
939
940 /* Run and mark it configured with a 64-byte max packet */
941 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
942
943 DbgPrint("uhci_start(): current uhci status=0x%x\n", uhci_status(uhci));
944
945 /* Enable PIRQ */
946 pirq = USBLEGSUP_DEFAULT;
947 SlotNum.u.AsULONG = 0;
948 SlotNum.u.bits.DeviceNumber = ((uhci->pdev_ext->pci_addr & 0xff) >> 3);
949 SlotNum.u.bits.FunctionNumber = (uhci->pdev_ext->pci_addr & 0x07);
950
951 DbgPrint("uhci_start(): set bus %d data at slot 0x%x\n", (uhci->pdev_ext->pci_addr >> 8),
952 SlotNum.u.AsULONG);
953
954 HalSetBusDataByOffset(PCIConfiguration, (uhci->pdev_ext->pci_addr >> 8), SlotNum.u.AsULONG,
955 &pirq, USBLEGSUP, sizeof(pirq));
956
957 return TRUE;
958 }
959
960 VOID
961 uhci_stop(PUHCI_DEV uhci)
962 {
963 PBYTE io_addr = uhci->port_base;
964 // turn off all the interrupt
965 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR), 0);
966 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
967 }
968
969 static VOID
970 uhci_reset(PUHCI_DEV uhci)
971 {
972 PBYTE io_addr = uhci->port_base;
973
974 uhci_stop(uhci);
975 /* Global reset for 50ms */
976 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_GRESET);
977 //uhci_wait_ms( uhci, 50 );
978 usb_wait_ms_dpc(50);
979
980 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
981 //uhci_wait_ms( uhci, 10 );
982 usb_wait_ms_dpc(10);
983 }
984
985 VOID
986 uhci_suspend(PUHCI_DEV uhci)
987 {
988 PBYTE io_addr = uhci->port_base;
989
990 //uhci->is_suspended = 1;
991 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_EGSM);
992
993 }
994
995 VOID
996 uhci_wakeup(PUHCI_DEV uhci)
997 {
998 PBYTE io_addr;
999 unsigned int status;
1000
1001 io_addr = uhci->port_base;
1002
1003 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
1004
1005 /* wait for EOP to be sent */
1006 status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));
1007 while (status & USBCMD_FGR)
1008 status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));
1009
1010 //uhci->is_suspended = 0;
1011
1012 /* Run and mark it configured with a 64-byte max packet */
1013 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
1014
1015 }
1016
1017 BOOLEAN
1018 uhci_init_schedule(PUHCI_DEV uhci, PADAPTER_OBJECT padapter)
1019 {
1020 int i, irq;
1021
1022 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_init_schedule(): entering..., uhci=0x%x\n", uhci));
1023 if (uhci == NULL || padapter == NULL)
1024 return FALSE;
1025
1026 if (init_td_pool_list(&uhci->td_pool, padapter) == FALSE)
1027 {
1028 return FALSE;
1029 }
1030 if (init_qh_pool(&uhci->qh_pool, padapter) == FALSE)
1031 {
1032 return FALSE;
1033 }
1034
1035 //since uhci is not started we can freely access all resources.
1036 for(i = 0; i < UHCI_MAX_SKELTDS; i++)
1037 {
1038 uhci->skel_td[i] = alloc_td(&uhci->td_pool);
1039 uhci_fill_td(uhci->skel_td[i], 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
1040
1041 if (i > 0)
1042 {
1043 uhci->skel_td[i]->link = uhci->skel_td[i - 1]->phy_addr;
1044 }
1045 }
1046
1047 /*for( i = UHCI_MAX_SKELTDS - 3; i >= 0; i-- )
1048 {
1049 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1050 &uhci->skel_td[ i ]->ptde->hori_link );
1051 } */
1052
1053 for(i = 0; i < UHCI_MAX_SKELQHS; i++)
1054 {
1055 uhci->skel_qh[i] = alloc_qh(&uhci->qh_pool);
1056 if (i > 0)
1057 {
1058 uhci->skel_qh[i - 1]->link = uhci->skel_qh[i]->phy_addr;
1059 }
1060
1061 uhci->skel_qh[i]->element = UHCI_PTR_TERM;
1062 }
1063
1064 uhci->skel_int1_td->link = uhci->skel_ls_control_qh->phy_addr;
1065
1066 // Hack for PIIX
1067 uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
1068 uhci->skel_term_td->link = uhci->skel_term_td->phy_addr;
1069
1070 uhci->skel_term_qh->link = UHCI_PTR_TERM;
1071 uhci->skel_term_qh->element = uhci->skel_term_td->phy_addr;
1072
1073 InsertTailList(&uhci->skel_term_qh->pqhe->vert_link, &uhci->skel_term_td->ptde->vert_link);
1074
1075 /*for( i = 0; i < UHCI_MAX_SKELQHS; i++ )
1076 {
1077 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1078 &uhci->skel_qh[ i ]->pqhe->hori_link );
1079 } */
1080
1081 if (uhci_init_frame_list(uhci, uhci->pdev_ext->padapter) == FALSE)
1082 uhci_destroy_frame_list(uhci);
1083
1084 //well all have been chained, now scatter the int tds to frame-list
1085 //shamelessly pasted from linux's uhci.c :-)
1086 for(i = 0; i < UHCI_MAX_FRAMES; i++)
1087 {
1088 irq = 0;
1089 if (i & 1)
1090 {
1091 irq++;
1092 if (i & 2)
1093 {
1094 irq++;
1095 if (i & 4)
1096 {
1097 irq++;
1098 if (i & 8)
1099 {
1100 irq++;
1101 if (i & 16)
1102 {
1103 irq++;
1104 if (i & 32)
1105 {
1106 irq++;
1107 if (i & 64)
1108 irq++;
1109 }
1110 }
1111 }
1112 }
1113 }
1114 }
1115
1116 /* Only place we don't use the frame list routines */
1117 uhci->frame_list[i] = uhci->skel_td[irq]->phy_addr;
1118 }
1119 return TRUE;
1120 }
1121
1122 BOOLEAN
1123 uhci_destroy_schedule(PUHCI_DEV uhci)
1124 {
1125 BOOLEAN ret;
1126
1127 ret = uhci_destroy_frame_list(uhci);
1128 ret = destroy_qh_pool(&uhci->qh_pool);
1129 ret = destroy_td_pool_list(&uhci->td_pool);
1130
1131 return ret;
1132
1133 }
1134
1135 VOID NTAPI
1136 uhci_cancel_pending_endp_urb(IN PVOID Parameter)
1137 {
1138 PLIST_ENTRY abort_list;
1139 PUSB_DEV pdev;
1140 PURB purb;
1141 USE_BASIC_NON_PENDING_IRQL;
1142
1143 abort_list = (PLIST_ENTRY) Parameter;
1144
1145 if (abort_list == NULL)
1146 return;
1147
1148 while (IsListEmpty(abort_list) == FALSE)
1149 {
1150 //these devs are protected by urb's ref-count
1151 purb = (PURB) RemoveHeadList(abort_list);
1152 pdev = purb->pdev;
1153 // purb->status is set when they are added to abort_list
1154
1155 uhci_generic_urb_completion(purb, purb->context);
1156
1157 lock_dev(pdev, FALSE);
1158 pdev->ref_count--;
1159 unlock_dev(pdev, FALSE);
1160 }
1161 usb_free_mem(abort_list);
1162 return;
1163 }
1164
1165 BOOLEAN
1166 uhci_process_pending_endp(PUHCI_DEV uhci)
1167 {
1168 PUSB_DEV pdev;
1169 LIST_ENTRY temp_list, abort_list;
1170 PLIST_ENTRY pthis;
1171 PURB purb;
1172 PUSB_ENDPOINT pendp;
1173 NTSTATUS can_submit = STATUS_UNSUCCESSFUL;
1174 PWORK_QUEUE_ITEM pwork_item;
1175 PLIST_ENTRY cancel_list;
1176 USE_BASIC_IRQL;
1177
1178 if (uhci == NULL)
1179 return FALSE;
1180
1181 InitializeListHead(&temp_list);
1182 InitializeListHead(&abort_list);
1183
1184 purb = NULL;
1185 uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): entering..., uhci=0x%x\n", uhci));
1186
1187 lock_pending_endp_list(&uhci->pending_endp_list_lock);
1188 while (IsListEmpty(&uhci->pending_endp_list) == FALSE)
1189 {
1190
1191 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): pending_endp_list=0x%x\n",
1192 &uhci->pending_endp_list));
1193
1194 pthis = RemoveHeadList(&uhci->pending_endp_list);
1195 pendp = ((PUHCI_PENDING_ENDP) pthis)->pendp;
1196 pdev = dev_from_endp(pendp);
1197
1198 lock_dev(pdev, TRUE);
1199
1200 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1201 {
1202 unlock_dev(pdev, TRUE);
1203 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1204 //delegate to uhci_remove_device for removing the urb queue on the endpoint
1205 continue;
1206 }
1207
1208 if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
1209 {
1210 while (IsListEmpty(&pendp->urb_list) == FALSE)
1211 {
1212 purb = (PURB) RemoveHeadList(&pendp->urb_list);
1213 purb->status = USB_STATUS_ENDPOINT_HALTED;
1214 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
1215 }
1216 InitializeListHead(&pendp->urb_list);
1217 unlock_dev(pdev, TRUE);
1218 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1219 continue;
1220 }
1221
1222
1223 if (IsListEmpty(&pendp->urb_list) == FALSE)
1224 {
1225 purb = (PURB) RemoveHeadList(&pendp->urb_list);
1226 ASSERT(purb);
1227 }
1228 else
1229 {
1230 InitializeListHead(&pendp->urb_list);
1231 unlock_dev(pdev, TRUE);
1232 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1233 continue;
1234 }
1235
1236 // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
1237 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): endp_type=0x%x\n",
1238 endp_type(pendp)));
1239 switch (endp_type(pendp))
1240 {
1241 case USB_ENDPOINT_XFER_BULK:
1242 {
1243 #ifdef DEMO
1244 can_submit = STATUS_UNSUCCESSFUL;
1245 #else
1246 can_submit = uhci_internal_submit_bulk(uhci, purb);
1247 #endif
1248 break;
1249 }
1250 case USB_ENDPOINT_XFER_CONTROL:
1251 {
1252 can_submit = uhci_internal_submit_ctrl(uhci, purb);
1253 break;
1254 }
1255 case USB_ENDPOINT_XFER_INT:
1256 {
1257 can_submit = uhci_internal_submit_int(uhci, purb);
1258 break;
1259 }
1260 case USB_ENDPOINT_XFER_ISOC:
1261 {
1262 can_submit = uhci_internal_submit_iso(uhci, purb);
1263 break;
1264 }
1265 }
1266
1267 if (can_submit == STATUS_NO_MORE_ENTRIES)
1268 {
1269 //no enough bandwidth or tds
1270 InsertHeadList(&pendp->urb_list, &purb->urb_link);
1271 InsertTailList(&temp_list, pthis);
1272 }
1273 else
1274 {
1275 // other error or success
1276 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1277
1278 if (can_submit != STATUS_SUCCESS)
1279 {
1280 //abort these URBs
1281 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
1282 uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): unable to submit urb 0x%x, "
1283 "with status=0x%x\n", purb, can_submit));
1284 purb->status = can_submit;
1285 }
1286
1287 }
1288 unlock_dev(pdev, TRUE);
1289 }
1290
1291 if (IsListEmpty(&temp_list) == FALSE)
1292 {
1293 //re-append them to the pending_endp_list
1294 ListFirst(&temp_list, pthis);
1295 RemoveEntryList(&temp_list);
1296 MergeList(&uhci->pending_endp_list, pthis);
1297 }
1298 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1299
1300 if (IsListEmpty(&abort_list) == FALSE)
1301 {
1302 PLIST_ENTRY pthis;
1303 cancel_list = (PLIST_ENTRY) usb_alloc_mem(NonPagedPool, sizeof(WORK_QUEUE_ITEM) + sizeof(LIST_ENTRY));
1304 ASSERT(cancel_list);
1305
1306 ListFirst(&abort_list, pthis);
1307 RemoveEntryList(&abort_list);
1308 InsertTailList(pthis, cancel_list);
1309
1310 pwork_item = (PWORK_QUEUE_ITEM) (cancel_list + 1);
1311
1312 // we do not need to worry the uhci_cancel_pending_endp_urb running when the
1313 // driver is unloading since it will prevent the dev_mgr to quit till all the
1314 // reference count to the dev drop to zero.
1315 ExInitializeWorkItem(pwork_item, uhci_cancel_pending_endp_urb, (PVOID) cancel_list);
1316 ExQueueWorkItem(pwork_item, DelayedWorkQueue);
1317 }
1318 return TRUE;
1319 }
1320
1321 NTSTATUS
1322 uhci_submit_urb(PUHCI_DEV uhci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
1323 {
1324 int i;
1325 PUHCI_PENDING_ENDP pending_endp;
1326 NTSTATUS status;
1327 USE_BASIC_IRQL;
1328
1329 if (uhci == NULL || pdev == NULL || pendp == NULL || purb == NULL)
1330 {
1331 uhci_dbg_print(DBGLVL_MEDIUM,
1332 ("uhci_submit_urb(): uhci=0x%x, pdev=0x%x, pendp=0x%x, purb=0x%x "
1333 "called with invalid param!\n", uhci, pdev, pendp, purb));
1334 return STATUS_INVALID_PARAMETER;
1335 }
1336
1337 lock_pending_endp_list(&uhci->pending_endp_list_lock);
1338 lock_dev(pdev, TRUE);
1339
1340 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1341 {
1342 status = purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1343 goto LBL_OUT;
1344 }
1345
1346 if (dev_class(pdev) == USB_DEV_CLASS_ROOT_HUB)
1347 {
1348 unlock_dev(pdev, TRUE);
1349 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1350 status = uhci_rh_submit_urb(pdev, purb);
1351 return status;
1352 }
1353
1354 if (pendp)
1355 purb->pendp = pendp;
1356 else
1357 purb->pendp = &pdev->default_endp;
1358
1359 if (dev_from_endp(purb->pendp) != pdev)
1360 {
1361 uhci_dbg_print(DBGLVL_MEDIUM,
1362 ("uhci_submit_urb(): dev_from_endp=0x%x\n, pdev=0x%x, pendp=0x%x "
1363 "devices mismatch!\n", dev_from_endp(purb->pendp), pdev, pendp));
1364
1365 status = purb->status = STATUS_INVALID_PARAMETER;
1366 goto LBL_OUT;
1367 }
1368
1369 if (endp_state(purb->pendp) == USB_ENDP_FLAG_STALL)
1370 {
1371 status = purb->status = USB_STATUS_ENDPOINT_HALTED;
1372 goto LBL_OUT;
1373 }
1374
1375 purb->pdev = pdev;
1376 purb->rest_bytes = purb->data_length;
1377
1378 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_BULK)
1379 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
1380 else
1381 purb->bytes_to_transfer = purb->data_length;
1382
1383 uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_submit_urb(): bytes_to_transfer=0x%x\n", purb->bytes_to_transfer));
1384
1385 purb->bytes_transfered = 0;
1386 InitializeListHead(&purb->trasac_list);
1387 purb->last_finished_td = &purb->trasac_list;
1388 purb->flags &= ~(URB_FLAG_STATE_MASK | URB_FLAG_IN_SCHEDULE | URB_FLAG_FORCE_CANCEL);
1389 purb->flags |= URB_FLAG_STATE_PENDING;
1390
1391
1392 i = IsListEmpty(&pendp->urb_list);
1393 InsertTailList(&pendp->urb_list, &purb->urb_link);
1394
1395 pdev->ref_count++; //for urb reference
1396
1397 if (i == FALSE)
1398 {
1399 //there is urb pending, simply queue it and return
1400 status = purb->status = STATUS_PENDING;
1401 goto LBL_OUT;
1402 }
1403 else if (usb_endp_busy_count(purb->pendp) && endp_type(purb->pendp) != USB_ENDPOINT_XFER_ISOC)
1404 {
1405 //
1406 //No urb waiting but urb overlap not allowed,
1407 //so leave it in queue and return, will be scheduled
1408 //later
1409 //
1410 status = purb->status = STATUS_PENDING;
1411 goto LBL_OUT;
1412 }
1413
1414 pending_endp = alloc_pending_endp(&uhci->pending_endp_pool, 1);
1415 if (pending_endp == NULL)
1416 {
1417 //panic
1418 status = purb->status = STATUS_UNSUCCESSFUL;
1419 goto LBL_OUT2;
1420 }
1421
1422 pending_endp->pendp = purb->pendp;
1423 InsertTailList(&uhci->pending_endp_list, &pending_endp->endp_link );
1424
1425 unlock_dev(pdev, TRUE);
1426 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1427
1428 uhci_process_pending_endp(uhci);
1429 return STATUS_PENDING;
1430
1431 LBL_OUT2:
1432 pdev->ref_count--;
1433 RemoveEntryList(&purb->urb_link);
1434
1435 LBL_OUT:
1436 unlock_dev(pdev, TRUE);
1437 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1438 return status;
1439 }
1440
1441 NTSTATUS
1442 uhci_set_error_code(PURB urb, ULONG raw_status)
1443 {
1444 if ((raw_status & TD_CTRL_ANY_ERROR) == 0)
1445 {
1446 //test if the urb is canceled
1447 if (urb->flags & URB_FLAG_FORCE_CANCEL)
1448 urb->status = STATUS_CANCELLED;
1449 else
1450 urb->status = STATUS_SUCCESS;
1451 }
1452
1453 else if (raw_status & TD_CTRL_BABBLE)
1454 urb->status = USB_STATUS_DATA_OVERRUN;
1455
1456 else if (raw_status & TD_CTRL_STALLED)
1457 urb->status = USB_STATUS_STALL_PID;
1458
1459 else if (raw_status & TD_CTRL_DBUFERR)
1460 urb->status = USB_STATUS_BUFFER_OVERRUN;
1461
1462 else if (raw_status & TD_CTRL_CRCTIMEO)
1463 urb->status = USB_STATUS_CRC;
1464
1465 else if (raw_status & TD_CTRL_BITSTUFF)
1466 urb->status = USB_STATUS_BTSTUFF;
1467
1468 else
1469 urb->status = STATUS_UNSUCCESSFUL;
1470
1471 return urb->status;
1472 }
1473
1474 BOOLEAN NTAPI
1475 uhci_sync_remove_urb_finished(PVOID context)
1476 {
1477 PUHCI_DEV uhci;
1478 PLIST_ENTRY pthis, pnext, ptemp;
1479 PURB purb;
1480 PSYNC_PARAM pparam;
1481
1482 pparam = (PSYNC_PARAM) context;
1483 uhci = pparam->uhci;
1484 ptemp = (PLIST_ENTRY) pparam->context;
1485
1486 if (uhci == NULL)
1487 {
1488 return (UCHAR) (pparam->ret = FALSE);
1489 }
1490
1491 ListFirst(&uhci->urb_list, pthis);
1492 while (pthis)
1493 {
1494 //remove urbs not in the schedule
1495 ListNext(&uhci->urb_list, pthis, pnext);
1496 purb = (PURB) pthis;
1497
1498 if ((purb->flags & URB_FLAG_IN_SCHEDULE) == 0)
1499 {
1500 //finished or canceled( not apply for split bulk ).
1501 purb->flags &= ~URB_FLAG_STATE_MASK;
1502 purb->flags |= URB_FLAG_STATE_FINISHED;
1503 RemoveEntryList(pthis);
1504 InsertTailList(ptemp, pthis);
1505 }
1506 pthis = pnext;
1507 }
1508 pparam->ret = TRUE;
1509 return (UCHAR) TRUE;
1510 }
1511
1512 BOOLEAN
1513 uhci_drop_fsbr(PUHCI_DEV uhci)
1514 {
1515 if (uhci == NULL)
1516 return (UCHAR) FALSE;
1517
1518 uhci->fsbr_cnt--;
1519
1520 if (uhci->fsbr_cnt <= 0)
1521 {
1522 uhci->skel_term_qh->link = UHCI_PTR_TERM;
1523 uhci->fsbr_cnt = 0;
1524 }
1525
1526 return (UCHAR) TRUE;
1527 }
1528
1529 VOID NTAPI
1530 uhci_dpc_callback(PKDPC dpc, PVOID context, PVOID sysarg1, PVOID sysarg2)
1531 {
1532 PUHCI_DEV uhci;
1533
1534 LIST_HEAD temp_list;
1535 PLIST_ENTRY pthis, pnext;
1536 PURB purb;
1537 PQH_EXTENSION pqhe;
1538 PUHCI_PENDING_ENDP pending_endp;
1539 PUSB_DEV pdev;
1540 PUSB_ENDPOINT pendp;
1541
1542 BOOLEAN finished;
1543 LONG i, j;
1544 ULONG uhci_status, urb_status, toggle = 0;
1545
1546 SYNC_PARAM sync_param;
1547 USE_BASIC_NON_PENDING_IRQL;
1548
1549 UNREFERENCED_PARAMETER(dpc);
1550 UNREFERENCED_PARAMETER(sysarg2);
1551
1552 uhci = (PUHCI_DEV) context;
1553 if (uhci == NULL)
1554 return;
1555
1556 uhci_status = (ULONG) sysarg1;
1557
1558 InitializeListHead(&temp_list);
1559
1560 sync_param.uhci = uhci;
1561 sync_param.context = (PVOID) & temp_list;
1562
1563 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_dpc_callback(): entering..., uhci=0x%x\n", uhci));
1564 //remove finished urb from uhci's urb-list
1565 KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_remove_urb_finished, &sync_param);
1566
1567 //release resources( tds, and qhs ) the urb occupied
1568 while (IsListEmpty(&temp_list) == FALSE)
1569 {
1570 //not in any public queue, if do not access into dev, no race
1571 //condition will occur
1572 purb = (PURB) RemoveHeadList(&temp_list);
1573 urb_status = purb->status;
1574
1575 //the only place we do not use this lock on non-pending-endp-list data ops
1576 KeAcquireSpinLockAtDpcLevel(&uhci->pending_endp_list_lock);
1577 while (IsListEmpty(&purb->trasac_list) == FALSE)
1578 {
1579 pthis = RemoveHeadList(&purb->trasac_list);
1580
1581 if ((((PTD_EXTENSION) pthis)->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
1582 {
1583 pqhe = (PQH_EXTENSION) pthis;
1584 lock_qh_pool(&uhci->qh_pool, TRUE);
1585 free_qh(&uhci->qh_pool, pqhe->pqh);
1586 unlock_qh_pool(&uhci->qh_pool, TRUE);
1587 }
1588 else
1589 {
1590 //must be a td chain
1591 InsertHeadList(&purb->trasac_list, pthis);
1592 for(i = 0, purb->bytes_transfered = 0; i < purb->td_count; i++)
1593 {
1594 PUHCI_TD ptd;
1595 // accumulate data transfered in tds
1596 ptd = ((PTD_EXTENSION) pthis)->ptd;
1597 if ((ptd->status & TD_CTRL_ACTIVE) == 0 && (ptd->status & TD_CTRL_ANY_ERROR) == 0)
1598 {
1599 j = ptd->status & 0x7ff;
1600 purb->bytes_transfered += ((j == 0x7ff) ? 0 : (j + 1));
1601
1602 }
1603 ListNext(&purb->trasac_list, pthis, pnext);
1604 pthis = pnext;
1605 }
1606
1607 if (urb_status & TD_CTRL_ANY_ERROR)
1608 {
1609 if (purb->last_finished_td != NULL && purb->last_finished_td != &purb->trasac_list)
1610 toggle = (((PTD_EXTENSION) purb->last_finished_td)->ptd->info & (1 << 19));
1611 }
1612 //trick, remove trasac_list
1613 ListFirst(&purb->trasac_list, pthis);
1614 RemoveEntryList(&purb->trasac_list);
1615 lock_td_pool(&uhci->td_pool, TRUE);
1616 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
1617 unlock_td_pool(&uhci->td_pool, TRUE);
1618 //termination condition
1619 InitializeListHead(&purb->trasac_list);
1620 purb->last_finished_td = NULL;
1621 }
1622 }
1623
1624 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_ISOC
1625 || endp_type(purb->pendp) == USB_ENDPOINT_XFER_INT)
1626 uhci_claim_bandwidth(uhci, purb, FALSE); //release band-width
1627
1628 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1629
1630 uhci_set_error_code(purb, urb_status);
1631
1632 finished = TRUE;
1633
1634 //since the ref_count for the urb is not released, we can safely have one
1635 //pointer to dev
1636 pdev = dev_from_endp(purb->pendp);
1637 pendp = purb->pendp;
1638
1639 if (purb->status == USB_STATUS_BABBLE_DETECTED)
1640 {
1641 usb_dbg_print(DBGLVL_MEDIUM,
1642 ("uhci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus\n"));
1643 uhci_reset(uhci);
1644 uhci_start(&uhci->hcd_interf);
1645 }
1646
1647 //this will let the new request in uhci_generic_urb_completion to this endp
1648 //be processed rather than queued in the pending_endp_list
1649 lock_dev(pdev, TRUE);
1650 usb_endp_busy_count_dec(pendp);
1651 unlock_dev(pdev, TRUE);
1652
1653 if (usb_success(purb->status) == FALSE)
1654 {
1655 // set error code and complete the urb and purb is invalid from this point
1656 uhci_generic_urb_completion(purb, purb->context);
1657 }
1658 else
1659 {
1660 if ((purb->pipe & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
1661 {
1662 purb->rest_bytes -= purb->bytes_transfered;
1663 if (purb->rest_bytes)
1664 {
1665 finished = FALSE;
1666 }
1667 else
1668 {
1669 uhci_generic_urb_completion(purb, purb->context);
1670 }
1671 }
1672 else
1673 {
1674 uhci_generic_urb_completion(purb, purb->context);
1675 //purb is now invalid
1676 }
1677 }
1678
1679 KeAcquireSpinLockAtDpcLevel(&uhci->pending_endp_list_lock);
1680 lock_dev(pdev, TRUE);
1681
1682 if (finished)
1683 pdev->ref_count--;
1684
1685 if (urb_status & TD_CTRL_ANY_ERROR && endp_type(pendp) != USB_ENDPOINT_XFER_CONTROL)
1686 {
1687 pendp->flags &= ~USB_ENDP_FLAG_STAT_MASK;
1688 pendp->flags |= USB_ENDP_FLAG_STALL;
1689 }
1690
1691 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1692 {
1693 unlock_dev(pdev, TRUE);
1694 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1695 if (finished == FALSE)
1696 {
1697
1698 purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1699 uhci_generic_urb_completion(purb, purb->context);
1700
1701 lock_dev(pdev, TRUE);
1702 pdev->ref_count--;
1703 unlock_dev(pdev, TRUE);
1704 }
1705 continue;
1706 }
1707
1708 if (finished && IsListEmpty(&pendp->urb_list) == TRUE)
1709 {
1710 unlock_dev(pdev, TRUE);
1711 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1712 continue;
1713 }
1714 else if (finished == TRUE)
1715 {
1716 //has urb in the endp's urb-list
1717 if (usb_endp_busy_count(pendp) > 0)
1718 {
1719 //the urbs still have chance to be sheduled but not this time
1720 unlock_dev(pdev, TRUE);
1721 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1722 continue;
1723 }
1724 }
1725
1726 if (finished == FALSE)
1727 {
1728 //a split bulk transfer
1729 purb->bytes_transfered = 0;
1730 purb->bytes_to_transfer =
1731 UHCI_MAX_TDS_PER_TRANSFER * purb->pendp->pusb_endp_desc->wMaxPacketSize
1732 > purb->rest_bytes
1733 ? purb->rest_bytes : UHCI_MAX_TDS_PER_TRANSFER * purb->pendp->pusb_endp_desc->wMaxPacketSize;
1734
1735 //the urb is not finished
1736 purb->flags &= ~URB_FLAG_STATE_MASK;
1737 purb->flags |= URB_FLAG_STATE_PENDING;
1738
1739 InsertHeadList(&pendp->urb_list, &purb->urb_link);
1740 }
1741
1742 pending_endp = alloc_pending_endp(&uhci->pending_endp_pool, 1);
1743 if (!pending_endp)
1744 {
1745 unlock_dev(pdev, TRUE);
1746 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1747 return;
1748 }
1749
1750 pending_endp->pendp = pendp;
1751 InsertTailList(&uhci->pending_endp_list, &pending_endp->endp_link);
1752
1753 unlock_dev(pdev, TRUE);
1754 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1755 }
1756
1757 //ah...exhausted, let's find some in the pending_endp_list to rock
1758 uhci_process_pending_endp(uhci);
1759 return;
1760 }
1761
1762 BOOLEAN
1763 uhci_add_device(PUHCI_DEV uhci, PUSB_DEV dev)
1764 {
1765 if (dev == NULL || uhci == NULL)
1766 return FALSE;
1767
1768 return TRUE;
1769 }
1770
1771 BOOLEAN NTAPI
1772 uhci_sync_cancel_urbs_dev(PVOID context)
1773 {
1774 //cancel all the urbs on one dev
1775 PUHCI_DEV uhci;
1776 PUSB_DEV pdev, dest_dev;
1777 PSYNC_PARAM sync_param;
1778 PLIST_ENTRY pthis, pnext;
1779 LONG count;
1780
1781 sync_param = (PSYNC_PARAM) context;
1782 dest_dev = (PUSB_DEV) sync_param->context;
1783 uhci = sync_param->uhci;
1784
1785 if (uhci == NULL || dest_dev == NULL)
1786 {
1787 return (UCHAR) (sync_param->ret = FALSE);
1788 }
1789 count = 0;
1790 ListFirst(&uhci->urb_list, pthis);
1791 while (pthis)
1792 {
1793 pdev = dev_from_endp(((PURB) pthis)->pendp);
1794 if (pdev == dest_dev)
1795 {
1796 ((PURB) pthis)->flags |= URB_FLAG_FORCE_CANCEL;
1797 }
1798 ListNext(&uhci->urb_list, pthis, pnext);
1799 pthis = pnext;
1800 count++;
1801 }
1802 if (count)
1803 uhci->skel_term_td->status |= TD_CTRL_IOC;
1804
1805 return (UCHAR) (sync_param->ret = TRUE);
1806 }
1807
1808 BOOLEAN
1809 uhci_remove_device(PUHCI_DEV uhci, PUSB_DEV dev)
1810 {
1811 PUHCI_PENDING_ENDP ppending_endp;
1812 PLIST_ENTRY pthis, pnext;
1813 PURB purb;
1814 LIST_HEAD temp_list;
1815 int i, j, k;
1816 SYNC_PARAM sync_param;
1817
1818 USE_BASIC_IRQL;
1819
1820 if (uhci == NULL || dev == NULL)
1821 return FALSE;
1822
1823 InitializeListHead(&temp_list);
1824
1825 //free pending endp that has urb queued from pending endp list
1826 lock_pending_endp_list(&uhci->pending_endp_list_lock);
1827
1828 ListFirst(&uhci->pending_endp_list, pthis);
1829
1830 while (pthis)
1831 {
1832 ppending_endp = (PUHCI_PENDING_ENDP) pthis;
1833 ListNext(&uhci->pending_endp_list, pthis, pnext);
1834 if (dev_from_endp(ppending_endp->pendp) == dev)
1835 {
1836 RemoveEntryList(pthis);
1837 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1838 }
1839 pthis = pnext;
1840 }
1841 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1842
1843 //cancel all the urbs in the urb-list
1844 sync_param.uhci = uhci;
1845 sync_param.context = (PVOID) dev;
1846
1847 KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_cancel_urbs_dev, &sync_param);
1848
1849 //cancel all the urb in the endp's urb-list
1850 k = 0;
1851 lock_dev(dev, FALSE);
1852 if (dev->usb_config)
1853 {
1854 //only for configed dev
1855 for(i = 0; i < dev->usb_config->if_count; i++)
1856 {
1857 for(j = 0; j < dev->usb_config->interf[i].endp_count; j++)
1858 {
1859 ListFirst(&dev->usb_config->interf[i].endp[j].urb_list, pthis);
1860 while (pthis)
1861 {
1862 ListNext(&dev->usb_config->interf[i].endp[j].urb_list, pthis, pnext);
1863
1864 RemoveEntryList(pthis);
1865 InsertHeadList(&temp_list, pthis);
1866 pthis = pnext;
1867 k++;
1868 }
1869
1870 }
1871 }
1872 }
1873 ListFirst(&dev->default_endp.urb_list, pthis);
1874
1875 while (pthis)
1876 {
1877 ListNext(&dev->default_endp.urb_list, pthis, pnext);
1878
1879 RemoveEntryList(pthis);
1880 InsertHeadList(&temp_list, pthis);
1881 pthis = pnext;
1882 k++;
1883 }
1884 unlock_dev(dev, FALSE);
1885
1886 if (IsListEmpty(&temp_list) == FALSE)
1887 {
1888 for(i = 0; i < k; i++)
1889 {
1890 //complete those urbs with error
1891 pthis = RemoveHeadList(&temp_list);
1892 purb = (PURB) pthis;
1893 purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1894 {
1895 uhci_generic_urb_completion(purb, purb->context);
1896 }
1897 }
1898 }
1899
1900 lock_dev(dev, FALSE) dev->ref_count -= k;
1901 unlock_dev(dev, FALSE);
1902
1903 return TRUE;
1904 }
1905
1906
1907 //
1908 // assume that the urb has its rest_bytes and bytes_to_transfer set
1909 // and bytes_transfered is zeroed.
1910 // dev_lock must be acquired outside
1911 // urb comes from dev's endpoint urb-list. it is already removed from
1912 // the endpoint urb-list.
1913 //
1914 NTSTATUS
1915 uhci_internal_submit_bulk(PUHCI_DEV uhci, PURB urb)
1916 {
1917
1918 LONG max_packet_size, td_count, offset, bytes_to_transfer, data_load;
1919 PBYTE start_addr;
1920 PUHCI_TD ptd;
1921 PUHCI_QH pqh;
1922 LIST_ENTRY td_list, *pthis, *pnext;
1923 BOOLEAN old_toggle, toggle, ret;
1924 UCHAR pid;
1925
1926 if (uhci == NULL || urb == NULL)
1927 return STATUS_INVALID_PARAMETER;
1928
1929 max_packet_size = endp_max_packet_size(urb->pendp);
1930 if (urb->bytes_to_transfer == 0)
1931 {
1932 return STATUS_INVALID_PARAMETER;
1933 }
1934
1935 td_count = (urb->bytes_to_transfer + max_packet_size - 1) / max_packet_size;
1936
1937 lock_td_pool(&uhci->td_pool, TRUE);
1938 if (can_transfer(&uhci->td_pool, td_count) == FALSE)
1939 {
1940 unlock_td_pool(&uhci->td_pool, TRUE);
1941 return STATUS_NO_MORE_ENTRIES;
1942 }
1943
1944 ptd = alloc_tds(&uhci->td_pool, td_count);
1945 unlock_td_pool(&uhci->td_pool, TRUE);
1946
1947 if (ptd == NULL)
1948 {
1949 return STATUS_UNSUCCESSFUL;
1950 }
1951
1952 InitializeListHead(&td_list);
1953 InsertTailList(&ptd->ptde->vert_link, &td_list);
1954
1955 ListFirst(&td_list, pthis);
1956 ListNext(&td_list, pthis, pnext);
1957
1958 start_addr = &urb->data_buffer[urb->data_length - urb->rest_bytes];
1959 offset = 0;
1960
1961 old_toggle = toggle = urb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE ? TRUE : FALSE;
1962 bytes_to_transfer = urb->bytes_to_transfer;
1963
1964 urb->pipe = ((max_packet_size - 1) << 21)
1965 | ((ULONG) endp_num(urb->pendp) << 15)
1966 | (dev_from_endp(urb->pendp)->dev_addr << 8)
1967 | ((ULONG) endp_dir(urb->pendp)) | USB_ENDPOINT_XFER_BULK;
1968
1969 pid = (((ULONG) urb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT);
1970 while (pthis)
1971 {
1972 ptd = ((PTD_EXTENSION) pthis)->ptd;
1973
1974 data_load = max_packet_size < bytes_to_transfer ? max_packet_size : bytes_to_transfer;
1975 ptd->purb = urb;
1976 uhci_fill_td(ptd,
1977 (3 << TD_CTRL_C_ERR_SHIFT)
1978 | (TD_CTRL_ACTIVE),
1979 ((data_load - 1) << 21)
1980 | (toggle << 19)
1981 | ((ULONG) endp_num(urb->pendp) << 15)
1982 | (dev_from_endp(urb->pendp)->dev_addr << 8)
1983 | pid, MmGetPhysicalAddress(start_addr + offset).LowPart);
1984
1985 bytes_to_transfer -= data_load;
1986 offset += data_load;
1987
1988 if (pnext)
1989 {
1990 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
1991 }
1992 else
1993 {
1994 //Last one, enable ioc and short packet detect if necessary
1995 ptd->link = UHCI_PTR_TERM;
1996 ptd->status |= TD_CTRL_IOC;
1997 if (bytes_to_transfer < max_packet_size && (pid == USB_PID_IN))
1998 {
1999 //ptd->status |= TD_CTRL_SPD;
2000 }
2001 }
2002
2003 pthis = pnext;
2004 toggle ^= 1;
2005 if (pthis)
2006 ListNext(&td_list, pthis, pnext);
2007
2008 }
2009
2010 ListFirst(&td_list, pthis);
2011 RemoveEntryList(&td_list);
2012
2013 lock_qh_pool(&uhci->qh_pool, TRUE);
2014 pqh = alloc_qh(&uhci->qh_pool);
2015 unlock_qh_pool(&uhci->qh_pool, TRUE);
2016
2017 if (pqh == NULL)
2018 {
2019 lock_td_pool(&uhci->td_pool, TRUE);
2020
2021 if (pthis)
2022 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2023
2024 unlock_td_pool(&uhci->td_pool, TRUE);
2025 return STATUS_NO_MORE_ENTRIES;
2026
2027 }
2028
2029 urb->td_count = td_count;
2030
2031 uhci_insert_tds_qh(pqh, ((PTD_EXTENSION) pthis)->ptd);
2032 uhci_insert_qh_urb(urb, pqh);
2033 urb->pendp->flags =
2034 (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
2035 usb_endp_busy_count_inc(urb->pendp);
2036 uhci_insert_urb_to_schedule(uhci, urb, ret);
2037
2038 if (ret == FALSE)
2039 {
2040 // undo all we have done
2041 RemoveEntryList(&pqh->pqhe->vert_link); //remove qh from td_chain
2042 RemoveEntryList(&urb->trasac_list);
2043
2044 lock_td_pool(&uhci->td_pool, TRUE);
2045 if (pthis)
2046 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2047 unlock_td_pool(&uhci->td_pool, TRUE);
2048
2049 lock_qh_pool(&uhci->qh_pool, TRUE);
2050 if (pqh)
2051 free_qh(&uhci->qh_pool, pqh);
2052 unlock_qh_pool(&uhci->qh_pool, TRUE);
2053
2054 InitializeListHead(&urb->trasac_list);
2055 usb_endp_busy_count_dec(urb->pendp);
2056 urb->pendp->flags =
2057 (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (old_toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
2058 return STATUS_UNSUCCESSFUL;
2059 }
2060 return STATUS_SUCCESS;
2061 }
2062
2063 NTSTATUS
2064 uhci_internal_submit_ctrl(PUHCI_DEV uhci, PURB urb)
2065 {
2066 LIST_ENTRY td_list, *pthis, *pnext;
2067 LONG i, td_count;
2068 LONG toggle;
2069 LONG max_packet_size, bytes_to_transfer, bytes_rest, start_idx;
2070 PUHCI_TD ptd;
2071 PUHCI_QH pqh;
2072 ULONG dev_addr;
2073 PUSB_DEV pdev;
2074 BOOLEAN ret;
2075
2076 if (uhci == NULL || urb == NULL)
2077 return STATUS_INVALID_PARAMETER;
2078
2079 toggle = 0;
2080 bytes_rest = urb->rest_bytes;
2081 bytes_to_transfer = urb->bytes_to_transfer;
2082 max_packet_size = endp_max_packet_size(urb->pendp);
2083 start_idx = urb->data_length - urb->rest_bytes;
2084 td_count = 2 + (urb->bytes_to_transfer + max_packet_size - 1) / max_packet_size;
2085
2086 lock_td_pool(&uhci->td_pool, TRUE);
2087
2088 if (can_transfer(&uhci->td_pool, td_count) == FALSE)
2089 {
2090 unlock_td_pool(&uhci->td_pool, TRUE);
2091 return STATUS_NO_MORE_ENTRIES;
2092 }
2093
2094 ptd = alloc_tds(&uhci->td_pool, td_count);
2095 unlock_td_pool(&uhci->td_pool, TRUE);
2096
2097 if (ptd == NULL)
2098 {
2099 return STATUS_UNSUCCESSFUL;
2100 }
2101
2102 InsertTailList(&ptd->ptde->vert_link, &td_list);
2103
2104 ListFirst(&td_list, pthis);
2105 ListNext(&td_list, pthis, pnext);
2106
2107 ptd = ((PTD_EXTENSION) pthis)->ptd;
2108
2109 pdev = dev_from_endp(urb->pendp);
2110 dev_addr = pdev->dev_addr;
2111
2112 if (dev_state(pdev) <= USB_DEV_STATE_RESET)
2113 dev_addr = 0;
2114
2115 usb_dbg_print(DBGLVL_MAXIMUM, ("uhci_internal_submit_ctrl(): dev_addr =0x%x\n", dev_addr));
2116
2117 RtlCopyMemory(uhci->io_buf, urb->setup_packet, 8);
2118
2119 if ((urb->setup_packet[0] & USB_DIR_IN) == 0) //out
2120 RtlCopyMemory(&uhci->io_buf[8], urb->data_buffer, bytes_to_transfer);
2121 else
2122 RtlZeroMemory(&uhci->io_buf[8], bytes_to_transfer);
2123
2124 uhci_fill_td(ptd,
2125 (3 << TD_CTRL_C_ERR_SHIFT) | (TD_CTRL_ACTIVE),
2126 (7 << 21) | (((ULONG) endp_num(urb->pendp)) << 15) | (dev_addr << 8) | (USB_PID_SETUP),
2127 //uhci->io_buf_logic_addr.LowPart);
2128 MmGetPhysicalAddress(urb->setup_packet).LowPart);
2129
2130 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
2131 pthis = pnext;
2132 ListNext(&td_list, pthis, pnext);
2133
2134 urb->pipe = ((max_packet_size - 1) << 21)
2135 | ((ULONG) endp_num(urb->pendp) << 15)
2136 | (dev_addr << 8) | (pdev->flags & USB_DEV_FLAG_LOW_SPEED) | USB_ENDPOINT_XFER_CONTROL;
2137
2138 for(i = 0, toggle = 1; ((i < td_count - 2) && pthis); i++, toggle ^= 1)
2139 {
2140 //construct tds for DATA packets of data stage.
2141 ptd = ((PTD_EXTENSION) pthis)->ptd;
2142 uhci_fill_td(ptd,
2143 (3 << TD_CTRL_C_ERR_SHIFT)
2144 | (TD_CTRL_ACTIVE),
2145 ((bytes_to_transfer >
2146 max_packet_size ? max_packet_size - 1 : bytes_to_transfer -
2147 1) << 21) | (toggle << 19) | (((ULONG) endp_num(urb->
2148 pendp)) << 15) | (dev_addr << 8) |
2149 ((urb->setup_packet[0] & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT),
2150 //uhci->io_buf_logic_addr.LowPart + 8 + i * max_packet_size );
2151 MmGetPhysicalAddress(&urb->data_buffer[start_idx + i * max_packet_size]).LowPart);
2152
2153 if (pnext)
2154 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
2155
2156 if (i < td_count - 3)
2157 {
2158 bytes_to_transfer -= max_packet_size;
2159 }
2160 else
2161 {
2162 if (bytes_to_transfer > 0)
2163 {
2164 if (bytes_to_transfer < max_packet_size && (urb->setup_packet[0] & USB_DIR_IN))
2165 ptd->status |= TD_CTRL_SPD;
2166 }
2167 }
2168 pthis = pnext;
2169
2170 if (pthis)
2171 ListNext(&td_list, pthis, pnext);
2172 }
2173
2174 if (pnext)
2175 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
2176
2177 ListFirstPrev(&td_list, pthis);
2178 ptd = ((PTD_EXTENSION) pthis)->ptd;
2179
2180 //the last is an IN transaction
2181 uhci_fill_td(ptd,
2182 (3 << TD_CTRL_C_ERR_SHIFT)
2183 | (TD_CTRL_ACTIVE | TD_CTRL_IOC),
2184 (UHCI_NULL_DATA_SIZE << 21)
2185 | (1 << 19)
2186 | (((ULONG) endp_num(urb->pendp)) << 15)
2187 | (dev_addr << 8)
2188 | ((td_count > 2)
2189 ? ((urb->setup_packet[0] & USB_DIR_IN) ? USB_PID_OUT : USB_PID_IN) : USB_PID_IN), 0);
2190
2191 ptd->link = UHCI_PTR_TERM;
2192
2193 ListFirst(&td_list, pthis);
2194 RemoveEntryList(&td_list);
2195
2196 lock_qh_pool(&uhci->qh_pool, TRUE);
2197 pqh = alloc_qh(&uhci->qh_pool);
2198 unlock_qh_pool(&uhci->qh_pool, TRUE);
2199
2200 if (pqh == NULL)
2201 {
2202 lock_td_pool(&uhci->td_pool, TRUE);
2203 if (pthis)
2204 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2205 unlock_td_pool(&uhci->td_pool, TRUE);
2206
2207 return STATUS_NO_MORE_ENTRIES;
2208 }
2209
2210 urb->td_count = td_count;
2211
2212 uhci_insert_tds_qh(pqh, ((PTD_EXTENSION) pthis)->ptd);
2213 uhci_insert_qh_urb(urb, pqh);
2214
2215 usb_endp_busy_count_inc(urb->pendp);
2216 uhci_insert_urb_to_schedule(uhci, urb, ret);
2217 if (ret == FALSE)
2218 {
2219 RemoveEntryList(&pqh->pqhe->vert_link);
2220 RemoveEntryList(&urb->trasac_list);
2221
2222 lock_td_pool(&uhci->td_pool, TRUE);
2223 if (pthis)
2224 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2225 unlock_td_pool(&uhci->td_pool, TRUE);
2226
2227 lock_qh_pool(&uhci->qh_pool, TRUE);
2228 if (pqh)
2229 free_qh(&uhci->qh_pool, pqh);
2230 unlock_qh_pool(&uhci->qh_pool, TRUE);
2231
2232 InitializeListHead(&urb->trasac_list);
2233 usb_endp_busy_count_dec(urb->pendp);
2234 return STATUS_UNSUCCESSFUL;
2235 }
2236
2237 return STATUS_SUCCESS;
2238 }
2239
2240 NTSTATUS
2241 uhci_internal_submit_int(PUHCI_DEV uhci, PURB urb)
2242 {
2243 LONG i;
2244 LONG toggle = 0;
2245 LONG max_packet_size;
2246 PUHCI_TD ptd;
2247 BOOLEAN ret;
2248
2249 if (uhci == NULL || urb == NULL)
2250 {
2251 uhci_dbg_print(DBGLVL_MEDIUM,
2252 ("uhci_internal_submit_int(): uhci=0x%x, urb=0x%x "
2253 "returning STATUS_INVALID_PARAMETER!\n", uhci, urb));
2254 return STATUS_INVALID_PARAMETER;
2255 }
2256
2257 toggle = (urb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE) ? TRUE : FALSE;
2258 max_packet_size = endp_max_packet_size(urb->pendp);
2259
2260 if (max_packet_size < urb->data_length || max_packet_size == 0 || max_packet_size > 64)
2261 {
2262 uhci_dbg_print(DBGLVL_MEDIUM,
2263 ("uhci_internal_submit_int(): max_packet_size=%d, urb->data_length=%d "
2264 "returning STATUS_INVALID_PARAMETER!\n", max_packet_size, urb->data_length));
2265 return STATUS_INVALID_PARAMETER;
2266 }
2267
2268 lock_td_pool(&uhci->td_pool, TRUE);
2269 ptd = alloc_td(&uhci->td_pool);
2270 unlock_td_pool(&uhci->td_pool, TRUE);
2271
2272 if (ptd == NULL)
2273 return STATUS_NO_MORE_ENTRIES;
2274
2275 for(i = 1; i <= 7; i++)
2276 {
2277 if (((ULONG) max_packet_size) >> i)
2278 continue;
2279 else
2280 break;
2281 }
2282
2283 i--;
2284 i &= 7;
2285
2286 urb->pipe = (((ULONG) urb->pendp->pusb_endp_desc->bInterval) << 24)
2287 | (i << 21)
2288 | (toggle << 19)
2289 | ((ULONG) endp_num(urb->pendp) << 15)
2290 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr) << 8)
2291 | USB_DIR_IN | (dev_from_endp(urb->pendp)->flags & USB_DEV_FLAG_LOW_SPEED) | USB_ENDPOINT_XFER_INT;
2292
2293 uhci_fill_td(ptd,
2294 (3 << TD_CTRL_C_ERR_SHIFT)
2295 | (TD_CTRL_ACTIVE)
2296 | ((urb->data_length < max_packet_size ? TD_CTRL_SPD : 0))
2297 | (TD_CTRL_IOC),
2298 (((ULONG) max_packet_size - 1) << 21)
2299 | (toggle << 19)
2300 | ((ULONG) endp_num(urb->pendp) << 15)
2301 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr & 0x7f) << 8)
2302 | USB_PID_IN, MmGetPhysicalAddress(urb->data_buffer).LowPart);
2303
2304 toggle ^= 1;
2305 urb->td_count = 1;
2306
2307 InitializeListHead(&urb->trasac_list);
2308 InsertTailList(&urb->trasac_list, &ptd->ptde->vert_link);
2309
2310 //indirectly guarded by pending_endp_list_lock
2311 if (uhci_claim_bandwidth(uhci, urb, TRUE) == FALSE)
2312 {
2313 InitializeListHead(&urb->trasac_list);
2314
2315 lock_td_pool(&uhci->td_pool, TRUE);
2316 free_td(&uhci->td_pool, ptd);
2317 unlock_td_pool(&uhci->td_pool, TRUE);
2318
2319 return STATUS_NO_MORE_ENTRIES;
2320 }
2321
2322 urb->pendp->flags = (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle << 31);
2323 usb_endp_busy_count_inc(urb->pendp);
2324
2325 uhci_insert_urb_to_schedule(uhci, urb, ret);
2326
2327 if (ret == FALSE)
2328 {
2329 lock_td_pool(&uhci->td_pool, TRUE);
2330 if (ptd)
2331 free_td(&uhci->td_pool, ptd);
2332 unlock_td_pool(&uhci->td_pool, TRUE);
2333
2334 InitializeListHead(&urb->trasac_list);
2335 usb_endp_busy_count_dec(urb->pendp);
2336 urb->pendp->flags = (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | ((toggle ^ 1) << 31);
2337 uhci_claim_bandwidth(uhci, urb, FALSE);
2338 return STATUS_UNSUCCESSFUL;
2339 }
2340
2341 return STATUS_SUCCESS;
2342 }
2343
2344
2345 NTSTATUS
2346 uhci_internal_submit_iso(PUHCI_DEV uhci, PURB urb)
2347 {
2348 PUHCI_TD ptd;
2349 LIST_ENTRY td_list, *pthis, *pnext;
2350 int i;
2351 BOOLEAN toggle = FALSE, ret;
2352
2353 if (uhci == NULL || urb == NULL)
2354 return STATUS_INVALID_PARAMETER;
2355
2356 if (urb->iso_frame_count == 0)
2357 return STATUS_INVALID_PARAMETER;
2358
2359 lock_td_pool(&uhci->td_pool, TRUE);
2360
2361 if (can_transfer(&uhci->td_pool, urb->iso_frame_count) == FALSE)
2362 {
2363 unlock_td_pool(&uhci->td_pool, TRUE);
2364 return STATUS_NO_MORE_ENTRIES;
2365 }
2366
2367 ptd = alloc_tds(&uhci->td_pool, urb->iso_frame_count);
2368 unlock_td_pool(&uhci->td_pool, TRUE);
2369
2370 if (ptd == NULL)
2371 {
2372 return STATUS_UNSUCCESSFUL;
2373 }
2374
2375 InsertTailList(&ptd->ptde->vert_link, &td_list);
2376 ListFirst(&td_list, pthis);
2377
2378 urb->td_count = urb->iso_frame_count;
2379
2380 urb->pipe = (((ULONG) urb->iso_packet_desc[0].length) << 21)
2381 | ((ULONG) endp_num(urb->pendp) << 15)
2382 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr) << 8)
2383 | ((ULONG) endp_dir(urb->pendp)) | USB_ENDPOINT_XFER_ISOC;
2384
2385
2386 for(i = 0; i < urb->iso_frame_count && pthis; i++)
2387 {
2388 ptd = ((PTD_EXTENSION) pthis)->ptd;
2389 uhci_fill_td(ptd,
2390 (3 << TD_CTRL_C_ERR_SHIFT)
2391 | (TD_CTRL_ACTIVE)
2392 | (TD_CTRL_IOS),
2393 (((ULONG) urb->iso_packet_desc[i].length - 1) << 21)
2394 | (0 << 19)
2395 | ((ULONG) endp_num(urb->pendp) << 15)
2396 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr) << 8)
2397 | ((urb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN)
2398 ? USB_PID_OUT : USB_PID_IN),
2399 MmGetPhysicalAddress(&urb->data_buffer[urb->iso_packet_desc[i].offset]).LowPart);
2400
2401 toggle ^= 1;
2402 ListNext(&td_list, pthis, pnext);
2403 pthis = pnext;
2404 }
2405
2406 ptd->status |= TD_CTRL_IOC; //need interrupt
2407
2408 ListFirst(&td_list, pthis);
2409 RemoveEntryList(&td_list);
2410
2411 InsertTailList(pthis, &urb->trasac_list);
2412
2413 //indirectly guarded by pending_endp_list_lock
2414 if (uhci_claim_bandwidth(uhci, urb, TRUE) == FALSE)
2415 {
2416 //bad news: we can not allocate the enough bandwidth for the urb
2417 RemoveEntryList(&urb->trasac_list);
2418 InitializeListHead(&urb->trasac_list);
2419
2420 lock_td_pool(&uhci->td_pool, TRUE);
2421 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2422 unlock_td_pool(&uhci->td_pool, TRUE);
2423 return STATUS_NO_MORE_ENTRIES;
2424
2425 }
2426
2427 usb_endp_busy_count_inc(urb->pendp);
2428 uhci_insert_urb_to_schedule(uhci, urb, ret);
2429 if (ret == FALSE)
2430 {
2431 usb_endp_busy_count_dec(urb->pendp);
2432 RemoveEntryList(&urb->trasac_list);
2433
2434 lock_td_pool(&uhci->td_pool, TRUE);
2435 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2436 unlock_td_pool(&uhci->td_pool, TRUE);
2437 uhci_claim_bandwidth(uhci, urb, FALSE);
2438 return STATUS_UNSUCCESSFUL;
2439 }
2440
2441 return STATUS_SUCCESS;
2442 }
2443
2444 // runs in uhci_isr
2445 BOOLEAN
2446 uhci_is_xfer_finished(PURB urb)
2447 {
2448 PLIST_ENTRY pthis, pnext;
2449 PUHCI_TD ptd;
2450 BOOLEAN ret = TRUE;
2451 PTD_EXTENSION ptde;
2452
2453 if (urb->last_finished_td == NULL)
2454 {
2455 urb->last_finished_td = &urb->trasac_list;
2456 }
2457
2458 if (&urb->trasac_list == urb->last_finished_td)
2459 ListFirst(&urb->trasac_list, pthis)
2460 else
2461 ListNext(&urb->trasac_list, urb->last_finished_td, pthis);
2462
2463 while (pthis)
2464 {
2465 if ((((PTD_EXTENSION) pthis)->flags & UHCI_ITEM_FLAG_TYPE) != UHCI_ITEM_FLAG_TD)
2466 {
2467 ListNext(&urb->trasac_list, pthis, pnext);
2468 pthis = pnext;
2469 continue;
2470 }
2471 else
2472 {
2473 ptde = (PTD_EXTENSION) pthis;
2474 ptd = ptde->ptd;
2475 ASSERT(ptd != NULL);
2476
2477 if (ptd->status & TD_CTRL_ACTIVE)
2478 {
2479 //still active
2480 ret = FALSE;
2481 break;
2482 }
2483 //let's see whether error occured
2484 if ((ptd->status & TD_CTRL_ANY_ERROR) == 0)
2485 {
2486 urb->last_finished_td = pthis;
2487 ListNext(&urb->trasac_list, pthis, pnext);
2488 pthis = pnext;
2489 continue;
2490 }
2491 else
2492 {
2493 urb->status = ptd->status;
2494 pthis = NULL;
2495 continue;
2496 }
2497 }
2498
2499 }
2500
2501 if (pthis == NULL)
2502 ret = TRUE;
2503
2504 return ret;
2505 }
2506
2507 // executed in isr, and have frame_list_lock acquired, so
2508 // never try to acquire any spin-lock
2509 // remove the bulk urb from schedule, and mark it not in
2510 // the schedule
2511 BOOLEAN
2512 uhci_remove_urb_from_schedule(PUHCI_DEV uhci, PURB urb)
2513 {
2514 BOOLEAN ret = FALSE;
2515 {
2516 switch (urb->pipe & USB_ENDPOINT_XFERTYPE_MASK)
2517 {
2518 case USB_ENDPOINT_XFER_BULK:
2519 {
2520 ret = uhci_remove_bulk_from_schedule(uhci, urb);
2521 break;
2522 }
2523 case USB_ENDPOINT_XFER_CONTROL:
2524 {
2525 ret = uhci_remove_ctrl_from_schedule(uhci, urb);
2526 break;
2527 }
2528 case USB_ENDPOINT_XFER_INT:
2529 {
2530 ret = uhci_remove_int_from_schedule(uhci, urb);
2531 break;
2532 }
2533 case USB_ENDPOINT_XFER_ISOC:
2534 {
2535 ret = uhci_remove_iso_from_schedule(uhci, urb);
2536 break;
2537 }
2538 }
2539 }
2540 return ret;
2541 }
2542
2543 // executed in isr, and have frame_list_lock acquired, so
2544 // never try to acquire any spin-lock
2545 // remove the bulk urb from schedule, and mark it not in
2546 // the schedule
2547 BOOLEAN
2548 uhci_remove_bulk_from_schedule(PUHCI_DEV uhci, PURB urb)
2549 {
2550
2551 PUHCI_QH pqh, pnext_qh, pprev_qh;
2552 PLIST_ENTRY pthis, pnext, pprev;
2553 LONG i;
2554
2555 if (uhci == NULL || urb == NULL)
2556 return FALSE;
2557
2558 ListFirst(&urb->trasac_list, pthis);
2559 pqh = ((PQH_EXTENSION) pthis)->pqh;
2560
2561 ListFirst(&pqh->pqhe->hori_link, pnext);
2562 ListFirstPrev(&pqh->pqhe->hori_link, pprev);
2563
2564 if (pprev == NULL || pnext == NULL)
2565 return FALSE;
2566
2567 pnext_qh = struct_ptr(pnext, QH_EXTENSION, hori_link)->pqh;
2568 pprev_qh = struct_ptr(pprev, QH_EXTENSION, hori_link)->pqh;
2569
2570 if (pprev != pnext)
2571 {
2572 //not the last one
2573 pprev_qh->link = pnext_qh->phy_addr;
2574 }
2575 else
2576 {
2577 //only two qhs in the list
2578 for(i = 0; i < UHCI_MAX_SKELQHS; i++)
2579 {
2580 if (pprev_qh == uhci->skel_qh[i])
2581 {
2582 break;
2583 }
2584 }
2585 ASSERT(i < UHCI_MAX_SKELQHS - 1);
2586 pprev_qh->link = uhci->skel_qh[i + 1]->phy_addr;
2587 }
2588 RemoveEntryList(&pqh->pqhe->hori_link);
2589
2590 urb->flags &= ~URB_FLAG_IN_SCHEDULE;
2591
2592 if ((urb->pipe & USB_DEV_FLAG_LOW_SPEED) == 0)
2593 uhci_drop_fsbr(uhci);
2594
2595 return TRUE;
2596 }
2597
2598 BOOLEAN
2599 uhci_remove_iso_from_schedule(PUHCI_DEV uhci, PURB urb)
2600 {
2601 PUHCI_TD ptd, pprev_td;
2602 PLIST_ENTRY pthis, pnext, pprev;
2603 int i, idx;
2604
2605 if (uhci == NULL || urb == NULL)
2606 return FALSE;
2607
2608 ListFirst(&urb->trasac_list, pthis);
2609
2610 for(i = 0; i < urb->iso_frame_count && pthis; i++)
2611 {
2612 ptd = ((PTD_EXTENSION) pthis)->ptd;
2613 idx = (urb->iso_start_frame + i) & (UHCI_MAX_FRAMES - 1);
2614
2615 ListFirstPrev(&ptd->ptde->hori_link, pprev);
2616
2617 if (pprev == NULL)
2618 return FALSE;
2619
2620 if (pprev == &uhci->frame_list_cpu[idx].td_link)
2621 {
2622 uhci->frame_list[idx] = ptd->link;
2623 }
2624 else
2625 {
2626 pprev_td = struct_ptr(pprev, TD_EXTENSION, hori_link)->ptd;
2627 pprev_td->link = ptd->link;
2628 }
2629
2630 RemoveEntryList(&ptd->ptde->hori_link);
2631 ListNext(&urb->trasac_list, pthis, pnext);
2632 pthis = pnext;
2633 }
2634
2635 urb->flags &= ~URB_FLAG_IN_SCHEDULE;
2636 return TRUE;
2637 }
2638
2639 BOOLEAN
2640 uhci_remove_int_from_schedule(PUHCI_DEV uhci, PURB urb)
2641 {
2642 PUHCI_TD ptd, pnext_td, pprev_td;
2643 PLIST_ENTRY pthis, pnext, pprev;
2644 LONG i;
2645
2646 if (uhci == NULL || urb == NULL)
2647 return FALSE;
2648
2649 ListFirst(&urb->trasac_list, pthis);
2650 ptd = ((PTD_EXTENSION) pthis)->ptd;
2651 ListFirst(&ptd->ptde->hori_link, pnext);
2652 ListFirstPrev(&ptd->ptde->hori_link, pprev);
2653
2654 if (pprev == NULL || pnext == NULL)
2655 return FALSE;
2656
2657 pnext_td = struct_ptr(pnext, TD_EXTENSION, hori_link)->ptd;
2658 pprev_td = struct_ptr(pprev, TD_EXTENSION, hori_link)->ptd;
2659
2660 if (pprev_td != pnext_td)
2661 pprev_td->link = pnext_td->phy_addr;
2662 else
2663 {
2664 //the last one
2665 for(i = UHCI_MAX_SKELTDS - 2; i >= 0; i--)
2666 {
2667 //UHCI_MAX_SKELTDS -1 skel tds for int transfer
2668 if (pprev_td == uhci->skel_td[i])
2669 break;
2670 }
2671
2672 ASSERT(i >= 0);
2673 if (i == 0)
2674 {
2675 pprev_td->link = uhci->skel_qh[0]->phy_addr;
2676 }
2677 else
2678 {
2679 pprev_td->link = uhci->skel_td[i - 1]->phy_addr;
2680 }
2681 }
2682 RemoveEntryList(&ptd->ptde->hori_link);
2683
2684 urb->flags &= ~URB_FLAG_IN_SCHEDULE;
2685 return TRUE;
2686 }
2687
2688 BOOLEAN
2689 uhci_insert_tds_qh(PUHCI_QH pqh, PUHCI_TD td_chain)
2690 {
2691 if (pqh == NULL || td_chain == NULL)
2692 return FALSE;
2693
2694 InsertTailList(&td_chain->ptde->vert_link, &pqh->pqhe->vert_link);
2695 pqh->element = td_chain->phy_addr;
2696 return TRUE;
2697 }
2698
2699 BOOLEAN
2700 uhci_insert_qh_urb(PURB urb, PUHCI_QH qh_chain)
2701 {
2702 if (urb == NULL || qh_chain == NULL)
2703 return FALSE;
2704
2705 InsertTailList(&qh_chain->pqhe->vert_link, &urb->trasac_list);
2706 qh_chain->pqhe->purb = urb;
2707 return TRUE;
2708 }
2709
2710 // must have dev_lock and frame_list_lock acquired
2711 BOOLEAN
2712 uhci_insert_urb_schedule(PUHCI_DEV uhci, PURB urb)
2713 {
2714 PUHCI_QH pqh, pskel_qh, pnext_qh;
2715 PUHCI_TD ptd, plast_td;
2716 PLIST_ENTRY pthis, pnext;
2717 int i;
2718
2719 if (uhci == NULL || urb == NULL)
2720 return FALSE;
2721
2722 ListFirst(&urb->trasac_list, pthis);
2723 if (pthis == NULL)
2724 return FALSE;
2725
2726 InsertTailList(&uhci->urb_list, &urb->urb_link);
2727
2728 urb->flags &= ~URB_FLAG_STATE_MASK;
2729 urb->flags |= URB_FLAG_STATE_IN_PROCESS | URB_FLAG_IN_SCHEDULE;
2730
2731
2732 switch (endp_type(urb->pendp))
2733 {
2734 case USB_ENDPOINT_XFER_CONTROL:
2735 {
2736 pqh = ((PQH_EXTENSION) pthis)->pqh;
2737
2738 if ((dev_from_endp(urb->pendp)->flags & USB_DEV_FLAG_LOW_SPEED) == 0)
2739 {
2740 pskel_qh = uhci->skel_hs_control_qh;
2741 pnext_qh = uhci->skel_bulk_qh;
2742 }
2743 else
2744 {
2745 pskel_qh = uhci->skel_ls_control_qh;
2746 pnext_qh = uhci->skel_hs_control_qh;
2747 }
2748
2749 ListFirstPrev(&pskel_qh->pqhe->hori_link, pthis);
2750
2751 if (pthis == NULL)
2752 pthis = &pskel_qh->pqhe->hori_link;
2753
2754 InsertTailList(&pskel_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
2755 pqh->link = pnext_qh->phy_addr;
2756 struct_ptr(pthis, QH_EXTENSION, hori_link)->pqh->link = pqh->phy_addr;
2757
2758 //full speed band reclaimation
2759 if ((urb->pipe & USB_DEV_FLAG_LOW_SPEED) == 0)
2760 {
2761 uhci->fsbr_cnt++;
2762 if (uhci->fsbr_cnt == 1)
2763 {
2764 uhci->skel_term_qh->link = uhci->skel_hs_control_qh->phy_addr;
2765 }
2766 }
2767 return TRUE;
2768 }
2769 case USB_ENDPOINT_XFER_BULK:
2770 {
2771 pqh = ((PQH_EXTENSION) pthis)->pqh;
2772
2773 ListFirstPrev(&uhci->skel_bulk_qh->pqhe->hori_link, pthis);
2774
2775 if (pthis == NULL)
2776 pthis = &uhci->skel_bulk_qh->pqhe->hori_link;
2777
2778 InsertTailList(&uhci->skel_bulk_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
2779
2780 pqh->link = uhci->skel_term_qh->phy_addr;
2781 struct_ptr(pthis, QH_EXTENSION, hori_link)->pqh->link = pqh->phy_addr;
2782
2783 //full speed band reclaimation
2784 uhci->fsbr_cnt++;
2785 if (uhci->fsbr_cnt == 1)
2786 {
2787 uhci->skel_term_qh->link = uhci->skel_hs_control_qh->phy_addr;
2788 }
2789
2790 return TRUE;
2791 }
2792 case USB_ENDPOINT_XFER_INT:
2793 {
2794 //bandwidth claim is done outside
2795 ptd = ((PTD_EXTENSION) pthis)->ptd;
2796
2797 get_int_idx(urb, i);
2798
2799 ListFirstPrev(&uhci->skel_td[i]->ptde->hori_link, pthis);
2800 if (pthis == NULL)
2801 pthis = &uhci->skel_td[i]->ptde->hori_link;
2802
2803 InsertTailList(&uhci->skel_td[i]->ptde->hori_link, &ptd->ptde->hori_link);
2804
2805 if (i > 0)
2806 {
2807 ptd->link = uhci->skel_td[i - 1]->phy_addr;
2808 }
2809 else if (i == 0)
2810 {
2811 ptd->link = uhci->skel_qh[0]->phy_addr;
2812 }
2813 //finally link the previous td to this td
2814 struct_ptr(pthis, TD_EXTENSION, hori_link)->ptd->link = ptd->phy_addr;
2815 return TRUE;
2816 }
2817 case USB_ENDPOINT_XFER_ISOC:
2818 {
2819
2820 for(i = 0; i < urb->iso_frame_count; i++)
2821 {
2822 ptd = ((PTD_EXTENSION) pthis)->ptd;
2823 InsertTailList(&uhci->frame_list_cpu[(urb->iso_start_frame + i) & 0x3ff].td_link,
2824 &ptd->ptde->hori_link);
2825
2826 if (IsListEmpty(&uhci->frame_list_cpu[(urb->iso_start_frame + i) & 0x3ff].td_link) == TRUE)
2827 {
2828 ptd->link = uhci->frame_list[(urb->iso_start_frame + i) & 0x3ff];
2829 uhci->frame_list[i] = ptd->phy_addr;
2830 }
2831 else
2832 {
2833 ListFirstPrev(&uhci->frame_list_cpu[(urb->iso_start_frame + i) & 0x3ff].td_link, pnext);
2834 plast_td = struct_ptr(pnext, TD_EXTENSION, hori_link)->ptd;
2835 ptd->link = plast_td->link;
2836 plast_td->link = ptd->phy_addr;
2837 }
2838
2839 ListNext(&urb->trasac_list, pthis, pnext);
2840 pthis = pnext;
2841 }
2842 return TRUE;
2843
2844 }
2845 }
2846 return FALSE;
2847 }
2848
2849 //this function used as the KeSynchronizeExecution param to delegate control to uhci_insert_urb_schedule
2850 BOOLEAN NTAPI
2851 uhci_sync_insert_urb_schedule(PVOID context)
2852 {
2853 PSYNC_PARAM sync_param;
2854 PUHCI_DEV uhci;
2855 PURB purb;
2856
2857 sync_param = (PSYNC_PARAM) context;
2858 if (sync_param == NULL)
2859 return FALSE;
2860
2861 uhci = sync_param->uhci;
2862 purb = (PURB) sync_param->context;
2863
2864 if (uhci == NULL || purb == NULL)
2865 return (UCHAR) (sync_param->ret = FALSE);
2866
2867 return (UCHAR) (sync_param->ret = uhci_insert_urb_schedule(uhci, purb));
2868 }
2869
2870 // be sure pending_endp_list_lock acquired
2871 BOOLEAN
2872 uhci_claim_bandwidth(PUHCI_DEV uhci,
2873 PURB urb,
2874 BOOLEAN claim_bw //true to claim bandwidth, false to free bandwidth
2875 )
2876 {
2877
2878 UCHAR type;
2879 BOOLEAN ls, can_alloc;
2880 LONG bus_time, us;
2881 LONG i, idx, j, start_frame, interval;
2882
2883 if (urb == NULL)
2884 return FALSE;
2885
2886 can_alloc = TRUE;
2887
2888 type = (UCHAR) (urb->pipe & USB_ENDPOINT_XFERTYPE_MASK);
2889 if (type == USB_ENDPOINT_XFER_BULK || type == USB_ENDPOINT_XFER_CONTROL)
2890 {
2891 return FALSE;
2892 }
2893
2894 ls = (urb->pipe & USB_DEV_FLAG_LOW_SPEED) ? TRUE : FALSE;
2895
2896 if (type == USB_ENDPOINT_XFER_INT)
2897 {
2898 start_frame = 0;
2899 i = urb->data_length;
2900 bus_time = usb_calc_bus_time(ls, FALSE, FALSE, i);
2901 us = ns_to_us(bus_time);
2902
2903 i = (urb->pipe >> 24); //polling interval
2904
2905 for(interval = 0, j = 0; j < 8; j++)
2906 {
2907 if (i & (1 << j))
2908 {
2909 interval = j;
2910 }
2911 }
2912
2913 interval = 1 << interval;
2914 start_frame = interval - 1;
2915
2916 if (claim_bw)
2917 {
2918
2919 for(idx = 0; idx < UHCI_MAX_FRAMES; idx += interval)
2920 {
2921 if (uhci->frame_bw[idx] < us)
2922 {
2923 can_alloc = FALSE;
2924 break;
2925 }
2926 }
2927
2928 if (!can_alloc)
2929 {
2930 return FALSE;
2931 }
2932
2933 for(idx = start_frame; idx < UHCI_MAX_FRAMES; idx += interval)
2934 {
2935 uhci->frame_bw[idx] -= us;
2936 }
2937 }
2938 else
2939 {
2940 for(idx = start_frame; idx < UHCI_MAX_FRAMES; idx += interval)
2941 {
2942 uhci->frame_bw[idx] += us;
2943 }
2944 }
2945
2946 }
2947 else if (type == USB_ENDPOINT_XFER_ISOC)
2948 {
2949 if (claim_bw)
2950 {
2951 for(i = 0; i < urb->iso_frame_count; i++)
2952 {
2953 bus_time = usb_calc_bus_time(FALSE,
2954 (urb->pipe & USB_DIR_IN)
2955 ? TRUE : FALSE, TRUE, urb->iso_packet_desc[i].length);
2956
2957 urb->iso_packet_desc[i].bus_time = ns_to_us(bus_time);
2958 }
2959
2960 for(i = 0; i < urb->iso_frame_count; i++)
2961 {
2962 if (uhci->frame_bw[(urb->iso_start_frame + i) & 0x3ff] < urb->iso_packet_desc[i].bus_time)
2963 {
2964 can_alloc = FALSE;
2965 break;
2966 }
2967 }
2968
2969 if (!can_alloc)
2970 {
2971 return FALSE;
2972 }
2973
2974 for(i = 0; i < urb->iso_frame_count; i++)
2975 {
2976 uhci->frame_bw[(urb->iso_start_frame + i) & 0x3ff] -= urb->iso_packet_desc[i].bus_time;
2977 }
2978 }
2979 else
2980 {
2981 for(i = 0; i < urb->iso_frame_count; i++)
2982 {
2983 uhci->frame_bw[(urb->iso_start_frame + i) & 0x3ff] += urb->iso_packet_desc[i].bus_time;
2984 }
2985 }
2986
2987 }
2988
2989 return TRUE;
2990 }
2991
2992
2993 //cancel a single urb
2994 BOOLEAN NTAPI
2995 uhci_sync_cancel_urb(PVOID context)
2996 {
2997 PUHCI_DEV uhci;
2998 PSYNC_PARAM sync_param;
2999 PURB purb2, dest_urb;
3000 PLIST_ENTRY pthis, pnext;
3001 BOOLEAN found = FALSE;
3002
3003 if (context == NULL)
3004 return FALSE;
3005
3006 sync_param = (PSYNC_PARAM) context;
3007 uhci = sync_param->uhci;
3008 dest_urb = (PURB) sync_param->context;
3009
3010 if (uhci == NULL || dest_urb == NULL)
3011 return (UCHAR) (sync_param->ret = FALSE);
3012
3013 ListFirst(&uhci->urb_list, pthis);
3014 while (pthis)
3015 {
3016 purb2 = (PURB) pthis;
3017 if (purb2 == dest_urb)
3018 {
3019 found = TRUE;
3020 purb2->flags |= URB_FLAG_FORCE_CANCEL;
3021 break;
3022 }
3023 ListNext(&uhci->urb_list, pthis, pnext);
3024 pthis = pnext;
3025 }
3026 if (found)
3027 uhci->skel_term_td->status |= TD_CTRL_IOC;
3028
3029 return (UCHAR) (sync_param->ret = found);
3030 }
3031
3032 //note any fields of the purb can not be referenced unless it is found in some queue
3033 NTSTATUS
3034 uhci_cancel_urb(PUHCI_DEV uhci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
3035 {
3036 PLIST_ENTRY pthis, pnext;
3037 BOOLEAN found;
3038 PURB purb2;
3039
3040 SYNC_PARAM sync_param;
3041
3042 USE_BASIC_NON_PENDING_IRQL;
3043
3044 if (uhci == NULL || purb == NULL || pdev == NULL || pendp == NULL)
3045 return STATUS_INVALID_PARAMETER;
3046
3047 lock_dev(pdev, FALSE);
3048
3049 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
3050 {
3051 unlock_dev(pdev, FALSE);
3052 //delegate to remove device for this job
3053 return STATUS_DEVICE_DOES_NOT_EXIST;
3054 }
3055
3056 if (dev_from_endp(pendp) != pdev)
3057 {
3058 unlock_dev(pdev, FALSE);
3059 return STATUS_INVALID_PARAMETER;
3060 }
3061
3062 if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
3063 {
3064 //it will be canceled in uhci_process_pending_endp
3065 unlock_dev(pdev, FALSE);
3066 return USB_STATUS_ENDPOINT_HALTED;
3067 }
3068
3069 found = FALSE;
3070 ListFirst(&pendp->urb_list, pthis);
3071 while (pthis)
3072 {
3073 purb2 = (PURB) pthis;
3074 if (purb2 == purb)
3075 {
3076 found = TRUE;
3077 RemoveEntryList(pthis);
3078 InitializeListHead(pthis);
3079 break;
3080 }
3081 ListNext(&pendp->urb_list, pthis, pnext);
3082 pthis = pnext;
3083 }
3084 unlock_dev(pdev, FALSE);
3085
3086 if (found)
3087 {
3088 purb->status = STATUS_CANCELLED;
3089
3090 uhci_generic_urb_completion(purb, purb->context);
3091
3092 lock_dev(pdev, FALSE);
3093 pdev->ref_count--;
3094 unlock_dev(pdev, FALSE);
3095 return STATUS_SUCCESS;
3096 }
3097
3098 // search the urb in the urb-list and try to cancel
3099 sync_param.uhci = uhci;
3100 sync_param.context = purb;
3101
3102 KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_cancel_urb, &sync_param);
3103
3104 found = (BOOLEAN) sync_param.ret;
3105
3106 if (found)
3107 return USB_STATUS_CANCELING;
3108
3109 return STATUS_INVALID_PARAMETER;
3110 }
3111
3112 VOID
3113 uhci_generic_urb_completion(PURB purb, PVOID context)
3114 {
3115 PUSB_DEV pdev;
3116 USE_NON_PENDING_IRQL;
3117
3118 old_irql = KeGetCurrentIrql();
3119 if (old_irql > DISPATCH_LEVEL)
3120 TRAP();
3121
3122 if (old_irql < DISPATCH_LEVEL)
3123 KeRaiseIrql(DISPATCH_LEVEL, &old_irql);
3124
3125 if (purb == NULL)
3126 return;
3127
3128 pdev = purb->pdev;
3129
3130 if (pdev == NULL)
3131 return;
3132
3133 lock_dev(pdev, TRUE);
3134
3135 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
3136 {
3137 unlock_dev(pdev, TRUE);
3138 goto LBL_CLIENT_PROCESS;
3139 }
3140 if (usb_error(purb->status))
3141 {
3142 pdev->error_count++;
3143 }
3144
3145 if (purb->pendp == &pdev->default_endp)
3146 {
3147 if (usb_halted(purb->status))
3148 {
3149 pdev->time_out_count++;
3150 if (pdev->time_out_count > 3)
3151 {
3152 dev_set_state(pdev, USB_DEV_STATE_ZOMB);
3153 uhci_dbg_print(DBGLVL_MAXIMUM,
3154 ("uhci_generic_urb_completion(): contiguous error 3 times, dev 0x%x is deactivated\n",
3155 pdev));
3156 }
3157 }
3158 else
3159 pdev->time_out_count = 0;
3160
3161 }
3162 unlock_dev(pdev, TRUE);
3163
3164 LBL_CLIENT_PROCESS:
3165 if (purb->completion)
3166 purb->completion(purb, context);
3167
3168 if (old_irql < DISPATCH_LEVEL)
3169 KeLowerIrql(old_irql);
3170
3171 return;
3172 }
3173
3174
3175 NTSTATUS
3176 uhci_rh_submit_urb(PUSB_DEV pdev, PURB purb)
3177 {
3178 PUSB_DEV_MANAGER dev_mgr;
3179 PTIMER_SVC ptimer;
3180 PUSB_CTRL_SETUP_PACKET psetup;
3181 PUHCI_DEV uhci;
3182 NTSTATUS status;
3183 USHORT port_status;
3184 #ifndef INCLUDE_EHCI
3185 PHUB_EXTENSION hub_ext;
3186 #else
3187 PHUB2_EXTENSION hub_ext;
3188 #endif
3189 PUSB_PORT_STATUS ps, psret;
3190 LONG i;
3191 USE_NON_PENDING_IRQL;
3192
3193 if (pdev == NULL || purb == NULL)
3194 return STATUS_INVALID_PARAMETER;
3195
3196 dev_mgr = dev_mgr_from_dev(pdev);
3197
3198 KeAcquireSpinLock(&dev_mgr->timer_svc_list_lock, &old_irql);
3199 lock_dev(pdev, FALSE);
3200 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
3201 {
3202 unlock_dev(pdev, FALSE);
3203 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
3204 return STATUS_DEVICE_DOES_NOT_EXIST;
3205 }
3206
3207 uhci = uhci_from_hcd(pdev->hcd);
3208 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
3209
3210 #ifndef INCLUDE_EHCI
3211 hub_ext = ((PHUB_EXTENSION) pdev->dev_ext);
3212 #else
3213 hub_ext = ((PHUB2_EXTENSION) pdev->dev_ext);
3214 #endif
3215
3216 switch (endp_type(purb->pendp))
3217 {
3218 case USB_ENDPOINT_XFER_CONTROL:
3219 {
3220 if (psetup->bmRequestType == 0xa3 && psetup->bRequest == USB_REQ_GET_STATUS)
3221 {
3222 //get-port-status
3223 if (psetup->wIndex == 0 || psetup->wIndex > 2 || psetup->wLength < 4)
3224 {
3225 purb->status = STATUS_INVALID_PARAMETER;
3226 break;
3227 }
3228 if (psetup->wIndex == 1)
3229 {
3230 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBPORTSC1));
3231 ps = &hub_ext->rh_port1_status;
3232 }
3233 else
3234 {
3235 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBPORTSC2));
3236 ps = &hub_ext->rh_port2_status;
3237 }
3238
3239 psret = (PUSB_PORT_STATUS) purb->data_buffer;
3240 ps->wPortStatus = 0;
3241
3242 if (status & USBPORTSC_CCS)
3243 {
3244 ps->wPortStatus |= USB_PORT_STAT_CONNECTION;
3245 }
3246 if (status & USBPORTSC_PE)
3247 {
3248 ps->wPortStatus |= USB_PORT_STAT_ENABLE;
3249 }
3250 if (status & USBPORTSC_PR)
3251 {
3252 ps->wPortStatus |= USB_PORT_STAT_RESET;
3253 }
3254 if (status & USBPORTSC_SUSP)
3255 {
3256 ps->wPortStatus |= USB_PORT_STAT_SUSPEND;
3257 }
3258 if (status & USBPORTSC_LSDA)
3259 {
3260 ps->wPortStatus |= USB_PORT_STAT_LOW_SPEED;
3261 }
3262
3263 //always power on
3264 ps->wPortStatus |= USB_PORT_STAT_POWER;
3265
3266 //now set change field
3267 if (status & USBPORTSC_CSC)
3268 {
3269 ps->wPortChange |= USB_PORT_STAT_C_CONNECTION;
3270 }
3271 if (status & USBPORTSC_PEC)
3272 {
3273 ps->wPortChange |= USB_PORT_STAT_C_ENABLE;
3274 }
3275
3276 //don't touch other fields, will be filled by
3277 //other function
3278
3279 usb_dbg_print(DBGLVL_MAXIMUM,
3280 ("uhci_rh_submit_urb(): get port status, wPortStatus=0x%x, wPortChange=0x%x, address=0x%x\n",
3281 ps->wPortStatus, ps->wPortChange, ps));
3282
3283 psret->wPortChange = ps->wPortChange;
3284 psret->wPortStatus = ps->wPortStatus;
3285
3286 purb->status = STATUS_SUCCESS;
3287
3288 break;
3289 }
3290 else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_CLEAR_FEATURE)
3291 {
3292 //clear-port-feature
3293 if (psetup->wIndex == 0 || psetup->wIndex > 2)
3294 {
3295 purb->status = STATUS_INVALID_PARAMETER;
3296 break;
3297 }
3298 if (psetup->wIndex == 1)
3299 {
3300 i = USBPORTSC1;
3301 ps = &hub_ext->rh_port1_status;
3302 }
3303 else
3304 {
3305 i = USBPORTSC2;
3306 ps = &hub_ext->rh_port2_status;
3307 }
3308
3309 purb->status = STATUS_SUCCESS;
3310 switch (psetup->wValue)
3311 {
3312 case USB_PORT_FEAT_C_CONNECTION:
3313 {
3314 ps->wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
3315 SET_RH_PORTSTAT(i, USBPORTSC_CSC);
3316 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + i));
3317 usb_dbg_print(DBGLVL_MAXIMUM,
3318 ("uhci_rh_submit_urb(): clear csc, port%d=0x%x\n", psetup->wIndex,
3319 status));
3320 break;
3321 }
3322 case USB_PORT_FEAT_C_ENABLE:
3323 {
3324 ps->wPortChange &= ~USB_PORT_STAT_C_ENABLE;
3325 SET_RH_PORTSTAT(i, USBPORTSC_PEC);
3326 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + i));
3327 usb_dbg_print(DBGLVL_MAXIMUM,
3328 ("uhci_rh_submit_urb(): clear pec, port%d=0x%x\n", psetup->wIndex,
3329 status));
3330 break;
3331 }
3332 case USB_PORT_FEAT_C_RESET:
3333 {
3334 ps->wPortChange &= ~USB_PORT_STAT_C_RESET;
3335 //the reset signal is down in rh_timer_svc_reset_port_completion
3336 //so enable the port here
3337 status = READ_PORT_USHORT((PUSHORT)(uhci->port_base + i));
3338 usb_dbg_print(DBGLVL_MAXIMUM,
3339 ("uhci_rh_submit_urb(): clear pr, enable pe, port%d=0x%x\n",
3340 psetup->wIndex, status));
3341 break;
3342 }
3343 case USB_PORT_FEAT_ENABLE:
3344 {
3345 ps->wPortStatus &= ~USB_PORT_STAT_ENABLE;
3346 CLR_RH_PORTSTAT(i, USBPORTSC_PE);
3347 status = READ_PORT_USHORT((PUSHORT)(uhci->port_base + i));
3348 usb_dbg_print(DBGLVL_MAXIMUM,
3349 ("uhci_rh_submit_urb(): clear pe, port%d=0x%x\n", psetup->wIndex,
3350 status));
3351 break;
3352 }
3353 default:
3354 purb->status = STATUS_UNSUCCESSFUL;
3355 }
3356 break;
3357 }
3358 else if (psetup->bmRequestType == 0xd3 && psetup->bRequest == HUB_REQ_GET_STATE)
3359 {
3360 // get bus state
3361 if (psetup->wIndex == 0 || psetup->wIndex > 2 || psetup->wLength == 0)
3362 {
3363 purb->status = STATUS_INVALID_PARAMETER;
3364 break;
3365 }
3366
3367 if (psetup->wIndex == 1)
3368 {
3369 i = USBPORTSC1;
3370 }
3371 else
3372 {
3373 i = USBPORTSC2;
3374 }
3375 port_status = READ_PORT_USHORT((PUSHORT)(uhci->port_base + i));
3376 purb->data_buffer[0] = (port_status & USBPORTSC_LS);
3377
3378 // reverse the order
3379 purb->data_buffer[0] ^= 0x3;
3380 purb->status = STATUS_SUCCESS;
3381 break;
3382 }
3383 else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_SET_FEATURE)
3384 {
3385 //reset port
3386 if (psetup->wValue != USB_PORT_FEAT_RESET)
3387 {
3388 purb->status = STATUS_INVALID_PARAMETER;
3389 uhci_dbg_print(DBGLVL_MAXIMUM,
3390 ("uhci_rh_submit_urb(): set feature with wValue=0x%x\n", psetup->wValue));
3391 break;
3392 }
3393 if (psetup->wIndex == 1)
3394 {
3395 i = USBPORTSC1;
3396 }
3397 else
3398 {
3399 i = USBPORTSC2;
3400 }
3401
3402 ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
3403 if (!ptimer)
3404 {
3405 purb->status = STATUS_NO_MEMORY;
3406 break;
3407 }
3408
3409 ptimer->threshold = 0; // within [ 50ms, 60ms ], one tick is 10 ms
3410 ptimer->context = (ULONG) purb;
3411 ptimer->pdev = pdev;
3412 ptimer->func = rh_timer_svc_reset_port_completion;
3413
3414 //start the timer
3415 pdev->ref_count += 2; //one for timer and one for urb
3416
3417 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + i));
3418 usb_dbg_print(DBGLVL_MAXIMUM,
3419 ("uhci_rh_submit_urb(): reset port, port%d=0x%x\n", psetup->wIndex, status));
3420 InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
3421 purb->status = STATUS_PENDING;
3422 }
3423 else
3424 {
3425 purb->status = STATUS_INVALID_PARAMETER;
3426 }
3427 break;
3428 }
3429 case USB_ENDPOINT_XFER_INT:
3430 {
3431 ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
3432 if (!ptimer)
3433 {
3434 purb->status = STATUS_NO_MEMORY;
3435 break;
3436 }
3437
3438 ptimer->threshold = RH_INTERVAL;
3439 ptimer->context = (ULONG) purb;
3440 ptimer->pdev = pdev;
3441 ptimer->func = rh_timer_svc_int_completion;
3442
3443 //start the timer
3444 InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
3445
3446 usb_dbg_print(DBGLVL_ULTRA,
3447 ("uhci_rh_submit_urb(): current rh's ref_count=0x%x\n", pdev->ref_count));
3448 pdev->ref_count += 2; //one for timer and one for urb
3449
3450 purb->status = STATUS_PENDING;
3451 break;
3452 }
3453 case USB_ENDPOINT_XFER_BULK:
3454 case USB_ENDPOINT_XFER_ISOC:
3455 default:
3456 {
3457 purb->status = STATUS_INVALID_PARAMETER;
3458 break;
3459 }
3460 }
3461 unlock_dev(pdev, FALSE);
3462 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
3463 return purb->status;
3464 }
3465
3466 //must have rh dev_lock acquired
3467 BOOLEAN
3468 uhci_rh_reset_port(PHCD hcd, UCHAR port_idx)
3469 {
3470 LONG i;
3471 PUHCI_DEV uhci;
3472 ULONG status;
3473
3474 if (port_idx != 1 && port_idx != 2)
3475 return FALSE;
3476
3477 if (hcd == NULL)
3478 return FALSE;
3479
3480 if (port_idx == 1)
3481 {
3482 i = USBPORTSC1;
3483 }
3484 else
3485 {
3486 i = USBPORTSC2;
3487 }
3488
3489 uhci = uhci_from_hcd(hcd);
3490 //assert the reset signal,(implicitly disable the port)
3491 SET_RH_PORTSTAT(i, USBPORTSC_PR);
3492 usb_wait_ms_dpc(50);
3493 //clear the reset signal, delay port enable till clearing port feature
3494 CLR_RH_PORTSTAT(i, USBPORTSC_PR);
3495 usb_wait_us_dpc(10);
3496 SET_RH_PORTSTAT(i, USBPORTSC_PE);
3497 //recovery time 10ms
3498 usb_wait_ms_dpc(10);
3499 SET_RH_PORTSTAT(i, 0x0a);
3500
3501 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + i));
3502 usb_dbg_print(DBGLVL_MAXIMUM, ("uhci_rh_reset_port(): status after written=0x%x\n", status));
3503
3504 return TRUE;
3505 }
3506
3507 NTSTATUS
3508 uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp)
3509 {
3510 PDEVICE_EXTENSION pdev_ext;
3511 PUSB_DEV_MANAGER dev_mgr;
3512 PUHCI_DEV uhci;
3513
3514 pdev_ext = DeviceObject->DeviceExtension;
3515 uhci = pdev_ext->uhci;
3516
3517 dev_mgr = uhci->hcd_interf.hcd_get_dev_mgr(&uhci->hcd_interf);
3518 return dev_mgr_dispatch(dev_mgr, irp);
3519 }
3520
3521 VOID NTAPI
3522 uhci_unload(IN PDRIVER_OBJECT DriverObject)
3523 {
3524 PDEVICE_OBJECT pdev;
3525 PDEVICE_EXTENSION pdev_ext;
3526 PUSB_DEV_MANAGER dev_mgr;
3527
3528 pdev = DriverObject->DeviceObject;
3529
3530 if (pdev == NULL)
3531 return;
3532
3533 pdev_ext = pdev->DeviceExtension;
3534 if (pdev_ext == NULL)
3535 return;
3536
3537 dev_mgr = &g_dev_mgr;
3538 if (dev_mgr == NULL)
3539 return;
3540 //
3541 // set the termination flag
3542 //
3543 dev_mgr->term_flag = TRUE;
3544
3545 //
3546 // wake up the thread if it is
3547 //
3548 KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE);
3549 KeWaitForSingleObject(dev_mgr->pthread, Executive, KernelMode, TRUE, NULL);
3550 ObDereferenceObject(dev_mgr->pthread);
3551 dev_mgr->pthread = NULL;
3552 // for( i = 0; i < dev_mgr->hcd_count; i++ )
3553 // dev_mgr->hcd_array[ i ]->hcd_release( dev_mgr->hcd_array[ i ]);
3554 dev_mgr_release_hcd(dev_mgr);
3555
3556 return;
3557 }
3558
3559 //the following are for hcd interface methods
3560 VOID
3561 uhci_set_dev_mgr(struct _HCD * hcd, PUSB_DEV_MANAGER dev_mgr)
3562 {
3563 hcd->dev_mgr = dev_mgr;
3564 }
3565
3566 PUSB_DEV_MANAGER
3567 uhci_get_dev_mgr(struct _HCD *hcd)
3568 {
3569 return hcd->dev_mgr;
3570 }
3571
3572 ULONG
3573 uhci_get_type(struct _HCD * hcd)
3574 {
3575 return (hcd->flags & HCD_TYPE_MASK);
3576 }
3577
3578 VOID
3579 uhci_set_id(struct _HCD * hcd, UCHAR id)
3580 {
3581 hcd->flags &= ~HCD_ID_MASK;
3582 hcd->flags |= (HCD_ID_MASK & id);
3583 }
3584
3585 UCHAR
3586 uhci_get_id(struct _HCD *hcd)
3587 {
3588 return (UCHAR) (hcd->flags & HCD_ID_MASK);
3589 }
3590
3591
3592 UCHAR
3593 uhci_alloc_addr(struct _HCD * hcd)
3594 {
3595 LONG i;
3596 if (hcd == NULL)
3597 return 0;
3598
3599 for(i = 1; i < MAX_DEVS; i++)
3600 {
3601 if (hcd->dev_addr_map[i >> 3] & (1 << (i & 7)))
3602 {
3603 continue;
3604 }
3605 else
3606 {
3607 break;
3608 }
3609 }
3610
3611 if (i >= MAX_DEVS)
3612 return 0xff;
3613
3614 hcd->dev_addr_map[i >> 3] |= (1 << (i & 7));
3615 hcd->conn_count++;
3616 return (BYTE) i;
3617 }
3618
3619 VOID
3620 uhci_free_addr(struct _HCD * hcd, UCHAR addr)
3621 {
3622 if (addr & 0x80)
3623 return;
3624
3625 if (hcd == NULL)
3626 return;
3627
3628 hcd->dev_addr_map[addr >> 3] &= ~(1 << (addr & 7));
3629 return;
3630
3631 }
3632
3633 NTSTATUS
3634 uhci_submit_urb2(struct _HCD * hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
3635 {
3636 return uhci_submit_urb(uhci_from_hcd(hcd), pdev, pendp, purb);
3637 }
3638
3639 PUSB_DEV
3640 uhci_get_root_hub(struct _HCD * hcd)
3641 {
3642 return uhci_from_hcd(hcd)->root_hub;
3643 }
3644
3645 VOID
3646 uhci_set_root_hub(struct _HCD * hcd, PUSB_DEV root_hub)
3647 {
3648 if (hcd == NULL || root_hub == NULL)
3649 return;
3650 uhci_from_hcd(hcd)->root_hub = root_hub;
3651 return;
3652 }
3653
3654 BOOLEAN
3655 uhci_remove_device2(struct _HCD * hcd, PUSB_DEV pdev)
3656 {
3657 if (hcd == NULL || pdev == NULL)
3658 return FALSE;
3659
3660 return uhci_remove_device(uhci_from_hcd(hcd), pdev);
3661 }
3662
3663 BOOLEAN
3664 uhci_hcd_release(struct _HCD * hcd)
3665 {
3666 PUHCI_DEV uhci;
3667 PDEVICE_EXTENSION pdev_ext;
3668
3669 if (hcd == NULL)
3670 return FALSE;
3671
3672
3673 uhci = uhci_from_hcd(hcd);
3674 pdev_ext = uhci->pdev_ext;
3675
3676 return uhci_release(pdev_ext->pdev_obj);
3677 }
3678
3679 NTSTATUS
3680 uhci_cancel_urb2(struct _HCD * hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
3681 {
3682 PUHCI_DEV uhci;
3683 if (hcd == NULL)
3684 return STATUS_INVALID_PARAMETER;
3685
3686 uhci = uhci_from_hcd(hcd);
3687 return uhci_cancel_urb(uhci, pdev, pendp, purb);
3688 }
3689
3690 BOOLEAN
3691 uhci_rh_get_dev_change(PHCD hcd, PBYTE buf)
3692 {
3693 PUHCI_DEV uhci;
3694 ULONG status;
3695
3696 if (hcd == NULL || buf == NULL)
3697 return FALSE;
3698
3699 uhci = uhci_from_hcd(hcd);
3700 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBPORTSC1));
3701 usb_dbg_print(DBGLVL_ULTRA, ("uhci_rh_get_dev_change(): rh port1 status=0x%x\n", status));
3702
3703 if ((status & USBPORTSC_PEC) || (status & USBPORTSC_CSC))
3704 {
3705 buf[0] |= (1 << 1);
3706 }
3707
3708 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBPORTSC2));
3709 usb_dbg_print(DBGLVL_ULTRA, ("uhci_rh_get_dev_change(): rh port2 status=0x%x\n", status));
3710
3711 if ((status & USBPORTSC_PEC) || (status & USBPORTSC_CSC))
3712 {
3713 buf[0] |= (1 << 2);
3714 }
3715 return TRUE;
3716 }
3717
3718 NTSTATUS
3719 uhci_dispatch(PHCD hcd, LONG disp_code, PVOID param) // locking depends on type of code
3720 {
3721 if (hcd == NULL)
3722 return FALSE;
3723
3724 switch (disp_code)
3725 {
3726 case HCD_DISP_READ_PORT_COUNT:
3727 {
3728 if (param == NULL)
3729 return STATUS_INVALID_PARAMETER;
3730 *((PUCHAR) param) = 2;
3731 return STATUS_SUCCESS;
3732 }
3733 case HCD_DISP_READ_RH_DEV_CHANGE:
3734 {
3735 if (uhci_rh_get_dev_change(hcd, param) == FALSE)
3736 return STATUS_INVALID_PARAMETER;
3737 return STATUS_SUCCESS;
3738 }
3739 }
3740
3741 return STATUS_NOT_IMPLEMENTED;
3742 }
3743
3744 VOID
3745 uhci_init_hcd_interface(PUHCI_DEV uhci)
3746 {
3747 uhci->hcd_interf.hcd_set_dev_mgr = uhci_set_dev_mgr;
3748 uhci->hcd_interf.hcd_get_dev_mgr = uhci_get_dev_mgr;
3749 uhci->hcd_interf.hcd_get_type = uhci_get_type;
3750 uhci->hcd_interf.hcd_set_id = uhci_set_id;
3751 uhci->hcd_interf.hcd_get_id = uhci_get_id;
3752 uhci->hcd_interf.hcd_alloc_addr = uhci_alloc_addr;
3753 uhci->hcd_interf.hcd_free_addr = uhci_free_addr;
3754 uhci->hcd_interf.hcd_submit_urb = uhci_submit_urb2;
3755 uhci->hcd_interf.hcd_generic_urb_completion = uhci_generic_urb_completion;
3756 uhci->hcd_interf.hcd_get_root_hub = uhci_get_root_hub;
3757 uhci->hcd_interf.hcd_set_root_hub = uhci_set_root_hub;
3758 uhci->hcd_interf.hcd_remove_device = uhci_remove_device2;
3759 uhci->hcd_interf.hcd_rh_reset_port = uhci_rh_reset_port;
3760 uhci->hcd_interf.hcd_release = uhci_hcd_release;
3761 uhci->hcd_interf.hcd_cancel_urb = uhci_cancel_urb2;
3762 uhci->hcd_interf.hcd_start = uhci_start;
3763 uhci->hcd_interf.hcd_dispatch = uhci_dispatch;
3764
3765 uhci->hcd_interf.flags = HCD_TYPE_UHCI; //hcd types | hcd id
3766 }
3767
3768 NTSTATUS NTAPI
3769 generic_dispatch_irp(IN PDEVICE_OBJECT dev_obj, IN PIRP irp)
3770 {
3771 PDEVEXT_HEADER dev_ext;
3772
3773 dev_ext = (PDEVEXT_HEADER) dev_obj->DeviceExtension;
3774
3775 if (dev_ext && dev_ext->dispatch)
3776 return dev_ext->dispatch(dev_obj, irp);
3777
3778 irp->IoStatus.Information = 0;
3779
3780 EXIT_DISPATCH(STATUS_UNSUCCESSFUL, irp);
3781 }
3782
3783
3784 VOID NTAPI
3785 generic_start_io(IN PDEVICE_OBJECT dev_obj, IN PIRP irp)
3786 {
3787 PDEVEXT_HEADER dev_ext;
3788
3789 KIRQL old_irql;
3790
3791 IoAcquireCancelSpinLock(&old_irql);
3792 if (irp != dev_obj->CurrentIrp || irp->Cancel)
3793 {
3794 IoReleaseCancelSpinLock(old_irql);
3795 return;
3796 }
3797 else
3798 {
3799 (void)IoSetCancelRoutine(irp, NULL);
3800 IoReleaseCancelSpinLock(old_irql);
3801 }
3802
3803 dev_ext = (PDEVEXT_HEADER) dev_obj->DeviceExtension;
3804
3805 if (dev_ext && dev_ext->start_io)
3806 {
3807 dev_ext->start_io(dev_obj, irp);
3808 return;
3809 }
3810
3811 irp->IoStatus.Information = 0;
3812 irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
3813
3814 IoStartNextPacket(dev_obj, FALSE);
3815 IoCompleteRequest(irp, IO_NO_INCREMENT);
3816 }
3817
3818 NTSTATUS
3819 NTAPI
3820 DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
3821 {
3822 NTSTATUS ntStatus = STATUS_SUCCESS;
3823
3824 #if DBG
3825 // should be done before any debug output is done.
3826 // read our debug verbosity level from the registry
3827 //NetacOD_GetRegistryDword( NetacOD_REGISTRY_PARAMETERS_PATH, //absolute registry path
3828 // L"DebugLevel", // REG_DWORD ValueName
3829 // &gDebugLevel ); // Value receiver
3830
3831 // debug_level = DBGLVL_MAXIMUM;
3832 #endif
3833
3834 uhci_dbg_print_cond(DBGLVL_MINIMUM, DEBUG_UHCI,
3835 ("Entering DriverEntry(), RegistryPath=\n %ws\n", RegistryPath->Buffer));
3836
3837 // Remember our driver object, for when we create our child PDO
3838 usb_driver_obj = DriverObject;
3839
3840 //
3841 // Create dispatch points for create, close, unload
3842 DriverObject->MajorFunction[IRP_MJ_CREATE] = generic_dispatch_irp;
3843 DriverObject->MajorFunction[IRP_MJ_CLOSE] = generic_dispatch_irp;
3844 DriverObject->DriverUnload = uhci_unload;
3845
3846 // User mode DeviceIoControl() calls will be routed here
3847 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = generic_dispatch_irp;
3848 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = generic_dispatch_irp;
3849
3850 // User mode ReadFile()/WriteFile() calls will be routed here
3851 DriverObject->MajorFunction[IRP_MJ_WRITE] = generic_dispatch_irp;
3852 DriverObject->MajorFunction[IRP_MJ_READ] = generic_dispatch_irp;
3853
3854 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = generic_dispatch_irp;
3855 DriverObject->MajorFunction[IRP_MJ_SCSI] = generic_dispatch_irp;
3856 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = generic_dispatch_irp;
3857
3858 DriverObject->DriverStartIo = generic_start_io;
3859 // routines for handling system PNP and power management requests
3860 //DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = generic_dispatch_irp;
3861
3862 // The Functional Device Object (FDO) will not be created for PNP devices until
3863 // this routine is called upon device plug-in.
3864 RtlZeroMemory(&g_dev_mgr, sizeof(USB_DEV_MANAGER));
3865 g_dev_mgr.usb_driver_obj = DriverObject;
3866
3867 #ifdef INCLUDE_EHCI
3868 ehci_probe(DriverObject, RegistryPath, &g_dev_mgr);
3869 #endif
3870
3871 uhci_probe(DriverObject, RegistryPath, &g_dev_mgr);
3872
3873 if (dev_mgr_strobe(&g_dev_mgr) == FALSE)
3874 {
3875
3876 dev_mgr_release_hcd(&g_dev_mgr);
3877 return STATUS_UNSUCCESSFUL;
3878 }
3879
3880 dev_mgr_start_hcd(&g_dev_mgr);
3881
3882 /* Wait till all drivers are initialized */
3883 ntStatus = KeWaitForSingleObject(&g_dev_mgr.drivers_inited, Executive, KernelMode, TRUE, NULL);
3884
3885 uhci_dbg_print_cond(DBGLVL_DEFAULT, DEBUG_UHCI, ("DriverEntry(): exiting... (%x)\n", ntStatus));
3886 return STATUS_SUCCESS;
3887 }
3888
3889 //note: the initialization will be in the following order
3890 // uhci_probe
3891 // dev_mgr_strobe
3892 // uhci_start
3893
3894 // to kill dev_mgr_thread:
3895 // dev_mgr->term_flag = TRUE;
3896 // KeSetEvent( &dev_mgr->wake_up_event );
3897 // this piece of code must run at passive-level