The real, definitive, Visual C++ support branch. Accept no substitutes
[reactos.git] / drivers / usb / nt4compat / usbdriver / uhci.c
1 /**
2 * uhci.c - USB driver stack project for Windows NT 4.0
3 *
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
5 *
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program (in the main directory of the distribution, the file
18 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "usbdriver.h"
23
24 //----------------------------------------------------------
25 // uhci routines
26 //#define DEMO
27
28 #ifdef INCLUDE_EHCI
29
30 #define rh_port1_status rh_port_status[ 1 ]
31 #define rh_port2_status rh_port_status[ 2 ]
32
33 extern PDEVICE_OBJECT ehci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr);
34
35 #endif
36
37 #define DEFAULT_ENDP( enDP ) \
38 ( enDP->flags & USB_ENDP_FLAG_DEFAULT_ENDP )
39
40 #define dev_from_endp( enDP ) \
41 ( DEFAULT_ENDP( enDP )\
42 ? ( ( PUSB_DEV )( enDP )->pusb_if )\
43 : ( ( enDP )->pusb_if->pusb_config->pusb_dev ) )
44
45 #define endp_state( enDP ) ( ( enDP )->flags & USB_ENDP_FLAG_STAT_MASK )
46
47 #define endp_num( enDP ) \
48 ( DEFAULT_ENDP( enDP )\
49 ? 0 \
50 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & 0x0f ) )
51
52 #define endp_dir( enDP ) \
53 ( DEFAULT_ENDP( enDP )\
54 ? 0L\
55 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & USB_DIR_IN ) )
56
57 #define dev_set_state( pdEV, staTE ) \
58 ( pdEV->flags = ( ( pdEV )->flags & ( ~USB_DEV_STATE_MASK ) ) | ( staTE ) )
59
60 #define endp_max_packet_size( enDP ) \
61 ( DEFAULT_ENDP( enDP )\
62 ? ( ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc ? \
63 ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc->bMaxPacketSize0\
64 : 8 )\
65 : enDP->pusb_endp_desc->wMaxPacketSize )
66
67
68 #if 0
69 /* WTF?! */
70 #define release_adapter( padapTER ) \
71 {\
72 ( ( padapTER ) ); \
73 }
74 #else
75 #define release_adapter( padapTER ) (void)(padapTER)
76 #endif
77
78 #define get_int_idx( _urb, _idx ) \
79 {\
80 UCHAR interVAL;\
81 interVAL = ( UCHAR )( ( _urb )->pipe >> 24 );\
82 for( _idx = 1; _idx < 9; _idx++ )\
83 {\
84 interVAL >>= 1;\
85 if( !interVAL )\
86 break;\
87 }\
88 _idx --;\
89 }
90
91 #define uhci_insert_urb_to_schedule( uHCI, pURB, rET ) \
92 {\
93 SYNC_PARAM sync_param;\
94 sync_param.uhci = uHCI;\
95 sync_param.context = pURB;\
96 \
97 rET = KeSynchronizeExecution( uHCI->pdev_ext->uhci_int, uhci_sync_insert_urb_schedule, &sync_param );\
98 }
99
100 //declarations
101 typedef struct
102 {
103 PUHCI_DEV uhci;
104 PVOID context;
105 ULONG ret;
106 } SYNC_PARAM, *PSYNC_PARAM;
107
108 PDEVICE_OBJECT
109 uhci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr);
110
111 BOOLEAN uhci_init_schedule(PUHCI_DEV uhci, PADAPTER_OBJECT padapter);
112
113 BOOLEAN uhci_release(PDEVICE_OBJECT pdev);
114
115 static VOID uhci_stop(PUHCI_DEV uhci);
116
117 BOOLEAN uhci_destroy_schedule(PUHCI_DEV uhci);
118
119 BOOLEAN NTAPI uhci_sync_insert_urb_schedule(PVOID context);
120
121 VOID uhci_init_hcd_interface(PUHCI_DEV uhci);
122
123 NTSTATUS uhci_rh_submit_urb(PUSB_DEV rh, PURB purb);
124
125 NTSTATUS uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
126
127 extern VOID rh_timer_svc_reset_port_completion(PUSB_DEV dev, PVOID context);
128
129 extern VOID rh_timer_svc_int_completion(PUSB_DEV dev, PVOID context);
130
131 ULONG debug_level = DBGLVL_MINIMUM;//DBGLVL_MAXIMUM;
132 PDRIVER_OBJECT usb_driver_obj = NULL;
133 extern USB_DEV_MANAGER g_dev_mgr;
134
135 //pending endpoint pool funcs
136 VOID
137 uhci_wait_ms(PUHCI_DEV uhci, LONG ms)
138 {
139 LARGE_INTEGER lms;
140 if (ms <= 0)
141 return;
142
143 lms.QuadPart = -10 * ms;
144 KeSetTimer(&uhci->reset_timer, lms, NULL);
145
146 KeWaitForSingleObject(&uhci->reset_timer, Executive, KernelMode, FALSE, NULL);
147
148 return;
149 }
150
151 BOOLEAN
152 init_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
153 {
154 int i;
155 if (pool == NULL)
156 return FALSE;
157
158 pool->pending_endp_array =
159 usb_alloc_mem(NonPagedPool, sizeof(UHCI_PENDING_ENDP) * UHCI_MAX_PENDING_ENDPS);
160 InitializeListHead(&pool->free_que);
161 pool->free_count = 0;
162 pool->total_count = UHCI_MAX_PENDING_ENDPS;
163 KeInitializeSpinLock(&pool->pool_lock);
164
165 for(i = 0; i < MAX_TIMER_SVCS; i++)
166 {
167 free_pending_endp(pool, &pool->pending_endp_array[i]);
168 }
169
170 return TRUE;
171
172 }
173
174 BOOLEAN
175 free_pending_endp(PUHCI_PENDING_ENDP_POOL pool, PUHCI_PENDING_ENDP pending_endp)
176 {
177 if (pool == NULL || pending_endp == NULL)
178 {
179 return FALSE;
180 }
181
182 RtlZeroMemory(pending_endp, sizeof(UHCI_PENDING_ENDP));
183 InsertTailList(&pool->free_que, (PLIST_ENTRY) & pending_endp->endp_link);
184 pool->free_count++;
185
186 return TRUE;
187 }
188
189 PUHCI_PENDING_ENDP
190 alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool, LONG count)
191 {
192 PUHCI_PENDING_ENDP new;
193 if (pool == NULL || count != 1)
194 return NULL;
195
196 if (pool->free_count <= 0)
197 return NULL;
198
199 new = (PUHCI_PENDING_ENDP) RemoveHeadList(&pool->free_que);
200 pool->free_count--;
201 return new;
202 }
203
204 BOOLEAN
205 destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
206 {
207 if (pool == NULL)
208 return FALSE;
209
210 InitializeListHead(&pool->free_que);
211 pool->free_count = pool->total_count = 0;
212 usb_free_mem(pool->pending_endp_array);
213 pool->pending_endp_array = NULL;
214
215 return TRUE;
216
217 }
218
219
220 //end of pending endpoint pool funcs
221
222 static void
223 uhci_fill_td(PUHCI_TD td, ULONG status, ULONG info, ULONG buffer)
224 {
225 td->status = status;
226 td->info = info;
227 td->buffer = buffer;
228 }
229
230 BOOLEAN
231 uhci_insert_td_fl(PUHCI_TD prev_td, PUHCI_TD ptd)
232 {
233 PLIST_ENTRY temp_entry;
234
235 if (prev_td == NULL || ptd == NULL)
236 return FALSE;
237
238 temp_entry = &prev_td->ptde->hori_link;
239
240 ptd->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
241 prev_td->link = ptd->phy_addr;
242
243 InsertHeadList(&prev_td->ptde->hori_link, &ptd->ptde->hori_link);
244 return TRUE;
245 }
246
247 BOOLEAN
248 uhci_remove_td_fl(PUHCI_TD ptd)
249 {
250 PUHCI_TD prev_td;
251
252 if (ptd == NULL)
253 return FALSE;
254
255 prev_td = (struct_ptr(ptd->ptde->hori_link.Blink, TD_EXTENSION, hori_link))->ptd;
256 prev_td->link = ptd->link;
257 ptd->link = UHCI_PTR_TERM;
258
259 RemoveEntryList(&ptd->ptde->hori_link);
260
261 return FALSE;
262 }
263
264 BOOLEAN
265 uhci_insert_qh_fl(PVOID prev_item, PUHCI_QH pqh)
266 {
267 //only horizontal link allowed
268 PUHCI_QH pprev_qh;
269 PUHCI_TD pprev_td;
270 PLIST_ENTRY temp_entry;
271
272 if (prev_item == NULL || pqh == NULL)
273 return FALSE;
274
275 if ((((PUHCI_TD) prev_item)->ptde->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
276 {
277 pprev_qh = (PUHCI_QH) prev_item;
278 temp_entry = pprev_qh->pqhe->hori_link.Flink;
279 pqh->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
280 pprev_qh->link = pqh->phy_addr;
281
282 InsertHeadList(&pprev_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
283 }
284 else
285 {
286 pprev_td = ((PUHCI_TD) prev_item);
287
288 temp_entry = pprev_td->ptde->hori_link.Flink;
289 pprev_td->link = pqh->phy_addr;
290 pqh->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
291
292 InsertHeadList(&pprev_td->ptde->hori_link, &pqh->pqhe->hori_link);
293 }
294
295 return FALSE;
296 }
297
298 BOOLEAN
299 uhci_remove_qh_fl(PUHCI_QH pqh)
300 {
301 PVOID prev_item;
302 PUHCI_QH pprevqh;
303 PUHCI_TD pprevtd;
304
305 if (pqh == NULL)
306 return FALSE;
307
308 prev_item = (struct_ptr(pqh->pqhe->hori_link.Blink, TD_EXTENSION, hori_link))->ptd;
309
310 if ((((PUHCI_TD) prev_item)->ptde->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
311 {
312 pprevqh = (PUHCI_QH) prev_item;
313 pprevqh->link = pqh->link;
314 }
315 else
316 {
317 pprevtd = ((PUHCI_TD) prev_item);
318 pprevtd->link = pqh->link;
319 }
320
321 RemoveEntryList(&pqh->pqhe->hori_link);
322
323 pqh->link = UHCI_PTR_TERM;
324 pqh->pqhe->hori_link.Flink = pqh->pqhe->hori_link.Blink = NULL;
325
326 return TRUE;
327 }
328
329 BOOLEAN
330 uhci_init_frame_list(PUHCI_DEV uhci, PADAPTER_OBJECT padapter)
331 {
332 int i;
333 if (uhci == NULL || padapter == NULL)
334 return FALSE;
335
336 //note: frame_list_lock will be connected to interrupt
337 KeInitializeSpinLock(&uhci->frame_list_lock);
338
339 uhci->io_buf = HalAllocateCommonBuffer(padapter, 4096, &uhci->io_buf_logic_addr, FALSE);
340
341 if (uhci->io_buf == NULL)
342 return FALSE;
343
344 uhci->frame_list =
345 HalAllocateCommonBuffer(padapter,
346 sizeof(ULONG) * UHCI_MAX_FRAMES, &uhci->frame_list_logic_addr, FALSE);
347
348 if (uhci->frame_list == NULL)
349 return FALSE;
350
351 RtlZeroMemory(uhci->frame_list, sizeof(ULONG) * UHCI_MAX_FRAMES);
352
353 uhci->frame_list_cpu = usb_alloc_mem(NonPagedPool, sizeof(FRAME_LIST_CPU_ENTRY) * UHCI_MAX_FRAMES);
354
355 if (uhci->frame_list_cpu == NULL)
356 return FALSE;
357
358 for(i = 0; i < UHCI_MAX_FRAMES; i++)
359 InitializeListHead(&uhci->frame_list_cpu[i].td_link);
360
361 uhci->frame_bw = usb_alloc_mem(NonPagedPool, sizeof(LONG) * UHCI_MAX_FRAMES);
362
363 if (uhci->frame_bw == NULL)
364 return FALSE;
365
366 for(i = 0; i < UHCI_MAX_FRAMES; i++)
367 {
368 uhci->frame_bw[i] = FRAME_TIME_MAX_USECS_ALLOC;
369 }
370 uhci->fsbr_cnt = 0;
371
372 return TRUE;
373
374 }
375
376 BOOLEAN
377 uhci_destroy_frame_list(PUHCI_DEV uhci)
378 {
379 if (uhci == NULL)
380 return FALSE;
381
382 if (uhci->frame_list)
383 HalFreeCommonBuffer(uhci->pdev_ext->padapter,
384 sizeof(ULONG) * UHCI_MAX_FRAMES,
385 uhci->frame_list_logic_addr, uhci->frame_list, FALSE);
386
387 uhci->frame_list = NULL;
388 uhci->frame_list_logic_addr.LowPart = 0;
389 uhci->frame_list_logic_addr.HighPart = 0;
390
391 if (uhci->frame_list_cpu)
392 usb_free_mem(uhci->frame_list_cpu);
393
394 uhci->frame_list_cpu = NULL;
395
396 if (uhci->frame_bw)
397 usb_free_mem(uhci->frame_bw);
398
399 uhci->frame_bw = NULL;
400
401 return TRUE;
402 }
403
404 PDEVICE_OBJECT
405 uhci_create_device(PDRIVER_OBJECT drvr_obj, PUSB_DEV_MANAGER dev_mgr)
406 {
407 NTSTATUS status;
408 PDEVICE_OBJECT pdev;
409 PDEVICE_EXTENSION pdev_ext;
410
411 UNICODE_STRING dev_name;
412 UNICODE_STRING symb_name;
413
414 STRING string, another_string;
415 CHAR str_dev_name[64], str_symb_name[64];
416 UCHAR hcd_id;
417
418 if (drvr_obj == NULL)
419 return NULL;
420
421 ASSERT(dev_mgr != NULL);
422
423 //note: hcd count wont increment till the hcd is registered in dev_mgr
424 sprintf(str_dev_name, "%s%d", UHCI_DEVICE_NAME, dev_mgr->hcd_count);
425 sprintf(str_symb_name, "%s%d", DOS_DEVICE_NAME, dev_mgr->hcd_count);
426
427 RtlInitString(&string, str_dev_name);
428 RtlAnsiStringToUnicodeString(&dev_name, &string, TRUE);
429
430 pdev = NULL;
431 status = IoCreateDevice(drvr_obj,
432 sizeof(DEVICE_EXTENSION) + sizeof(UHCI_DEV),
433 &dev_name, FILE_UHCI_DEV_TYPE, 0, FALSE, &pdev);
434
435 if (status != STATUS_SUCCESS || pdev == NULL)
436 {
437 RtlFreeUnicodeString(&dev_name);
438 return NULL;
439 }
440
441 pdev_ext = pdev->DeviceExtension;
442 RtlZeroMemory(pdev_ext, sizeof(DEVICE_EXTENSION) + sizeof(UHCI_DEV));
443
444 pdev_ext->dev_ext_hdr.type = NTDEV_TYPE_HCD;
445 pdev_ext->dev_ext_hdr.dispatch = uhci_dispatch_irp;
446 pdev_ext->dev_ext_hdr.start_io = NULL; //we do not support startio
447 pdev_ext->dev_ext_hdr.dev_mgr = dev_mgr;
448
449 pdev_ext->pdev_obj = pdev;
450 pdev_ext->pdrvr_obj = drvr_obj;
451
452 pdev_ext->uhci = (PUHCI_DEV) & (pdev_ext[1]);
453
454 RtlInitString(&another_string, str_symb_name);
455 RtlAnsiStringToUnicodeString(&symb_name, &another_string, TRUE);
456
457 IoCreateSymbolicLink(&symb_name, &dev_name);
458
459 uhci_dbg_print(DBGLVL_MAXIMUM,
460 ("uhci_create_device(): dev=0x%x\n, pdev_ext= 0x%x, uhci=0x%x, dev_mgr=0x%x\n", pdev,
461 pdev_ext, pdev_ext->uhci, dev_mgr));
462
463 RtlFreeUnicodeString(&dev_name);
464 RtlFreeUnicodeString(&symb_name);
465
466 //register with dev_mgr though it is not initilized
467 uhci_init_hcd_interface(pdev_ext->uhci);
468 hcd_id = dev_mgr_register_hcd(dev_mgr, &pdev_ext->uhci->hcd_interf);
469
470 pdev_ext->uhci->hcd_interf.hcd_set_id(&pdev_ext->uhci->hcd_interf, hcd_id);
471 pdev_ext->uhci->hcd_interf.hcd_set_dev_mgr(&pdev_ext->uhci->hcd_interf, dev_mgr);
472 return pdev;
473 }
474
475 BOOLEAN
476 uhci_delete_device(PDEVICE_OBJECT pdev)
477 {
478 STRING string;
479 UNICODE_STRING symb_name;
480 PDEVICE_EXTENSION pdev_ext;
481 CHAR str_symb_name[64];
482
483
484 if (pdev == NULL)
485 return FALSE;
486
487 pdev_ext = pdev->DeviceExtension;
488
489 sprintf(str_symb_name,
490 "%s%d", DOS_DEVICE_NAME, pdev_ext->uhci->hcd_interf.hcd_get_id(&pdev_ext->uhci->hcd_interf));
491 RtlInitString(&string, str_symb_name);
492 RtlAnsiStringToUnicodeString(&symb_name, &string, TRUE);
493 IoDeleteSymbolicLink(&symb_name);
494 RtlFreeUnicodeString(&symb_name);
495
496 if (pdev_ext->res_list)
497 ExFreePool(pdev_ext->res_list); // not allocated by usb_alloc_mem
498
499 IoDeleteDevice(pdev);
500 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_delete_device(): device deleted\n"));
501 return TRUE;
502 }
503
504 // we can not use endp here for it is within the dev scope, and
505 // we can not acquire the dev-lock, fortunately we saved some
506 // info in urb->pipe in uhci_internal_submit_XXX.
507 BOOLEAN NTAPI
508 uhci_isr(PKINTERRUPT interrupt, PVOID context)
509 {
510 PUHCI_DEV uhci;
511 USHORT status;
512 PLIST_ENTRY pthis, pnext;
513 PURB purb;
514
515 UNREFERENCED_PARAMETER(interrupt);
516 UNREFERENCED_PARAMETER(context);
517
518 uhci_dbg_print(DBGLVL_ULTRA, ("uhci_isr(): context=0x%x\n", context));
519
520 /*
521 * Read the interrupt status, and write it back to clear the
522 * interrupt cause
523 */
524 uhci = (PUHCI_DEV) context;
525 if (uhci == NULL)
526 return FALSE;
527
528 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS));
529 if (!status) /* shared interrupt, not mine */
530 return FALSE;
531
532 if (status != 1)
533 {
534 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr(): current uhci status=0x%x\n", status));
535 }
536 else
537 {
538 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr(): congratulations, no error occurs\n"));
539 }
540
541 /* clear it */
542 WRITE_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS), status);
543
544 if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD))
545 {
546 if (status & USBSTS_HSE)
547 {
548 DbgPrint("uhci_isr(): host system error, PCI problems?\n");
549 //for( ; ; );
550 }
551 if (status & USBSTS_HCPE)
552 {
553 DbgPrint("uhci_isr(): host controller process error. something bad happened\n");
554 //for( ; ; );
555 //for( ; ; );
556 }
557 if ((status & USBSTS_HCH)) //&& !uhci->is_suspended
558 {
559 DbgPrint("uhci_isr(): host controller halted. very bad\n");
560 /* FIXME: Reset the controller, fix the offending TD */
561 }
562 }
563
564 // don't no how to handle it yet
565 //if (status & USBSTS_RD)
566 //{
567 //uhci_wakeup(uhci);
568 //}*/
569
570 //let's remove those force-cancel urbs from the schedule first
571 ListFirst(&uhci->urb_list, pthis);
572 while (pthis)
573 {
574 purb = (PURB) pthis;
575 if (purb->flags & URB_FLAG_FORCE_CANCEL)
576 {
577 uhci_remove_urb_from_schedule(uhci, purb);
578 }
579 ListNext(&uhci->urb_list, pthis, pnext);
580 pthis = pnext;
581 }
582
583 //clear the interrupt if the urb is force canceled
584 uhci->skel_term_td->status &= ~TD_CTRL_IOC;
585
586 //next we need to find if anything fininshed
587 ListFirst(&uhci->urb_list, pthis);
588 while (pthis)
589 {
590 purb = (PURB) pthis;
591 if (purb->flags & URB_FLAG_IN_SCHEDULE)
592 {
593 if (uhci_is_xfer_finished(purb))
594 uhci_remove_urb_from_schedule(uhci, purb);
595 }
596 ListNext(&uhci->urb_list, pthis, pnext);
597 pthis = pnext;
598 }
599
600 KeInsertQueueDpc(&uhci->pdev_ext->uhci_dpc, uhci, 0);
601 return TRUE;
602 }
603
604 BOOLEAN NTAPI
605 uhci_cal_cpu_freq(PVOID context)
606 {
607 UNREFERENCED_PARAMETER(context);
608
609 usb_cal_cpu_freq();
610 return TRUE;
611 }
612
613 PDEVICE_OBJECT
614 uhci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr)
615 {
616 LONG bus, i, j, ret = 0;
617 PCI_SLOT_NUMBER slot_num;
618 PPCI_COMMON_CONFIG pci_config;
619 PDEVICE_OBJECT pdev;
620 BYTE buffer[sizeof(PCI_COMMON_CONFIG)];
621 LONG count;
622 PDEVICE_EXTENSION pdev_ext;
623
624 slot_num.u.AsULONG = 0;
625 pci_config = (PPCI_COMMON_CONFIG) buffer;
626 count = 0;
627 pdev = NULL;
628
629 //scan the bus to find uhci controller
630 for(bus = 0; bus < 2; bus++) /*enum only bus0 and bus1 */
631 {
632 for(i = 0; i < PCI_MAX_DEVICES; i++)
633 {
634 slot_num.u.bits.DeviceNumber = i;
635 for(j = 0; j < PCI_MAX_FUNCTIONS; j++)
636 {
637 slot_num.u.bits.FunctionNumber = j;
638
639 ret = HalGetBusData(PCIConfiguration,
640 bus, slot_num.u.AsULONG, pci_config, PCI_COMMON_HDR_LENGTH);
641
642 if (ret == 0) /*no this bus */
643 break;
644
645 if (ret == 2) /*no device on the slot */
646 break;
647
648 if (pci_config->BaseClass == 0x0c && pci_config->SubClass == 0x03)
649 {
650 // well, we find our usb host controller, create device
651 #ifdef _MULTI_UHCI
652 {
653 pdev = uhci_alloc(drvr_obj, reg_path, ((bus << 8) | (i << 3) | j), dev_mgr);
654 count++;
655 if (!pdev)
656 return NULL;
657 }
658 #else
659 pdev = uhci_alloc(drvr_obj, reg_path, ((bus << 8) | (i << 3) | j), dev_mgr);
660 if (pdev)
661 goto LBL_LOOPOUT;
662 #endif
663 }
664 }
665 if (ret == 0)
666 break;
667 }
668 }
669
670 LBL_LOOPOUT:
671 if (pdev)
672 {
673 pdev_ext = pdev->DeviceExtension;
674 if (pdev_ext)
675 {
676 // acquire higher irql to eliminate pre-empty
677 KeSynchronizeExecution(pdev_ext->uhci_int, uhci_cal_cpu_freq, NULL);
678 }
679 }
680 return NULL;
681 }
682
683 PDEVICE_OBJECT
684 uhci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr)
685 {
686 LONG frd_num, prd_num;
687 PDEVICE_OBJECT pdev;
688 PDEVICE_EXTENSION pdev_ext;
689 ULONG vector, addr_space;
690 LONG bus;
691 KIRQL irql;
692 KAFFINITY affinity;
693
694 DEVICE_DESCRIPTION dev_desc;
695 CM_PARTIAL_RESOURCE_DESCRIPTOR *pprd;
696 PCI_SLOT_NUMBER slot_num;
697 NTSTATUS status;
698
699
700 pdev = uhci_create_device(drvr_obj, dev_mgr);
701 pdev_ext = pdev->DeviceExtension;
702
703 pdev_ext->pci_addr = bus_addr;
704 bus = (bus_addr >> 8);
705
706 slot_num.u.AsULONG = 0;
707 slot_num.u.bits.DeviceNumber = ((bus_addr & 0xff) >> 3);
708 slot_num.u.bits.FunctionNumber = (bus_addr & 0x07);
709
710 if (pdev == NULL)
711 return pdev;
712
713 //now create adapter object
714 RtlZeroMemory(&dev_desc, sizeof(dev_desc));
715
716 dev_desc.Version = DEVICE_DESCRIPTION_VERSION;
717 dev_desc.Master = TRUE;
718 dev_desc.ScatterGather = TRUE;
719 dev_desc.Dma32BitAddresses = TRUE;
720 dev_desc.BusNumber = bus;
721 dev_desc.InterfaceType = PCIBus;
722 dev_desc.MaximumLength =
723 UHCI_MAX_POOL_TDS * sizeof(UHCI_TD) * UHCI_MAX_TD_POOLS
724 + sizeof(UHCI_QH) * UHCI_MAX_POOL_QHS + sizeof(ULONG) * UHCI_MAX_FRAMES;
725
726 pdev_ext->map_regs = 2; // UHCI_MAX_TD_POOLS +
727 //+ BYTES_TO_PAGES( ( UHCI_MAX_POOL_TDS * 64 ) * UHCI_MAX_TD_POOLS ) ;
728
729 pdev_ext->padapter = HalGetAdapter(&dev_desc, &pdev_ext->map_regs);
730
731 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_alloc(): padapter=0x%x\n", pdev_ext->padapter));
732 if (pdev_ext->padapter == NULL)
733 {
734 //fatal error
735 uhci_delete_device(pdev);
736 return NULL;
737 }
738
739 DbgPrint("uhci_alloc(): reg_path=%p, \n \
740 uhci_alloc(): PCIBus=0x%x, bus=0x%x, bus_addr=0x%x \n \
741 uhci_alloc(): slot_num=0x%x, &res_list=%p \n", reg_path, (DWORD) PCIBus, (DWORD) bus,
742 (DWORD) bus_addr, (DWORD) slot_num.u.AsULONG, & pdev_ext->res_list);
743
744 //let's allocate resources for this device
745 DbgPrint("uhci_alloc(): about to assign slot res\n");
746 if ((status = HalAssignSlotResources(reg_path, NULL, //no class name yet
747 drvr_obj, NULL, //no support of another uhci controller
748 PCIBus,
749 bus, slot_num.u.AsULONG, &pdev_ext->res_list)) != STATUS_SUCCESS)
750 {
751 DbgPrint("uhci_alloc(): error assign slot res, 0x%x\n", status);
752 release_adapter(pdev_ext->padapter);
753 pdev_ext->padapter = NULL;
754 uhci_delete_device(pdev);
755 return NULL;
756 }
757
758 //parse the resource list
759 for(frd_num = 0; frd_num < (LONG) pdev_ext->res_list->Count; frd_num++)
760 {
761 for(prd_num = 0; prd_num < (LONG) pdev_ext->res_list->List[frd_num].PartialResourceList.Count;
762 prd_num++)
763 {
764 pprd = &pdev_ext->res_list->List[frd_num].PartialResourceList.PartialDescriptors[prd_num];
765 if (pprd->Type == CmResourceTypePort)
766 {
767 RtlCopyMemory(&pdev_ext->res_port, &pprd->u.Port, sizeof(pprd->u.Port));
768 }
769 else if (pprd->Type == CmResourceTypeInterrupt)
770 {
771 RtlCopyMemory(&pdev_ext->res_interrupt, &pprd->u.Interrupt, sizeof(pprd->u.Interrupt));
772 }
773 }
774 }
775
776 //for port, translate them to system address
777 addr_space = 1;
778 if (HalTranslateBusAddress(PCIBus, bus, pdev_ext->res_port.Start, &addr_space, //io space
779 &pdev_ext->uhci->uhci_reg_base) != (BOOLEAN) TRUE)
780 {
781 DbgPrint("uhci_alloc(): error, can not translate bus address\n");
782 release_adapter(pdev_ext->padapter);
783 pdev_ext->padapter = NULL;
784 uhci_delete_device(pdev);
785 return NULL;
786 }
787
788 DbgPrint("uhci_alloc(): address space=0x%x\n, reg_base=0x%x\n",
789 addr_space, pdev_ext->uhci->uhci_reg_base.u.LowPart);
790
791 if (addr_space == 0)
792 {
793 //port has been mapped to memory space
794 pdev_ext->uhci->port_mapped = TRUE;
795 pdev_ext->uhci->port_base = (PBYTE) MmMapIoSpace(pdev_ext->uhci->uhci_reg_base,
796 pdev_ext->res_port.Length, FALSE);
797
798 //fatal error can not map the registers
799 if (pdev_ext->uhci->port_base == NULL)
800 {
801 release_adapter(pdev_ext->padapter);
802 pdev_ext->padapter = NULL;
803 uhci_delete_device(pdev);
804 return NULL;
805 }
806 }
807 else
808 {
809 //io space
810 pdev_ext->uhci->port_mapped = FALSE;
811 pdev_ext->uhci->port_base = (PBYTE) pdev_ext->uhci->uhci_reg_base.LowPart;
812 }
813
814 //before we connect the interrupt, we have to init uhci
815 pdev_ext->uhci->fsbr_cnt = 0;
816 pdev_ext->uhci->pdev_ext = pdev_ext;
817
818 if (uhci_init_schedule(pdev_ext->uhci, pdev_ext->padapter) == FALSE)
819 {
820 release_adapter(pdev_ext->padapter);
821 pdev_ext->padapter = NULL;
822 uhci_delete_device(pdev);
823 return NULL;
824 }
825
826 InitializeListHead(&pdev_ext->uhci->urb_list);
827 KeInitializeSpinLock(&pdev_ext->uhci->pending_endp_list_lock);
828 InitializeListHead(&pdev_ext->uhci->pending_endp_list);
829
830 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_alloc(): pending_endp_list=0x%x\n",
831 &pdev_ext->uhci->pending_endp_list));
832
833 init_pending_endp_pool(&pdev_ext->uhci->pending_endp_pool);
834 KeInitializeTimer(&pdev_ext->uhci->reset_timer);
835
836 vector = HalGetInterruptVector(PCIBus,
837 bus,
838 pdev_ext->res_interrupt.level,
839 pdev_ext->res_interrupt.vector,
840 &irql,
841 &affinity);
842
843 //connect the interrupt
844 DbgPrint("uhci_alloc(): the int=0x%x\n", vector);
845 if (IoConnectInterrupt(&pdev_ext->uhci_int,
846 uhci_isr,
847 pdev_ext->uhci,
848 NULL, //&pdev_ext->uhci->frame_list_lock,
849 vector,
850 irql,
851 irql,
852 LevelSensitive,
853 TRUE, //share the vector
854 affinity,
855 FALSE) //No float save
856 != STATUS_SUCCESS)
857 {
858 uhci_release(pdev);
859 return NULL;
860 }
861
862 KeInitializeDpc(&pdev_ext->uhci_dpc, uhci_dpc_callback, (PVOID) pdev_ext->uhci);
863
864 return pdev;
865 }
866
867 BOOLEAN
868 uhci_release(PDEVICE_OBJECT pdev)
869 {
870 PDEVICE_EXTENSION pdev_ext;
871 PUHCI_DEV uhci;
872
873 if (pdev == NULL)
874 return FALSE;
875
876 pdev_ext = pdev->DeviceExtension;
877
878 if (pdev_ext == NULL)
879 return FALSE;
880
881 uhci = pdev_ext->uhci;
882 if (uhci == NULL)
883 return FALSE;
884
885 uhci_stop(uhci);
886 //pdev_ext->uhci->conn_count = 0;
887 pdev_ext->uhci->fsbr_cnt = 0;
888
889 if (pdev_ext->uhci_int)
890 {
891 IoDisconnectInterrupt(pdev_ext->uhci_int);
892 pdev_ext->uhci_int = NULL;
893 }
894 else
895 TRAP();
896 destroy_pending_endp_pool(&pdev_ext->uhci->pending_endp_pool);
897 //pdev_ext->uhci->pending_endp_pool = NULL;
898
899 uhci_destroy_schedule(uhci);
900
901 release_adapter(pdev_ext->padapter);
902 pdev_ext->padapter = NULL;
903
904 uhci_delete_device(pdev);
905
906 return FALSE;
907
908 }
909
910 // send cmds to start the uhc
911 // shamelessly copied from linux's uhci.c (reset_hc(), configure_hc() routines)
912 BOOLEAN
913 uhci_start(PHCD hcd)
914 {
915 PUHCI_DEV uhci;
916 PBYTE io_addr;
917 USHORT pirq;
918 PCI_SLOT_NUMBER SlotNum;
919 int timeout = 10000;
920
921 uhci = uhci_from_hcd(hcd);
922 io_addr = uhci->port_base;
923
924 /*
925 * Reset the HC - this will force us to get a
926 * new notification of any already connected
927 * ports due to the virtual disconnect that it
928 * implies.
929 */
930 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_HCRESET);
931 while (READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD)) & USBCMD_HCRESET)
932 {
933 if (!--timeout)
934 {
935 break;
936 }
937 }
938
939 /* Turn on all interrupts */
940 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR),
941 USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP);
942
943 /* Start at frame 0 */
944 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBFRNUM), 0);
945 WRITE_PORT_ULONG((PULONG) (io_addr + USBFLBASEADD), uhci->frame_list_logic_addr.LowPart);
946
947 /* Run and mark it configured with a 64-byte max packet */
948 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
949
950 DbgPrint("uhci_start(): current uhci status=0x%x\n", uhci_status(uhci));
951
952 /* Enable PIRQ */
953 pirq = USBLEGSUP_DEFAULT;
954 SlotNum.u.AsULONG = 0;
955 SlotNum.u.bits.DeviceNumber = ((uhci->pdev_ext->pci_addr & 0xff) >> 3);
956 SlotNum.u.bits.FunctionNumber = (uhci->pdev_ext->pci_addr & 0x07);
957
958 DbgPrint("uhci_start(): set bus %d data at slot 0x%x\n", (uhci->pdev_ext->pci_addr >> 8),
959 SlotNum.u.AsULONG);
960
961 HalSetBusDataByOffset(PCIConfiguration, (uhci->pdev_ext->pci_addr >> 8), SlotNum.u.AsULONG,
962 &pirq, USBLEGSUP, sizeof(pirq));
963
964 return TRUE;
965 }
966
967 VOID
968 uhci_stop(PUHCI_DEV uhci)
969 {
970 PBYTE io_addr = uhci->port_base;
971 // turn off all the interrupt
972 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR), 0);
973 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
974 }
975
976 static VOID
977 uhci_reset(PUHCI_DEV uhci)
978 {
979 PBYTE io_addr = uhci->port_base;
980
981 uhci_stop(uhci);
982 /* Global reset for 50ms */
983 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_GRESET);
984 //uhci_wait_ms( uhci, 50 );
985 usb_wait_ms_dpc(50);
986
987 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
988 //uhci_wait_ms( uhci, 10 );
989 usb_wait_ms_dpc(10);
990 }
991
992 VOID
993 uhci_suspend(PUHCI_DEV uhci)
994 {
995 PBYTE io_addr = uhci->port_base;
996
997 //uhci->is_suspended = 1;
998 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_EGSM);
999
1000 }
1001
1002 VOID
1003 uhci_wakeup(PUHCI_DEV uhci)
1004 {
1005 PBYTE io_addr;
1006 unsigned int status;
1007
1008 io_addr = uhci->port_base;
1009
1010 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
1011
1012 /* wait for EOP to be sent */
1013 status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));
1014 while (status & USBCMD_FGR)
1015 status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));
1016
1017 //uhci->is_suspended = 0;
1018
1019 /* Run and mark it configured with a 64-byte max packet */
1020 WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
1021
1022 }
1023
1024 BOOLEAN
1025 uhci_init_schedule(PUHCI_DEV uhci, PADAPTER_OBJECT padapter)
1026 {
1027 int i, irq;
1028
1029 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_init_schedule(): entering..., uhci=0x%x\n", uhci));
1030 if (uhci == NULL || padapter == NULL)
1031 return FALSE;
1032
1033 if (init_td_pool_list(&uhci->td_pool, padapter) == FALSE)
1034 {
1035 return FALSE;
1036 }
1037 if (init_qh_pool(&uhci->qh_pool, padapter) == FALSE)
1038 {
1039 return FALSE;
1040 }
1041
1042 //since uhci is not started we can freely access all resources.
1043 for(i = 0; i < UHCI_MAX_SKELTDS; i++)
1044 {
1045 uhci->skel_td[i] = alloc_td(&uhci->td_pool);
1046 uhci_fill_td(uhci->skel_td[i], 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
1047
1048 if (i > 0)
1049 {
1050 uhci->skel_td[i]->link = uhci->skel_td[i - 1]->phy_addr;
1051 }
1052 }
1053
1054 /*for( i = UHCI_MAX_SKELTDS - 3; i >= 0; i-- )
1055 {
1056 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1057 &uhci->skel_td[ i ]->ptde->hori_link );
1058 } */
1059
1060 for(i = 0; i < UHCI_MAX_SKELQHS; i++)
1061 {
1062 uhci->skel_qh[i] = alloc_qh(&uhci->qh_pool);
1063 if (i > 0)
1064 {
1065 uhci->skel_qh[i - 1]->link = uhci->skel_qh[i]->phy_addr;
1066 }
1067
1068 uhci->skel_qh[i]->element = UHCI_PTR_TERM;
1069 }
1070
1071 uhci->skel_int1_td->link = uhci->skel_ls_control_qh->phy_addr;
1072
1073 // Hack for PIIX
1074 uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
1075 uhci->skel_term_td->link = uhci->skel_term_td->phy_addr;
1076
1077 uhci->skel_term_qh->link = UHCI_PTR_TERM;
1078 uhci->skel_term_qh->element = uhci->skel_term_td->phy_addr;
1079
1080 InsertTailList(&uhci->skel_term_qh->pqhe->vert_link, &uhci->skel_term_td->ptde->vert_link);
1081
1082 /*for( i = 0; i < UHCI_MAX_SKELQHS; i++ )
1083 {
1084 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1085 &uhci->skel_qh[ i ]->pqhe->hori_link );
1086 } */
1087
1088 if (uhci_init_frame_list(uhci, uhci->pdev_ext->padapter) == FALSE)
1089 uhci_destroy_frame_list(uhci);
1090
1091 //well all have been chained, now scatter the int tds to frame-list
1092 //shamelessly pasted from linux's uhci.c :-)
1093 for(i = 0; i < UHCI_MAX_FRAMES; i++)
1094 {
1095 irq = 0;
1096 if (i & 1)
1097 {
1098 irq++;
1099 if (i & 2)
1100 {
1101 irq++;
1102 if (i & 4)
1103 {
1104 irq++;
1105 if (i & 8)
1106 {
1107 irq++;
1108 if (i & 16)
1109 {
1110 irq++;
1111 if (i & 32)
1112 {
1113 irq++;
1114 if (i & 64)
1115 irq++;
1116 }
1117 }
1118 }
1119 }
1120 }
1121 }
1122
1123 /* Only place we don't use the frame list routines */
1124 uhci->frame_list[i] = uhci->skel_td[irq]->phy_addr;
1125 }
1126 return TRUE;
1127 }
1128
1129 BOOLEAN
1130 uhci_destroy_schedule(PUHCI_DEV uhci)
1131 {
1132 BOOLEAN ret;
1133
1134 ret = uhci_destroy_frame_list(uhci);
1135 ret = destroy_qh_pool(&uhci->qh_pool);
1136 ret = destroy_td_pool_list(&uhci->td_pool);
1137
1138 return ret;
1139
1140 }
1141
1142 VOID NTAPI
1143 uhci_cancel_pending_endp_urb(IN PVOID Parameter)
1144 {
1145 PLIST_ENTRY abort_list;
1146 PUSB_DEV pdev;
1147 PURB purb;
1148 USE_BASIC_NON_PENDING_IRQL;
1149
1150 abort_list = (PLIST_ENTRY) Parameter;
1151
1152 if (abort_list == NULL)
1153 return;
1154
1155 while (IsListEmpty(abort_list) == FALSE)
1156 {
1157 //these devs are protected by urb's ref-count
1158 purb = (PURB) RemoveHeadList(abort_list);
1159 pdev = purb->pdev;
1160 // purb->status is set when they are added to abort_list
1161
1162 uhci_generic_urb_completion(purb, purb->context);
1163
1164 lock_dev(pdev, FALSE);
1165 pdev->ref_count--;
1166 unlock_dev(pdev, FALSE);
1167 }
1168 usb_free_mem(abort_list);
1169 return;
1170 }
1171
1172 BOOLEAN
1173 uhci_process_pending_endp(PUHCI_DEV uhci)
1174 {
1175 PUSB_DEV pdev;
1176 LIST_ENTRY temp_list, abort_list;
1177 PLIST_ENTRY pthis;
1178 PURB purb;
1179 PUSB_ENDPOINT pendp;
1180 NTSTATUS can_submit = STATUS_UNSUCCESSFUL;
1181 PWORK_QUEUE_ITEM pwork_item;
1182 PLIST_ENTRY cancel_list;
1183 USE_BASIC_IRQL;
1184
1185 if (uhci == NULL)
1186 return FALSE;
1187
1188 InitializeListHead(&temp_list);
1189 InitializeListHead(&abort_list);
1190
1191 purb = NULL;
1192 uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): entering..., uhci=0x%x\n", uhci));
1193
1194 lock_pending_endp_list(&uhci->pending_endp_list_lock);
1195 while (IsListEmpty(&uhci->pending_endp_list) == FALSE)
1196 {
1197
1198 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): pending_endp_list=0x%x\n",
1199 &uhci->pending_endp_list));
1200
1201 pthis = RemoveHeadList(&uhci->pending_endp_list);
1202 pendp = ((PUHCI_PENDING_ENDP) pthis)->pendp;
1203 pdev = dev_from_endp(pendp);
1204
1205 lock_dev(pdev, TRUE);
1206
1207 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1208 {
1209 unlock_dev(pdev, TRUE);
1210 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1211 //delegate to uhci_remove_device for removing the urb queue on the endpoint
1212 continue;
1213 }
1214
1215 if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
1216 {
1217 while (IsListEmpty(&pendp->urb_list) == FALSE)
1218 {
1219 purb = (PURB) RemoveHeadList(&pendp->urb_list);
1220 purb->status = USB_STATUS_ENDPOINT_HALTED;
1221 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
1222 }
1223 InitializeListHead(&pendp->urb_list);
1224 unlock_dev(pdev, TRUE);
1225 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1226 continue;
1227 }
1228
1229
1230 if (IsListEmpty(&pendp->urb_list) == FALSE)
1231 {
1232 purb = (PURB) RemoveHeadList(&pendp->urb_list);
1233 ASSERT(purb);
1234 }
1235 else
1236 {
1237 InitializeListHead(&pendp->urb_list);
1238 unlock_dev(pdev, TRUE);
1239 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1240 continue;
1241 }
1242
1243 // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
1244 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): endp_type=0x%x\n",
1245 endp_type(pendp)));
1246 switch (endp_type(pendp))
1247 {
1248 case USB_ENDPOINT_XFER_BULK:
1249 {
1250 #ifdef DEMO
1251 can_submit = STATUS_UNSUCCESSFUL;
1252 #else
1253 can_submit = uhci_internal_submit_bulk(uhci, purb);
1254 #endif
1255 break;
1256 }
1257 case USB_ENDPOINT_XFER_CONTROL:
1258 {
1259 can_submit = uhci_internal_submit_ctrl(uhci, purb);
1260 break;
1261 }
1262 case USB_ENDPOINT_XFER_INT:
1263 {
1264 can_submit = uhci_internal_submit_int(uhci, purb);
1265 break;
1266 }
1267 case USB_ENDPOINT_XFER_ISOC:
1268 {
1269 can_submit = uhci_internal_submit_iso(uhci, purb);
1270 break;
1271 }
1272 }
1273
1274 if (can_submit == STATUS_NO_MORE_ENTRIES)
1275 {
1276 //no enough bandwidth or tds
1277 InsertHeadList(&pendp->urb_list, (PLIST_ENTRY) purb);
1278 InsertTailList(&temp_list, pthis);
1279 }
1280 else
1281 {
1282 // other error or success
1283 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1284
1285 if (can_submit != STATUS_SUCCESS)
1286 {
1287 //abort these URBs
1288 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
1289 uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): unable to submit urb 0x%x, "
1290 "with status=0x%x\n", purb, can_submit));
1291 purb->status = can_submit;
1292 }
1293
1294 }
1295 unlock_dev(pdev, TRUE);
1296 }
1297
1298 if (IsListEmpty(&temp_list) == FALSE)
1299 {
1300 //re-append them to the pending_endp_list
1301 ListFirst(&temp_list, pthis);
1302 RemoveEntryList(&temp_list);
1303 MergeList(&uhci->pending_endp_list, pthis);
1304 }
1305 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1306
1307 if (IsListEmpty(&abort_list) == FALSE)
1308 {
1309 PLIST_ENTRY pthis;
1310 cancel_list = (PLIST_ENTRY) usb_alloc_mem(NonPagedPool, sizeof(WORK_QUEUE_ITEM) + sizeof(LIST_ENTRY));
1311 ASSERT(cancel_list);
1312
1313 ListFirst(&abort_list, pthis);
1314 RemoveEntryList(&abort_list);
1315 InsertTailList(pthis, cancel_list);
1316
1317 pwork_item = (PWORK_QUEUE_ITEM) & cancel_list[1];
1318
1319 // we do not need to worry the uhci_cancel_pending_endp_urb running when the
1320 // driver is unloading since it will prevent the dev_mgr to quit till all the
1321 // reference count to the dev drop to zero.
1322 ExInitializeWorkItem(pwork_item, uhci_cancel_pending_endp_urb, (PVOID) cancel_list);
1323 ExQueueWorkItem(pwork_item, DelayedWorkQueue);
1324 }
1325 return TRUE;
1326 }
1327
1328 NTSTATUS
1329 uhci_submit_urb(PUHCI_DEV uhci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
1330 {
1331 int i;
1332 PUHCI_PENDING_ENDP pending_endp;
1333 NTSTATUS status;
1334 USE_BASIC_IRQL;
1335
1336 if (uhci == NULL || pdev == NULL || pendp == NULL || purb == NULL)
1337 {
1338 uhci_dbg_print(DBGLVL_MEDIUM,
1339 ("uhci_submit_urb(): uhci=0x%x, pdev=0x%x, pendp=0x%x, purb=0x%x "
1340 "called with invalid param!\n", uhci, pdev, pendp, purb));
1341 return STATUS_INVALID_PARAMETER;
1342 }
1343
1344 lock_pending_endp_list(&uhci->pending_endp_list_lock);
1345 lock_dev(pdev, TRUE);
1346
1347 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1348 {
1349 status = purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1350 goto LBL_OUT;
1351 }
1352
1353 if (dev_class(pdev) == USB_DEV_CLASS_ROOT_HUB)
1354 {
1355 unlock_dev(pdev, TRUE);
1356 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1357 status = uhci_rh_submit_urb(pdev, purb);
1358 return status;
1359 }
1360
1361 if (pendp)
1362 purb->pendp = pendp;
1363 else
1364 purb->pendp = &pdev->default_endp;
1365
1366 if (dev_from_endp(purb->pendp) != pdev)
1367 {
1368 uhci_dbg_print(DBGLVL_MEDIUM,
1369 ("uhci_submit_urb(): dev_from_endp=0x%x\n, pdev=0x%x, pendp=0x%x "
1370 "devices mismatch!\n", dev_from_endp(purb->pendp), pdev, pendp));
1371
1372 status = purb->status = STATUS_INVALID_PARAMETER;
1373 goto LBL_OUT;
1374 }
1375
1376 if (endp_state(purb->pendp) == USB_ENDP_FLAG_STALL)
1377 {
1378 status = purb->status = USB_STATUS_ENDPOINT_HALTED;
1379 goto LBL_OUT;
1380 }
1381
1382 purb->pdev = pdev;
1383 purb->rest_bytes = purb->data_length;
1384
1385 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_BULK)
1386 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
1387 else
1388 purb->bytes_to_transfer = purb->data_length;
1389
1390 uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_submit_urb(): bytes_to_transfer=0x%x\n", purb->bytes_to_transfer));
1391
1392 purb->bytes_transfered = 0;
1393 InitializeListHead(&purb->trasac_list);
1394 purb->last_finished_td = &purb->trasac_list;
1395 purb->flags &= ~(URB_FLAG_STATE_MASK | URB_FLAG_IN_SCHEDULE | URB_FLAG_FORCE_CANCEL);
1396 purb->flags |= URB_FLAG_STATE_PENDING;
1397
1398
1399 i = IsListEmpty(&pendp->urb_list);
1400 InsertTailList(&pendp->urb_list, &purb->urb_link);
1401
1402 pdev->ref_count++; //for urb reference
1403
1404 if (i == FALSE)
1405 {
1406 //there is urb pending, simply queue it and return
1407 status = purb->status = STATUS_PENDING;
1408 goto LBL_OUT;
1409 }
1410 else if (usb_endp_busy_count(purb->pendp) && endp_type(purb->pendp) != USB_ENDPOINT_XFER_ISOC)
1411 {
1412 //
1413 //No urb waiting but urb overlap not allowed,
1414 //so leave it in queue and return, will be scheduled
1415 //later
1416 //
1417 status = purb->status = STATUS_PENDING;
1418 goto LBL_OUT;
1419 }
1420
1421 pending_endp = alloc_pending_endp(&uhci->pending_endp_pool, 1);
1422 if (pending_endp == NULL)
1423 {
1424 //panic
1425 status = purb->status = STATUS_UNSUCCESSFUL;
1426 goto LBL_OUT2;
1427 }
1428
1429 pending_endp->pendp = purb->pendp;
1430 InsertTailList(&uhci->pending_endp_list, (PLIST_ENTRY) pending_endp);
1431
1432 unlock_dev(pdev, TRUE);
1433 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1434
1435 uhci_process_pending_endp(uhci);
1436 return STATUS_PENDING;
1437
1438 LBL_OUT2:
1439 pdev->ref_count--;
1440 RemoveEntryList((PLIST_ENTRY) purb);
1441
1442 LBL_OUT:
1443 unlock_dev(pdev, TRUE);
1444 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1445 return status;
1446 }
1447
1448 NTSTATUS
1449 uhci_set_error_code(PURB urb, ULONG raw_status)
1450 {
1451 if ((raw_status & TD_CTRL_ANY_ERROR) == 0)
1452 {
1453 //test if the urb is canceled
1454 if (urb->flags & URB_FLAG_FORCE_CANCEL)
1455 urb->status = STATUS_CANCELLED;
1456 else
1457 urb->status = STATUS_SUCCESS;
1458 }
1459
1460 else if (raw_status & TD_CTRL_BABBLE)
1461 urb->status = USB_STATUS_DATA_OVERRUN;
1462
1463 else if (raw_status & TD_CTRL_STALLED)
1464 urb->status = USB_STATUS_STALL_PID;
1465
1466 else if (raw_status & TD_CTRL_DBUFERR)
1467 urb->status = USB_STATUS_BUFFER_OVERRUN;
1468
1469 else if (raw_status & TD_CTRL_CRCTIMEO)
1470 urb->status = USB_STATUS_CRC;
1471
1472 else if (raw_status & TD_CTRL_BITSTUFF)
1473 urb->status = USB_STATUS_BTSTUFF;
1474
1475 else
1476 urb->status = STATUS_UNSUCCESSFUL;
1477
1478 return urb->status;
1479 }
1480
1481 BOOLEAN NTAPI
1482 uhci_sync_remove_urb_finished(PVOID context)
1483 {
1484 PUHCI_DEV uhci;
1485 PLIST_ENTRY pthis, pnext, ptemp;
1486 PURB purb;
1487 PSYNC_PARAM pparam;
1488
1489 pparam = (PSYNC_PARAM) context;
1490 uhci = pparam->uhci;
1491 ptemp = (PLIST_ENTRY) pparam->context;
1492
1493 if (uhci == NULL)
1494 {
1495 return (UCHAR) (pparam->ret = FALSE);
1496 }
1497
1498 ListFirst(&uhci->urb_list, pthis);
1499 while (pthis)
1500 {
1501 //remove urbs not in the schedule
1502 ListNext(&uhci->urb_list, pthis, pnext);
1503 purb = (PURB) pthis;
1504
1505 if ((purb->flags & URB_FLAG_IN_SCHEDULE) == 0)
1506 {
1507 //finished or canceled( not apply for split bulk ).
1508 purb->flags &= ~URB_FLAG_STATE_MASK;
1509 purb->flags |= URB_FLAG_STATE_FINISHED;
1510 RemoveEntryList(pthis);
1511 InsertTailList(ptemp, pthis);
1512 }
1513 pthis = pnext;
1514 }
1515 pparam->ret = TRUE;
1516 return (UCHAR) TRUE;
1517 }
1518
1519 BOOLEAN
1520 uhci_drop_fsbr(PUHCI_DEV uhci)
1521 {
1522 if (uhci == NULL)
1523 return (UCHAR) FALSE;
1524
1525 uhci->fsbr_cnt--;
1526
1527 if (uhci->fsbr_cnt <= 0)
1528 {
1529 uhci->skel_term_qh->link = UHCI_PTR_TERM;
1530 uhci->fsbr_cnt = 0;
1531 }
1532
1533 return (UCHAR) TRUE;
1534 }
1535
1536 VOID NTAPI
1537 uhci_dpc_callback(PKDPC dpc, PVOID context, PVOID sysarg1, PVOID sysarg2)
1538 {
1539 PUHCI_DEV uhci;
1540
1541 LIST_HEAD temp_list;
1542 PLIST_ENTRY pthis, pnext;
1543 PURB purb;
1544 PQH_EXTENSION pqhe;
1545 PUHCI_PENDING_ENDP pending_endp;
1546 PUSB_DEV pdev;
1547 PUSB_ENDPOINT pendp;
1548
1549 BOOLEAN finished;
1550 LONG i, j;
1551 ULONG uhci_status, urb_status, toggle = 0;
1552
1553 SYNC_PARAM sync_param;
1554 USE_BASIC_NON_PENDING_IRQL;
1555
1556 UNREFERENCED_PARAMETER(dpc);
1557 UNREFERENCED_PARAMETER(sysarg2);
1558
1559 uhci = (PUHCI_DEV) context;
1560 if (uhci == NULL)
1561 return;
1562
1563 uhci_status = (ULONG) sysarg1;
1564
1565 InitializeListHead(&temp_list);
1566
1567 sync_param.uhci = uhci;
1568 sync_param.context = (PVOID) & temp_list;
1569
1570 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_dpc_callback(): entering..., uhci=0x%x\n", uhci));
1571 //remove finished urb from uhci's urb-list
1572 KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_remove_urb_finished, &sync_param);
1573
1574 //release resources( tds, and qhs ) the urb occupied
1575 while (IsListEmpty(&temp_list) == FALSE)
1576 {
1577 //not in any public queue, if do not access into dev, no race
1578 //condition will occur
1579 purb = (PURB) RemoveHeadList(&temp_list);
1580 urb_status = purb->status;
1581
1582 //the only place we do not use this lock on non-pending-endp-list data ops
1583 KeAcquireSpinLockAtDpcLevel(&uhci->pending_endp_list_lock);
1584 while (IsListEmpty(&purb->trasac_list) == FALSE)
1585 {
1586 pthis = RemoveHeadList(&purb->trasac_list);
1587
1588 if ((((PTD_EXTENSION) pthis)->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
1589 {
1590 pqhe = (PQH_EXTENSION) pthis;
1591 lock_qh_pool(&uhci->qh_pool, TRUE);
1592 free_qh(&uhci->qh_pool, pqhe->pqh);
1593 unlock_qh_pool(&uhci->qh_pool, TRUE);
1594 }
1595 else
1596 {
1597 //must be a td chain
1598 InsertHeadList(&purb->trasac_list, pthis);
1599 for(i = 0, purb->bytes_transfered = 0; i < purb->td_count; i++)
1600 {
1601 PUHCI_TD ptd;
1602 // accumulate data transfered in tds
1603 ptd = ((PTD_EXTENSION) pthis)->ptd;
1604 if ((ptd->status & TD_CTRL_ACTIVE) == 0 && (ptd->status & TD_CTRL_ANY_ERROR) == 0)
1605 {
1606 j = ptd->status & 0x7ff;
1607 purb->bytes_transfered += ((j == 0x7ff) ? 0 : (j + 1));
1608
1609 }
1610 ListNext(&purb->trasac_list, pthis, pnext);
1611 pthis = pnext;
1612 }
1613
1614 if (urb_status & TD_CTRL_ANY_ERROR)
1615 {
1616 if (purb->last_finished_td != NULL && purb->last_finished_td != &purb->trasac_list)
1617 toggle = (((PTD_EXTENSION) purb->last_finished_td)->ptd->info & (1 << 19));
1618 }
1619 //trick, remove trasac_list
1620 ListFirst(&purb->trasac_list, pthis);
1621 RemoveEntryList(&purb->trasac_list);
1622 lock_td_pool(&uhci->td_pool, TRUE);
1623 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
1624 unlock_td_pool(&uhci->td_pool, TRUE);
1625 //termination condition
1626 InitializeListHead(&purb->trasac_list);
1627 purb->last_finished_td = NULL;
1628 }
1629 }
1630
1631 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_ISOC
1632 || endp_type(purb->pendp) == USB_ENDPOINT_XFER_INT)
1633 uhci_claim_bandwidth(uhci, purb, FALSE); //release band-width
1634
1635 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1636
1637 uhci_set_error_code(purb, urb_status);
1638
1639 finished = TRUE;
1640
1641 //since the ref_count for the urb is not released, we can safely have one
1642 //pointer to dev
1643 pdev = dev_from_endp(purb->pendp);
1644 pendp = purb->pendp;
1645
1646 if (purb->status == USB_STATUS_BABBLE_DETECTED)
1647 {
1648 usb_dbg_print(DBGLVL_MEDIUM,
1649 ("uhci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus\n"));
1650 uhci_reset(uhci);
1651 uhci_start(&uhci->hcd_interf);
1652 }
1653
1654 //this will let the new request in uhci_generic_urb_completion to this endp
1655 //be processed rather than queued in the pending_endp_list
1656 lock_dev(pdev, TRUE);
1657 usb_endp_busy_count_dec(pendp);
1658 unlock_dev(pdev, TRUE);
1659
1660 if (usb_success(purb->status) == FALSE)
1661 {
1662 // set error code and complete the urb and purb is invalid from this point
1663 uhci_generic_urb_completion(purb, purb->context);
1664 }
1665 else
1666 {
1667 if ((purb->pipe & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
1668 {
1669 purb->rest_bytes -= purb->bytes_transfered;
1670 if (purb->rest_bytes)
1671 {
1672 finished = FALSE;
1673 }
1674 else
1675 {
1676 uhci_generic_urb_completion(purb, purb->context);
1677 }
1678 }
1679 else
1680 {
1681 uhci_generic_urb_completion(purb, purb->context);
1682 //purb is now invalid
1683 }
1684 }
1685
1686 KeAcquireSpinLockAtDpcLevel(&uhci->pending_endp_list_lock);
1687 lock_dev(pdev, TRUE);
1688
1689 if (finished)
1690 pdev->ref_count--;
1691
1692 if (urb_status & TD_CTRL_ANY_ERROR && endp_type(pendp) != USB_ENDPOINT_XFER_CONTROL)
1693 {
1694 pendp->flags &= ~USB_ENDP_FLAG_STAT_MASK;
1695 pendp->flags |= USB_ENDP_FLAG_STALL;
1696 }
1697
1698 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1699 {
1700 unlock_dev(pdev, TRUE);
1701 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1702 if (finished == FALSE)
1703 {
1704
1705 purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1706 uhci_generic_urb_completion(purb, purb->context);
1707
1708 lock_dev(pdev, TRUE);
1709 pdev->ref_count--;
1710 unlock_dev(pdev, TRUE);
1711 }
1712 continue;
1713 }
1714
1715 if (finished && IsListEmpty(&pendp->urb_list) == TRUE)
1716 {
1717 unlock_dev(pdev, TRUE);
1718 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1719 continue;
1720 }
1721 else if (finished == TRUE)
1722 {
1723 //has urb in the endp's urb-list
1724 if (usb_endp_busy_count(pendp) > 0)
1725 {
1726 //the urbs still have chance to be sheduled but not this time
1727 unlock_dev(pdev, TRUE);
1728 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1729 continue;
1730 }
1731 }
1732
1733 if (finished == FALSE)
1734 {
1735 //a split bulk transfer
1736 purb->bytes_transfered = 0;
1737 purb->bytes_to_transfer =
1738 UHCI_MAX_TDS_PER_TRANSFER * purb->pendp->pusb_endp_desc->wMaxPacketSize
1739 > purb->rest_bytes
1740 ? purb->rest_bytes : UHCI_MAX_TDS_PER_TRANSFER * purb->pendp->pusb_endp_desc->wMaxPacketSize;
1741
1742 //the urb is not finished
1743 purb->flags &= ~URB_FLAG_STATE_MASK;
1744 purb->flags |= URB_FLAG_STATE_PENDING;
1745
1746 InsertHeadList(&pendp->urb_list, (PLIST_ENTRY) purb);
1747 }
1748
1749 pending_endp = alloc_pending_endp(&uhci->pending_endp_pool, 1);
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, (PLIST_ENTRY) urb);
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 pdev = purb->pdev;
3126 if (purb == NULL)
3127 return;
3128
3129 if (pdev == NULL)
3130 return;
3131
3132 lock_dev(pdev, TRUE);
3133
3134 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
3135 {
3136 unlock_dev(pdev, TRUE);
3137 goto LBL_CLIENT_PROCESS;
3138 }
3139 if (usb_error(purb->status))
3140 {
3141 pdev->error_count++;
3142 }
3143
3144 if (purb->pendp == &pdev->default_endp)
3145 {
3146 if (usb_halted(purb->status))
3147 {
3148 pdev->time_out_count++;
3149 if (pdev->time_out_count > 3)
3150 {
3151 dev_set_state(pdev, USB_DEV_STATE_ZOMB);
3152 uhci_dbg_print(DBGLVL_MAXIMUM,
3153 ("uhci_generic_urb_completion(): contiguous error 3 times, dev 0x%x is deactivated\n",
3154 pdev));
3155 }
3156 }
3157 else
3158 pdev->time_out_count = 0;
3159
3160 }
3161 unlock_dev(pdev, TRUE);
3162
3163 LBL_CLIENT_PROCESS:
3164 if (purb->completion)
3165 purb->completion(purb, context);
3166
3167 if (old_irql < DISPATCH_LEVEL)
3168 KeLowerIrql(old_irql);
3169
3170 return;
3171 }
3172
3173
3174 NTSTATUS
3175 uhci_rh_submit_urb(PUSB_DEV pdev, PURB purb)
3176 {
3177 PUSB_DEV_MANAGER dev_mgr;
3178 PTIMER_SVC ptimer;
3179 PUSB_CTRL_SETUP_PACKET psetup;
3180 PUHCI_DEV uhci;
3181 NTSTATUS status;
3182 USHORT port_status;
3183 #ifndef INCLUDE_EHCI
3184 PHUB_EXTENSION hub_ext;
3185 #else
3186 PHUB2_EXTENSION hub_ext;
3187 #endif
3188 PUSB_PORT_STATUS ps, psret;
3189 LONG i;
3190 USE_NON_PENDING_IRQL;
3191
3192 if (pdev == NULL || purb == NULL)
3193 return STATUS_INVALID_PARAMETER;
3194
3195 dev_mgr = dev_mgr_from_dev(pdev);
3196
3197 KeAcquireSpinLock(&dev_mgr->timer_svc_list_lock, &old_irql);
3198 lock_dev(pdev, FALSE);
3199 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
3200 {
3201 unlock_dev(pdev, FALSE);
3202 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
3203 return STATUS_DEVICE_DOES_NOT_EXIST;
3204 }
3205
3206 uhci = uhci_from_hcd(pdev->hcd);
3207 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
3208
3209 #ifndef INCLUDE_EHCI
3210 hub_ext = ((PHUB_EXTENSION) pdev->dev_ext);
3211 #else
3212 hub_ext = ((PHUB2_EXTENSION) pdev->dev_ext);
3213 #endif
3214
3215 switch (endp_type(purb->pendp))
3216 {
3217 case USB_ENDPOINT_XFER_CONTROL:
3218 {
3219 if (psetup->bmRequestType == 0xa3 && psetup->bRequest == USB_REQ_GET_STATUS)
3220 {
3221 //get-port-status
3222 if (psetup->wIndex == 0 || psetup->wIndex > 2 || psetup->wLength < 4)
3223 {
3224 purb->status = STATUS_INVALID_PARAMETER;
3225 break;
3226 }
3227 if (psetup->wIndex == 1)
3228 {
3229 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBPORTSC1));
3230 ps = &hub_ext->rh_port1_status;
3231 }
3232 else
3233 {
3234 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBPORTSC2));
3235 ps = &hub_ext->rh_port2_status;
3236 }
3237
3238 psret = (PUSB_PORT_STATUS) purb->data_buffer;
3239 ps->wPortStatus = 0;
3240
3241 if (status & USBPORTSC_CCS)
3242 {
3243 ps->wPortStatus |= USB_PORT_STAT_CONNECTION;
3244 }
3245 if (status & USBPORTSC_PE)
3246 {
3247 ps->wPortStatus |= USB_PORT_STAT_ENABLE;
3248 }
3249 if (status & USBPORTSC_PR)
3250 {
3251 ps->wPortStatus |= USB_PORT_STAT_RESET;
3252 }
3253 if (status & USBPORTSC_SUSP)
3254 {
3255 ps->wPortStatus |= USB_PORT_STAT_SUSPEND;
3256 }
3257 if (status & USBPORTSC_LSDA)
3258 {
3259 ps->wPortStatus |= USB_PORT_STAT_LOW_SPEED;
3260 }
3261
3262 //always power on
3263 ps->wPortStatus |= USB_PORT_STAT_POWER;
3264
3265 //now set change field
3266 if (status & USBPORTSC_CSC)
3267 {
3268 ps->wPortChange |= USB_PORT_STAT_C_CONNECTION;
3269 }
3270 if (status & USBPORTSC_PEC)
3271 {
3272 ps->wPortChange |= USB_PORT_STAT_C_ENABLE;
3273 }
3274
3275 //don't touch other fields, will be filled by
3276 //other function
3277
3278 usb_dbg_print(DBGLVL_MAXIMUM,
3279 ("uhci_rh_submit_urb(): get port status, wPortStatus=0x%x, wPortChange=0x%x, address=0x%x\n",
3280 ps->wPortStatus, ps->wPortChange, ps));
3281
3282 psret->wPortChange = ps->wPortChange;
3283 psret->wPortStatus = ps->wPortStatus;
3284
3285 purb->status = STATUS_SUCCESS;
3286
3287 break;
3288 }
3289 else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_CLEAR_FEATURE)
3290 {
3291 //clear-port-feature
3292 if (psetup->wIndex == 0 || psetup->wIndex > 2)
3293 {
3294 purb->status = STATUS_INVALID_PARAMETER;
3295 break;
3296 }
3297 if (psetup->wIndex == 1)
3298 {
3299 i = USBPORTSC1;
3300 ps = &hub_ext->rh_port1_status;
3301 }
3302 else
3303 {
3304 i = USBPORTSC2;
3305 ps = &hub_ext->rh_port2_status;
3306 }
3307
3308 purb->status = STATUS_SUCCESS;
3309 switch (psetup->wValue)
3310 {
3311 case USB_PORT_FEAT_C_CONNECTION:
3312 {
3313 ps->wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
3314 SET_RH_PORTSTAT(i, USBPORTSC_CSC);
3315 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + i));
3316 usb_dbg_print(DBGLVL_MAXIMUM,
3317 ("uhci_rh_submit_urb(): clear csc, port%d=0x%x\n", psetup->wIndex,
3318 status));
3319 break;
3320 }
3321 case USB_PORT_FEAT_C_ENABLE:
3322 {
3323 ps->wPortChange &= ~USB_PORT_STAT_C_ENABLE;
3324 SET_RH_PORTSTAT(i, USBPORTSC_PEC);
3325 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + i));
3326 usb_dbg_print(DBGLVL_MAXIMUM,
3327 ("uhci_rh_submit_urb(): clear pec, port%d=0x%x\n", psetup->wIndex,
3328 status));
3329 break;
3330 }
3331 case USB_PORT_FEAT_C_RESET:
3332 {
3333 ps->wPortChange &= ~USB_PORT_STAT_C_RESET;
3334 //the reset signal is down in rh_timer_svc_reset_port_completion
3335 //so enable the port here
3336 status = READ_PORT_USHORT((PUSHORT)(uhci->port_base + i));
3337 usb_dbg_print(DBGLVL_MAXIMUM,
3338 ("uhci_rh_submit_urb(): clear pr, enable pe, port%d=0x%x\n",
3339 psetup->wIndex, status));
3340 break;
3341 }
3342 case USB_PORT_FEAT_ENABLE:
3343 {
3344 ps->wPortStatus &= ~USB_PORT_STAT_ENABLE;
3345 CLR_RH_PORTSTAT(i, USBPORTSC_PE);
3346 status = READ_PORT_USHORT((PUSHORT)(uhci->port_base + i));
3347 usb_dbg_print(DBGLVL_MAXIMUM,
3348 ("uhci_rh_submit_urb(): clear pe, port%d=0x%x\n", psetup->wIndex,
3349 status));
3350 break;
3351 }
3352 default:
3353 purb->status = STATUS_UNSUCCESSFUL;
3354 }
3355 break;
3356 }
3357 else if (psetup->bmRequestType == 0xd3 && psetup->bRequest == HUB_REQ_GET_STATE)
3358 {
3359 // get bus state
3360 if (psetup->wIndex == 0 || psetup->wIndex > 2 || psetup->wLength == 0)
3361 {
3362 purb->status = STATUS_INVALID_PARAMETER;
3363 break;
3364 }
3365
3366 if (psetup->wIndex == 1)
3367 {
3368 i = USBPORTSC1;
3369 }
3370 else
3371 {
3372 i = USBPORTSC2;
3373 }
3374 port_status = READ_PORT_USHORT((PUSHORT)(uhci->port_base + i));
3375 purb->data_buffer[0] = (port_status & USBPORTSC_LS);
3376
3377 // reverse the order
3378 purb->data_buffer[0] ^= 0x3;
3379 purb->status = STATUS_SUCCESS;
3380 break;
3381 }
3382 else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_SET_FEATURE)
3383 {
3384 //reset port
3385 if (psetup->wValue != USB_PORT_FEAT_RESET)
3386 {
3387 purb->status = STATUS_INVALID_PARAMETER;
3388 uhci_dbg_print(DBGLVL_MAXIMUM,
3389 ("uhci_rh_submit_urb(): set feature with wValue=0x%x\n", psetup->wValue));
3390 break;
3391 }
3392 if (psetup->wIndex == 1)
3393 {
3394 i = USBPORTSC1;
3395 }
3396 else
3397 {
3398 i = USBPORTSC2;
3399 }
3400
3401 ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
3402 ptimer->threshold = 0; // within [ 50ms, 60ms ], one tick is 10 ms
3403 ptimer->context = (ULONG) purb;
3404 ptimer->pdev = pdev;
3405 ptimer->func = rh_timer_svc_reset_port_completion;
3406
3407 //start the timer
3408 pdev->ref_count += 2; //one for timer and one for urb
3409
3410 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + i));
3411 usb_dbg_print(DBGLVL_MAXIMUM,
3412 ("uhci_rh_submit_urb(): reset port, port%d=0x%x\n", psetup->wIndex, status));
3413 InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
3414 purb->status = STATUS_PENDING;
3415 }
3416 else
3417 {
3418 purb->status = STATUS_INVALID_PARAMETER;
3419 }
3420 break;
3421 }
3422 case USB_ENDPOINT_XFER_INT:
3423 {
3424 ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
3425 ptimer->threshold = RH_INTERVAL;
3426 ptimer->context = (ULONG) purb;
3427 ptimer->pdev = pdev;
3428 ptimer->func = rh_timer_svc_int_completion;
3429
3430 //start the timer
3431 InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
3432
3433 usb_dbg_print(DBGLVL_ULTRA,
3434 ("uhci_rh_submit_urb(): current rh's ref_count=0x%x\n", pdev->ref_count));
3435 pdev->ref_count += 2; //one for timer and one for urb
3436
3437 purb->status = STATUS_PENDING;
3438 break;
3439 }
3440 case USB_ENDPOINT_XFER_BULK:
3441 case USB_ENDPOINT_XFER_ISOC:
3442 default:
3443 {
3444 purb->status = STATUS_INVALID_PARAMETER;
3445 break;
3446 }
3447 }
3448 unlock_dev(pdev, FALSE);
3449 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
3450 return purb->status;
3451 }
3452
3453 //must have rh dev_lock acquired
3454 BOOLEAN
3455 uhci_rh_reset_port(PHCD hcd, UCHAR port_idx)
3456 {
3457 LONG i;
3458 PUHCI_DEV uhci;
3459 ULONG status;
3460
3461 if (port_idx != 1 && port_idx != 2)
3462 return FALSE;
3463
3464 if (hcd == NULL)
3465 return FALSE;
3466
3467 if (port_idx == 1)
3468 {
3469 i = USBPORTSC1;
3470 }
3471 else
3472 {
3473 i = USBPORTSC2;
3474 }
3475
3476 uhci = uhci_from_hcd(hcd);
3477 //assert the reset signal,(implicitly disable the port)
3478 SET_RH_PORTSTAT(i, USBPORTSC_PR);
3479 usb_wait_ms_dpc(50);
3480 //clear the reset signal, delay port enable till clearing port feature
3481 CLR_RH_PORTSTAT(i, USBPORTSC_PR);
3482 usb_wait_us_dpc(10);
3483 SET_RH_PORTSTAT(i, USBPORTSC_PE);
3484 //recovery time 10ms
3485 usb_wait_ms_dpc(10);
3486 SET_RH_PORTSTAT(i, 0x0a);
3487
3488 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + i));
3489 usb_dbg_print(DBGLVL_MAXIMUM, ("uhci_rh_reset_port(): status after written=0x%x\n", status));
3490
3491 return TRUE;
3492 }
3493
3494 NTSTATUS
3495 uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp)
3496 {
3497 PDEVICE_EXTENSION pdev_ext;
3498 PUSB_DEV_MANAGER dev_mgr;
3499 PUHCI_DEV uhci;
3500
3501 pdev_ext = DeviceObject->DeviceExtension;
3502 uhci = pdev_ext->uhci;
3503
3504 dev_mgr = uhci->hcd_interf.hcd_get_dev_mgr(&uhci->hcd_interf);
3505 return dev_mgr_dispatch(dev_mgr, irp);
3506 }
3507
3508 VOID NTAPI
3509 uhci_unload(IN PDRIVER_OBJECT DriverObject)
3510 {
3511 PDEVICE_OBJECT pdev;
3512 PDEVICE_EXTENSION pdev_ext;
3513 PUSB_DEV_MANAGER dev_mgr;
3514
3515 pdev = DriverObject->DeviceObject;
3516
3517 if (pdev == NULL)
3518 return;
3519
3520 pdev_ext = pdev->DeviceExtension;
3521 if (pdev_ext == NULL)
3522 return;
3523
3524 dev_mgr = &g_dev_mgr;
3525 if (dev_mgr == NULL)
3526 return;
3527 //
3528 // set the termination flag
3529 //
3530 dev_mgr->term_flag = TRUE;
3531
3532 //
3533 // wake up the thread if it is
3534 //
3535 KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE);
3536 KeWaitForSingleObject(dev_mgr->pthread, Executive, KernelMode, TRUE, NULL);
3537 ObDereferenceObject(dev_mgr->pthread);
3538 dev_mgr->pthread = NULL;
3539 // for( i = 0; i < dev_mgr->hcd_count; i++ )
3540 // dev_mgr->hcd_array[ i ]->hcd_release( dev_mgr->hcd_array[ i ]);
3541 dev_mgr_release_hcd(dev_mgr);
3542
3543 return;
3544 }
3545
3546 //the following are for hcd interface methods
3547 VOID
3548 uhci_set_dev_mgr(struct _HCD * hcd, PUSB_DEV_MANAGER dev_mgr)
3549 {
3550 hcd->dev_mgr = dev_mgr;
3551 }
3552
3553 PUSB_DEV_MANAGER
3554 uhci_get_dev_mgr(struct _HCD *hcd)
3555 {
3556 return hcd->dev_mgr;
3557 }
3558
3559 ULONG
3560 uhci_get_type(struct _HCD * hcd)
3561 {
3562 return (hcd->flags & HCD_TYPE_MASK);
3563 }
3564
3565 VOID
3566 uhci_set_id(struct _HCD * hcd, UCHAR id)
3567 {
3568 hcd->flags &= ~HCD_ID_MASK;
3569 hcd->flags |= (HCD_ID_MASK & id);
3570 }
3571
3572 UCHAR
3573 uhci_get_id(struct _HCD *hcd)
3574 {
3575 return (UCHAR) (hcd->flags & HCD_ID_MASK);
3576 }
3577
3578
3579 UCHAR
3580 uhci_alloc_addr(struct _HCD * hcd)
3581 {
3582 LONG i;
3583 if (hcd == NULL)
3584 return 0;
3585
3586 for(i = 1; i < MAX_DEVS; i++)
3587 {
3588 if (hcd->dev_addr_map[i >> 3] & (1 << (i & 7)))
3589 {
3590 continue;
3591 }
3592 else
3593 {
3594 break;
3595 }
3596 }
3597
3598 if (i >= MAX_DEVS)
3599 return 0xff;
3600
3601 hcd->dev_addr_map[i >> 3] |= (1 << (i & 7));
3602 hcd->conn_count++;
3603 return (BYTE) i;
3604 }
3605
3606 VOID
3607 uhci_free_addr(struct _HCD * hcd, UCHAR addr)
3608 {
3609 if (addr & 0x80)
3610 return;
3611
3612 if (hcd == NULL)
3613 return;
3614
3615 hcd->dev_addr_map[addr >> 3] &= ~(1 << (addr & 7));
3616 return;
3617
3618 }
3619
3620 NTSTATUS
3621 uhci_submit_urb2(struct _HCD * hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
3622 {
3623 return uhci_submit_urb(uhci_from_hcd(hcd), pdev, pendp, purb);
3624 }
3625
3626 PUSB_DEV
3627 uhci_get_root_hub(struct _HCD * hcd)
3628 {
3629 return uhci_from_hcd(hcd)->root_hub;
3630 }
3631
3632 VOID
3633 uhci_set_root_hub(struct _HCD * hcd, PUSB_DEV root_hub)
3634 {
3635 if (hcd == NULL || root_hub == NULL)
3636 return;
3637 uhci_from_hcd(hcd)->root_hub = root_hub;
3638 return;
3639 }
3640
3641 BOOLEAN
3642 uhci_remove_device2(struct _HCD * hcd, PUSB_DEV pdev)
3643 {
3644 if (hcd == NULL || pdev == NULL)
3645 return FALSE;
3646
3647 return uhci_remove_device(uhci_from_hcd(hcd), pdev);
3648 }
3649
3650 BOOLEAN
3651 uhci_hcd_release(struct _HCD * hcd)
3652 {
3653 PUHCI_DEV uhci;
3654 PDEVICE_EXTENSION pdev_ext;
3655
3656 if (hcd == NULL)
3657 return FALSE;
3658
3659
3660 uhci = uhci_from_hcd(hcd);
3661 pdev_ext = uhci->pdev_ext;
3662
3663 return uhci_release(pdev_ext->pdev_obj);
3664 }
3665
3666 NTSTATUS
3667 uhci_cancel_urb2(struct _HCD * hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
3668 {
3669 PUHCI_DEV uhci;
3670 if (hcd == NULL)
3671 return STATUS_INVALID_PARAMETER;
3672
3673 uhci = uhci_from_hcd(hcd);
3674 return uhci_cancel_urb(uhci, pdev, pendp, purb);
3675 }
3676
3677 BOOLEAN
3678 uhci_rh_get_dev_change(PHCD hcd, PBYTE buf)
3679 {
3680 PUHCI_DEV uhci;
3681 ULONG status;
3682
3683 if (hcd == NULL || buf == NULL)
3684 return FALSE;
3685
3686 uhci = uhci_from_hcd(hcd);
3687 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBPORTSC1));
3688 usb_dbg_print(DBGLVL_ULTRA, ("uhci_rh_get_dev_change(): rh port1 status=0x%x\n", status));
3689
3690 if ((status & USBPORTSC_PEC) || (status & USBPORTSC_CSC))
3691 {
3692 buf[0] |= (1 << 1);
3693 }
3694
3695 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBPORTSC2));
3696 usb_dbg_print(DBGLVL_ULTRA, ("uhci_rh_get_dev_change(): rh port2 status=0x%x\n", status));
3697
3698 if ((status & USBPORTSC_PEC) || (status & USBPORTSC_CSC))
3699 {
3700 buf[0] |= (1 << 2);
3701 }
3702 return TRUE;
3703 }
3704
3705 NTSTATUS
3706 uhci_dispatch(PHCD hcd, LONG disp_code, PVOID param) // locking depends on type of code
3707 {
3708 if (hcd == NULL)
3709 return FALSE;
3710
3711 switch (disp_code)
3712 {
3713 case HCD_DISP_READ_PORT_COUNT:
3714 {
3715 if (param == NULL)
3716 return STATUS_INVALID_PARAMETER;
3717 *((PUCHAR) param) = 2;
3718 return STATUS_SUCCESS;
3719 }
3720 case HCD_DISP_READ_RH_DEV_CHANGE:
3721 {
3722 if (uhci_rh_get_dev_change(hcd, param) == FALSE)
3723 return STATUS_INVALID_PARAMETER;
3724 return STATUS_SUCCESS;
3725 }
3726 }
3727
3728 return STATUS_NOT_IMPLEMENTED;
3729 }
3730
3731 VOID
3732 uhci_init_hcd_interface(PUHCI_DEV uhci)
3733 {
3734 uhci->hcd_interf.hcd_set_dev_mgr = uhci_set_dev_mgr;
3735 uhci->hcd_interf.hcd_get_dev_mgr = uhci_get_dev_mgr;
3736 uhci->hcd_interf.hcd_get_type = uhci_get_type;
3737 uhci->hcd_interf.hcd_set_id = uhci_set_id;
3738 uhci->hcd_interf.hcd_get_id = uhci_get_id;
3739 uhci->hcd_interf.hcd_alloc_addr = uhci_alloc_addr;
3740 uhci->hcd_interf.hcd_free_addr = uhci_free_addr;
3741 uhci->hcd_interf.hcd_submit_urb = uhci_submit_urb2;
3742 uhci->hcd_interf.hcd_generic_urb_completion = uhci_generic_urb_completion;
3743 uhci->hcd_interf.hcd_get_root_hub = uhci_get_root_hub;
3744 uhci->hcd_interf.hcd_set_root_hub = uhci_set_root_hub;
3745 uhci->hcd_interf.hcd_remove_device = uhci_remove_device2;
3746 uhci->hcd_interf.hcd_rh_reset_port = uhci_rh_reset_port;
3747 uhci->hcd_interf.hcd_release = uhci_hcd_release;
3748 uhci->hcd_interf.hcd_cancel_urb = uhci_cancel_urb2;
3749 uhci->hcd_interf.hcd_start = uhci_start;
3750 uhci->hcd_interf.hcd_dispatch = uhci_dispatch;
3751
3752 uhci->hcd_interf.flags = HCD_TYPE_UHCI; //hcd types | hcd id
3753 }
3754
3755
3756 NTSTATUS NTAPI
3757 generic_dispatch_irp(IN PDEVICE_OBJECT dev_obj, IN PIRP irp)
3758 {
3759 PDEVEXT_HEADER dev_ext;
3760
3761 dev_ext = (PDEVEXT_HEADER) dev_obj->DeviceExtension;
3762
3763 if (dev_ext && dev_ext->dispatch)
3764 return dev_ext->dispatch(dev_obj, irp);
3765
3766 irp->IoStatus.Information = 0;
3767
3768 EXIT_DISPATCH(STATUS_UNSUCCESSFUL, irp);
3769 }
3770
3771
3772 VOID NTAPI
3773 generic_start_io(IN PDEVICE_OBJECT dev_obj, IN PIRP irp)
3774 {
3775 PDEVEXT_HEADER dev_ext;
3776
3777 KIRQL old_irql;
3778
3779 IoAcquireCancelSpinLock(&old_irql);
3780 if (irp != dev_obj->CurrentIrp || irp->Cancel)
3781 {
3782 IoReleaseCancelSpinLock(old_irql);
3783 return;
3784 }
3785 else
3786 {
3787 (void)IoSetCancelRoutine(irp, NULL);
3788 IoReleaseCancelSpinLock(old_irql);
3789 }
3790
3791 dev_ext = (PDEVEXT_HEADER) dev_obj->DeviceExtension;
3792
3793 if (dev_ext && dev_ext->start_io)
3794 {
3795 dev_ext->start_io(dev_obj, irp);
3796 return;
3797 }
3798
3799 irp->IoStatus.Information = 0;
3800 irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
3801
3802 IoStartNextPacket(dev_obj, FALSE);
3803 IoCompleteRequest(irp, IO_NO_INCREMENT);
3804 }
3805
3806 NTSTATUS
3807 DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
3808 {
3809 #if DBG
3810 NTSTATUS ntStatus = STATUS_SUCCESS;
3811
3812 // should be done before any debug output is done.
3813 // read our debug verbosity level from the registry
3814 //NetacOD_GetRegistryDword( NetacOD_REGISTRY_PARAMETERS_PATH, //absolute registry path
3815 // L"DebugLevel", // REG_DWORD ValueName
3816 // &gDebugLevel ); // Value receiver
3817
3818 // debug_level = DBGLVL_MAXIMUM;
3819 #endif
3820
3821 uhci_dbg_print_cond(DBGLVL_MINIMUM, DEBUG_UHCI,
3822 ("Entering DriverEntry(), RegistryPath=\n %ws\n", RegistryPath->Buffer));
3823
3824 // Remember our driver object, for when we create our child PDO
3825 usb_driver_obj = DriverObject;
3826
3827 //
3828 // Create dispatch points for create, close, unload
3829 DriverObject->MajorFunction[IRP_MJ_CREATE] = generic_dispatch_irp;
3830 DriverObject->MajorFunction[IRP_MJ_CLOSE] = generic_dispatch_irp;
3831 DriverObject->DriverUnload = uhci_unload;
3832
3833 // User mode DeviceIoControl() calls will be routed here
3834 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = generic_dispatch_irp;
3835 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = generic_dispatch_irp;
3836
3837 // User mode ReadFile()/WriteFile() calls will be routed here
3838 DriverObject->MajorFunction[IRP_MJ_WRITE] = generic_dispatch_irp;
3839 DriverObject->MajorFunction[IRP_MJ_READ] = generic_dispatch_irp;
3840
3841 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = generic_dispatch_irp;
3842 DriverObject->MajorFunction[IRP_MJ_SCSI] = generic_dispatch_irp;
3843 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = generic_dispatch_irp;
3844
3845 DriverObject->DriverStartIo = generic_start_io;
3846 // routines for handling system PNP and power management requests
3847 //DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = generic_dispatch_irp;
3848
3849 // The Functional Device Object (FDO) will not be created for PNP devices until
3850 // this routine is called upon device plug-in.
3851 RtlZeroMemory(&g_dev_mgr, sizeof(USB_DEV_MANAGER));
3852 g_dev_mgr.usb_driver_obj = DriverObject;
3853
3854 #ifdef INCLUDE_EHCI
3855 ehci_probe(DriverObject, RegistryPath, &g_dev_mgr);
3856 #endif
3857
3858 uhci_probe(DriverObject, RegistryPath, &g_dev_mgr);
3859
3860 if (dev_mgr_strobe(&g_dev_mgr) == FALSE)
3861 {
3862
3863 dev_mgr_release_hcd(&g_dev_mgr);
3864 return STATUS_UNSUCCESSFUL;
3865 }
3866
3867 dev_mgr_start_hcd(&g_dev_mgr);
3868
3869 uhci_dbg_print_cond(DBGLVL_DEFAULT, DEBUG_UHCI, ("DriverEntry(): exiting... (%x)\n", ntStatus));
3870 return STATUS_SUCCESS;
3871 }
3872
3873 //note: the initialization will be in the following order
3874 // uhci_probe
3875 // dev_mgr_strobe
3876 // uhci_start
3877
3878 // to kill dev_mgr_thread:
3879 // dev_mgr->term_flag = TRUE;
3880 // KeSetEvent( &dev_mgr->wake_up_event );
3881 // this piece of code must run at passive-level