- Fix release build.
[reactos.git] / reactos / drivers / usb / nt4compat / usbdriver / uhci.c
1 /**
2 * uhci.c - USB driver stack project for Windows NT 4.0
3 *
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
5 *
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program (in the main directory of the distribution, the file
18 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "usbdriver.h"
23
24 //----------------------------------------------------------
25 // uhci routines
26 //#define DEMO
27
28 #ifdef INCLUDE_EHCI
29
30 #define rh_port1_status rh_port_status[ 1 ]
31 #define rh_port2_status rh_port_status[ 2 ]
32
33 extern PDEVICE_OBJECT ehci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr);
34
35 #endif
36
37 #define DEFAULT_ENDP( enDP ) \
38 ( enDP->flags & USB_ENDP_FLAG_DEFAULT_ENDP )
39
40 #define dev_from_endp( enDP ) \
41 ( DEFAULT_ENDP( enDP )\
42 ? ( ( PUSB_DEV )( enDP )->pusb_if )\
43 : ( ( enDP )->pusb_if->pusb_config->pusb_dev ) )
44
45 #define endp_state( enDP ) ( ( enDP )->flags & USB_ENDP_FLAG_STAT_MASK )
46
47 #define endp_num( enDP ) \
48 ( DEFAULT_ENDP( enDP )\
49 ? 0 \
50 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & 0x0f ) )
51
52 #define endp_dir( enDP ) \
53 ( DEFAULT_ENDP( enDP )\
54 ? 0L\
55 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & USB_DIR_IN ) )
56
57 #define dev_set_state( pdEV, staTE ) \
58 ( pdEV->flags = ( ( pdEV )->flags & ( ~USB_DEV_STATE_MASK ) ) | ( staTE ) )
59
60 #define endp_max_packet_size( enDP ) \
61 ( DEFAULT_ENDP( enDP )\
62 ? ( ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc ? \
63 ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc->bMaxPacketSize0\
64 : 8 )\
65 : enDP->pusb_endp_desc->wMaxPacketSize )
66
67
68 #if 0
69 /* WTF?! */
70 #define release_adapter( padapTER ) \
71 {\
72 ( ( padapTER ) ); \
73 }
74 #else
75 #define release_adapter( padapTER ) (void)(padapTER)
76 #endif
77
78 #define get_int_idx( _urb, _idx ) \
79 {\
80 UCHAR interVAL;\
81 interVAL = ( UCHAR )( ( _urb )->pipe >> 24 );\
82 for( _idx = 1; _idx < 9; _idx++ )\
83 {\
84 interVAL >>= 1;\
85 if( !interVAL )\
86 break;\
87 }\
88 _idx --;\
89 }
90
91 #define uhci_insert_urb_to_schedule( uHCI, pURB, rET ) \
92 {\
93 SYNC_PARAM sync_param;\
94 sync_param.uhci = uHCI;\
95 sync_param.context = pURB;\
96 \
97 rET = KeSynchronizeExecution( uHCI->pdev_ext->uhci_int, uhci_sync_insert_urb_schedule, &sync_param );\
98 }
99
100 //declarations
101 typedef struct
102 {
103 PUHCI_DEV uhci;
104 PVOID context;
105 ULONG ret;
106 } SYNC_PARAM, *PSYNC_PARAM;
107
108 PDEVICE_OBJECT
109 uhci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr);
110
111 BOOLEAN uhci_init_schedule(PUHCI_DEV uhci, PADAPTER_OBJECT padapter);
112
113 BOOLEAN uhci_release(PDEVICE_OBJECT pdev);
114
115 static VOID uhci_stop(PUHCI_DEV uhci);
116
117 BOOLEAN uhci_destroy_schedule(PUHCI_DEV uhci);
118
119 BOOLEAN NTAPI uhci_sync_insert_urb_schedule(PVOID context);
120
121 VOID uhci_init_hcd_interface(PUHCI_DEV uhci);
122
123 NTSTATUS uhci_rh_submit_urb(PUSB_DEV rh, PURB purb);
124
125 NTSTATUS uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
126
127 extern VOID rh_timer_svc_reset_port_completion(PUSB_DEV dev, PVOID context);
128
129 extern VOID rh_timer_svc_int_completion(PUSB_DEV dev, PVOID context);
130
131 ULONG debug_level = DBGLVL_MINIMUM;//DBGLVL_MAXIMUM;
132 PDRIVER_OBJECT usb_driver_obj = NULL;
133 extern USB_DEV_MANAGER g_dev_mgr;
134
135 //pending endpoint pool funcs
136 VOID
137 uhci_wait_ms(PUHCI_DEV uhci, LONG ms)
138 {
139 LARGE_INTEGER lms;
140 if (ms <= 0)
141 return;
142
143 lms.QuadPart = -10 * ms;
144 KeSetTimer(&uhci->reset_timer, lms, NULL);
145
146 KeWaitForSingleObject(&uhci->reset_timer, Executive, KernelMode, FALSE, NULL);
147
148 return;
149 }
150
151 BOOLEAN
152 init_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
153 {
154 int i;
155 if (pool == NULL)
156 return FALSE;
157
158 pool->pending_endp_array =
159 usb_alloc_mem(NonPagedPool, sizeof(UHCI_PENDING_ENDP) * UHCI_MAX_PENDING_ENDPS);
160 InitializeListHead(&pool->free_que);
161 pool->free_count = 0;
162 pool->total_count = UHCI_MAX_PENDING_ENDPS;
163 KeInitializeSpinLock(&pool->pool_lock);
164
165 for(i = 0; i < MAX_TIMER_SVCS; i++)
166 {
167 free_pending_endp(pool, &pool->pending_endp_array[i]);
168 }
169
170 return TRUE;
171
172 }
173
174 BOOLEAN
175 free_pending_endp(PUHCI_PENDING_ENDP_POOL pool, PUHCI_PENDING_ENDP pending_endp)
176 {
177 if (pool == NULL || pending_endp == NULL)
178 {
179 return FALSE;
180 }
181
182 RtlZeroMemory(pending_endp, sizeof(UHCI_PENDING_ENDP));
183 InsertTailList(&pool->free_que, &pending_endp->endp_link);
184 pool->free_count++;
185
186 return TRUE;
187 }
188
189 PUHCI_PENDING_ENDP
190 alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool, LONG count)
191 {
192 PUHCI_PENDING_ENDP new_endp;
193 if (pool == NULL || count != 1)
194 return NULL;
195
196 if (pool->free_count <= 0)
197 return NULL;
198
199 new_endp = (PUHCI_PENDING_ENDP) RemoveHeadList(&pool->free_que);
200 pool->free_count--;
201 return new_endp;
202 }
203
204 BOOLEAN
205 destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
206 {
207 if (pool == NULL)
208 return FALSE;
209
210 InitializeListHead(&pool->free_que);
211 pool->free_count = pool->total_count = 0;
212 usb_free_mem(pool->pending_endp_array);
213 pool->pending_endp_array = NULL;
214
215 return TRUE;
216
217 }
218
219
220 //end of pending endpoint pool funcs
221
222 static void
223 uhci_fill_td(PUHCI_TD td, ULONG status, ULONG info, ULONG buffer)
224 {
225 td->status = status;
226 td->info = info;
227 td->buffer = buffer;
228 }
229
230 BOOLEAN
231 uhci_insert_td_fl(PUHCI_TD prev_td, PUHCI_TD ptd)
232 {
233 PLIST_ENTRY temp_entry;
234
235 if (prev_td == NULL || ptd == NULL)
236 return FALSE;
237
238 temp_entry = &prev_td->ptde->hori_link;
239
240 ptd->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
241 prev_td->link = ptd->phy_addr;
242
243 InsertHeadList(&prev_td->ptde->hori_link, &ptd->ptde->hori_link);
244 return TRUE;
245 }
246
247 BOOLEAN
248 uhci_remove_td_fl(PUHCI_TD ptd)
249 {
250 PUHCI_TD prev_td;
251
252 if (ptd == NULL)
253 return FALSE;
254
255 prev_td = (struct_ptr(ptd->ptde->hori_link.Blink, TD_EXTENSION, hori_link))->ptd;
256 prev_td->link = ptd->link;
257 ptd->link = UHCI_PTR_TERM;
258
259 RemoveEntryList(&ptd->ptde->hori_link);
260
261 return FALSE;
262 }
263
264 BOOLEAN
265 uhci_insert_qh_fl(PVOID prev_item, PUHCI_QH pqh)
266 {
267 //only horizontal link allowed
268 PUHCI_QH pprev_qh;
269 PUHCI_TD pprev_td;
270 PLIST_ENTRY temp_entry;
271
272 if (prev_item == NULL || pqh == NULL)
273 return FALSE;
274
275 if ((((PUHCI_TD) prev_item)->ptde->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
276 {
277 pprev_qh = (PUHCI_QH) prev_item;
278 temp_entry = pprev_qh->pqhe->hori_link.Flink;
279 pqh->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
280 pprev_qh->link = pqh->phy_addr;
281
282 InsertHeadList(&pprev_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
283 }
284 else
285 {
286 pprev_td = ((PUHCI_TD) prev_item);
287
288 temp_entry = pprev_td->ptde->hori_link.Flink;
289 pprev_td->link = pqh->phy_addr;
290 pqh->link = (struct_ptr(temp_entry, TD_EXTENSION, hori_link))->ptd->phy_addr;
291
292 InsertHeadList(&pprev_td->ptde->hori_link, &pqh->pqhe->hori_link);
293 }
294
295 return FALSE;
296 }
297
298 BOOLEAN
299 uhci_remove_qh_fl(PUHCI_QH pqh)
300 {
301 PVOID prev_item;
302 PUHCI_QH pprevqh;
303 PUHCI_TD pprevtd;
304
305 if (pqh == NULL)
306 return FALSE;
307
308 prev_item = (struct_ptr(pqh->pqhe->hori_link.Blink, TD_EXTENSION, hori_link))->ptd;
309
310 if ((((PUHCI_TD) prev_item)->ptde->flags & UHCI_ITEM_FLAG_TYPE) == UHCI_ITEM_FLAG_QH)
311 {
312 pprevqh = (PUHCI_QH) prev_item;
313 pprevqh->link = pqh->link;
314 }
315 else
316 {
317 pprevtd = ((PUHCI_TD) prev_item);
318 pprevtd->link = pqh->link;
319 }
320
321 RemoveEntryList(&pqh->pqhe->hori_link);
322
323 pqh->link = UHCI_PTR_TERM;
324 pqh->pqhe->hori_link.Flink = pqh->pqhe->hori_link.Blink = NULL;
325
326 return TRUE;
327 }
328
329 BOOLEAN
330 uhci_init_frame_list(PUHCI_DEV uhci, PADAPTER_OBJECT padapter)
331 {
332 int i;
333 if (uhci == NULL || padapter == NULL)
334 return FALSE;
335
336 //note: frame_list_lock will be connected to interrupt
337 KeInitializeSpinLock(&uhci->frame_list_lock);
338
339 uhci->io_buf = HalAllocateCommonBuffer(padapter, 4096, &uhci->io_buf_logic_addr, FALSE);
340
341 if (uhci->io_buf == NULL)
342 return FALSE;
343
344 uhci->frame_list =
345 HalAllocateCommonBuffer(padapter,
346 sizeof(ULONG) * UHCI_MAX_FRAMES, &uhci->frame_list_logic_addr, FALSE);
347
348 if (uhci->frame_list == NULL)
349 return FALSE;
350
351 RtlZeroMemory(uhci->frame_list, sizeof(ULONG) * UHCI_MAX_FRAMES);
352
353 uhci->frame_list_cpu = usb_alloc_mem(NonPagedPool, sizeof(FRAME_LIST_CPU_ENTRY) * UHCI_MAX_FRAMES);
354
355 if (uhci->frame_list_cpu == NULL)
356 return FALSE;
357
358 for(i = 0; i < UHCI_MAX_FRAMES; i++)
359 InitializeListHead(&uhci->frame_list_cpu[i].td_link);
360
361 uhci->frame_bw = usb_alloc_mem(NonPagedPool, sizeof(LONG) * UHCI_MAX_FRAMES);
362
363 if (uhci->frame_bw == NULL)
364 return FALSE;
365
366 for(i = 0; i < UHCI_MAX_FRAMES; i++)
367 {
368 uhci->frame_bw[i] = FRAME_TIME_MAX_USECS_ALLOC;
369 }
370 uhci->fsbr_cnt = 0;
371
372 return TRUE;
373
374 }
375
376 BOOLEAN
377 uhci_destroy_frame_list(PUHCI_DEV uhci)
378 {
379 if (uhci == NULL)
380 return FALSE;
381
382 if (uhci->frame_list)
383 HalFreeCommonBuffer(uhci->pdev_ext->padapter,
384 sizeof(ULONG) * UHCI_MAX_FRAMES,
385 uhci->frame_list_logic_addr, uhci->frame_list, FALSE);
386
387 uhci->frame_list = NULL;
388 uhci->frame_list_logic_addr.LowPart = 0;
389 uhci->frame_list_logic_addr.HighPart = 0;
390
391 if (uhci->frame_list_cpu)
392 usb_free_mem(uhci->frame_list_cpu);
393
394 uhci->frame_list_cpu = NULL;
395
396 if (uhci->frame_bw)
397 usb_free_mem(uhci->frame_bw);
398
399 uhci->frame_bw = NULL;
400
401 return TRUE;
402 }
403
404 PDEVICE_OBJECT
405 uhci_create_device(PDRIVER_OBJECT drvr_obj, PUSB_DEV_MANAGER dev_mgr)
406 {
407 NTSTATUS status;
408 PDEVICE_OBJECT pdev;
409 PDEVICE_EXTENSION pdev_ext;
410
411 UNICODE_STRING dev_name;
412 UNICODE_STRING symb_name;
413
414 STRING string, another_string;
415 CHAR str_dev_name[64], str_symb_name[64];
416 UCHAR hcd_id;
417
418 if (drvr_obj == NULL)
419 return NULL;
420
421 ASSERT(dev_mgr != NULL);
422
423 //note: hcd count wont increment till the hcd is registered in dev_mgr
424 sprintf(str_dev_name, "%s%d", UHCI_DEVICE_NAME, dev_mgr->hcd_count);
425 sprintf(str_symb_name, "%s%d", DOS_DEVICE_NAME, dev_mgr->hcd_count);
426
427 RtlInitString(&string, str_dev_name);
428 RtlAnsiStringToUnicodeString(&dev_name, &string, TRUE);
429
430 pdev = NULL;
431 status = IoCreateDevice(drvr_obj,
432 sizeof(DEVICE_EXTENSION) + sizeof(UHCI_DEV),
433 &dev_name, FILE_UHCI_DEV_TYPE, 0, FALSE, &pdev);
434
435 if (status != STATUS_SUCCESS || pdev == NULL)
436 {
437 RtlFreeUnicodeString(&dev_name);
438 return NULL;
439 }
440
441 pdev_ext = pdev->DeviceExtension;
442 RtlZeroMemory(pdev_ext, sizeof(DEVICE_EXTENSION) + sizeof(UHCI_DEV));
443
444 pdev_ext->dev_ext_hdr.type = NTDEV_TYPE_HCD;
445 pdev_ext->dev_ext_hdr.dispatch = uhci_dispatch_irp;
446 pdev_ext->dev_ext_hdr.start_io = NULL; //we do not support startio
447 pdev_ext->dev_ext_hdr.dev_mgr = dev_mgr;
448
449 pdev_ext->pdev_obj = pdev;
450 pdev_ext->pdrvr_obj = drvr_obj;
451
452 pdev_ext->uhci = (PUHCI_DEV) & (pdev_ext[1]);
453
454 RtlInitString(&another_string, str_symb_name);
455 RtlAnsiStringToUnicodeString(&symb_name, &another_string, TRUE);
456
457 IoCreateSymbolicLink(&symb_name, &dev_name);
458
459 uhci_dbg_print(DBGLVL_MAXIMUM,
460 ("uhci_create_device(): dev=0x%x\n, pdev_ext= 0x%x, uhci=0x%x, dev_mgr=0x%x\n", pdev,
461 pdev_ext, pdev_ext->uhci, dev_mgr));
462
463 RtlFreeUnicodeString(&dev_name);
464 RtlFreeUnicodeString(&symb_name);
465
466 //register with dev_mgr though it is not initilized
467 uhci_init_hcd_interface(pdev_ext->uhci);
468 hcd_id = dev_mgr_register_hcd(dev_mgr, &pdev_ext->uhci->hcd_interf);
469
470 pdev_ext->uhci->hcd_interf.hcd_set_id(&pdev_ext->uhci->hcd_interf, hcd_id);
471 pdev_ext->uhci->hcd_interf.hcd_set_dev_mgr(&pdev_ext->uhci->hcd_interf, dev_mgr);
472 return pdev;
473 }
474
475 BOOLEAN
476 uhci_delete_device(PDEVICE_OBJECT pdev)
477 {
478 STRING string;
479 UNICODE_STRING symb_name;
480 PDEVICE_EXTENSION pdev_ext;
481 CHAR str_symb_name[64];
482
483
484 if (pdev == NULL)
485 return FALSE;
486
487 pdev_ext = pdev->DeviceExtension;
488
489 sprintf(str_symb_name,
490 "%s%d", DOS_DEVICE_NAME, pdev_ext->uhci->hcd_interf.hcd_get_id(&pdev_ext->uhci->hcd_interf));
491 RtlInitString(&string, str_symb_name);
492 RtlAnsiStringToUnicodeString(&symb_name, &string, TRUE);
493 IoDeleteSymbolicLink(&symb_name);
494 RtlFreeUnicodeString(&symb_name);
495
496 if (pdev_ext->res_list)
497 ExFreePool(pdev_ext->res_list); // not allocated by usb_alloc_mem
498
499 IoDeleteDevice(pdev);
500 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_delete_device(): device deleted\n"));
501 return TRUE;
502 }
503
504 // we can not use endp here for it is within the dev scope, and
505 // we can not acquire the dev-lock, fortunately we saved some
506 // info in urb->pipe in uhci_internal_submit_XXX.
507 BOOLEAN NTAPI
508 uhci_isr(PKINTERRUPT interrupt, PVOID context)
509 {
510 PUHCI_DEV uhci;
511 USHORT status;
512 PLIST_ENTRY pthis, pnext;
513 PURB purb;
514
515 UNREFERENCED_PARAMETER(interrupt);
516 UNREFERENCED_PARAMETER(context);
517
518 uhci_dbg_print(DBGLVL_ULTRA, ("uhci_isr(): context=0x%x\n", context));
519
520 /*
521 * Read the interrupt status, and write it back to clear the
522 * interrupt cause
523 */
524 uhci = (PUHCI_DEV) context;
525 if (uhci == NULL)
526 return FALSE;
527
528 status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS));
529 if (!status) /* shared interrupt, not mine */
530 return FALSE;
531
532 if (status != 1)
533 {
534 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr(): current uhci status=0x%x\n", status));
535 }
536 else
537 {
538 uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr(): congratulations, no error occurs\n"));
539 }
540
541 /* clear it */
542 WRITE_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS), status);
543
544 if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD))
545 {
546 if (status & USBSTS_HSE)
547 {
548 DbgPrint("uhci_isr(): host system error, PCI problems?\n");
549 //for( ; ; );
550 }
551 if (status & USBSTS_HCPE)
552 {
553 DbgPrint("uhci_isr(): host controller process error. something bad happened\n");
554 //for( ; ; );
555 //for( ; ; );
556 }
557 if ((status & USBSTS_HCH)) //&& !uhci->is_suspended
558 {
559 DbgPrint("uhci_isr(): host controller halted. very bad\n");
560 /* FIXME: Reset the controller, fix the offending TD */
561 }
562 }
563
564 // don't no how to handle it yet
565 //if (status & USBSTS_RD)
566 //{
567 //uhci_wakeup(uhci);
568 //}*/
569
570 //let's remove those force-cancel urbs from the schedule first
571 ListFirst(&uhci->urb_list, pthis);
572 while (pthis)
573 {
574 purb = (PURB) pthis;
575 if (purb->flags & URB_FLAG_FORCE_CANCEL)
576 {
577 uhci_remove_urb_from_schedule(uhci, purb);
578 }
579 ListNext(&uhci->urb_list, pthis, pnext);
580 pthis = pnext;
581 }
582
583 //clear the interrupt if the urb is force canceled
584 uhci->skel_term_td->status &= ~TD_CTRL_IOC;
585
586 //next we need to find if anything fininshed
587 ListFirst(&uhci->urb_list, pthis);
588 while (pthis)
589 {
590 purb = (PURB) pthis;
591 if (purb->flags & URB_FLAG_IN_SCHEDULE)
592 {
593 if (uhci_is_xfer_finished(purb))
594 uhci_remove_urb_from_schedule(uhci, purb);
595 }
596 ListNext(&uhci->urb_list, pthis, pnext);
597 pthis = pnext;
598 }
599
600 KeInsertQueueDpc(&uhci->pdev_ext->uhci_dpc, uhci, 0);
601 return TRUE;
602 }
603
604 BOOLEAN NTAPI
605 uhci_cal_cpu_freq(PVOID context)
606 {
607 UNREFERENCED_PARAMETER(context);
608
609 usb_cal_cpu_freq();
610 return TRUE;
611 }
612
613 PDEVICE_OBJECT
614 uhci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr)
615 {
616 LONG bus, i, j, ret = 0;
617 PCI_SLOT_NUMBER slot_num;
618 PPCI_COMMON_CONFIG pci_config;
619 PDEVICE_OBJECT pdev;
620 BYTE buffer[sizeof(PCI_COMMON_CONFIG)];
621 LONG count;
622 PDEVICE_EXTENSION pdev_ext;
623
624 slot_num.u.AsULONG = 0;
625 pci_config = (PPCI_COMMON_CONFIG) buffer;
626 count = 0;
627 pdev = NULL;
628
629 //scan the bus to find uhci controller
630 for(bus = 0; bus < 3; bus++) /* enum bus0-bus2 */
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 if (pdev)
655 count++;
656 }
657 #else
658 pdev = uhci_alloc(drvr_obj, reg_path, ((bus << 8) | (i << 3) | j), dev_mgr);
659 if (pdev)
660 goto LBL_LOOPOUT;
661 #endif
662 }
663 }
664 if (ret == 0)
665 break;
666 }
667 }
668
669 #ifndef _MULTI_UHCI
670 LBL_LOOPOUT:
671 #endif
672 if (pdev)
673 {
674 pdev_ext = pdev->DeviceExtension;
675 if (pdev_ext)
676 {
677 // acquire higher irql to eliminate pre-empty
678 KeSynchronizeExecution(pdev_ext->uhci_int, uhci_cal_cpu_freq, NULL);
679 }
680 }
681 return pdev;
682 }
683
684 PDEVICE_OBJECT
685 uhci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr)
686 {
687 LONG frd_num, prd_num;
688 PDEVICE_OBJECT pdev;
689 PDEVICE_EXTENSION pdev_ext;
690 ULONG vector, addr_space;
691 LONG bus;
692 KIRQL irql;
693 KAFFINITY affinity;
694
695 DEVICE_DESCRIPTION dev_desc;
696 CM_PARTIAL_RESOURCE_DESCRIPTOR *pprd;
697 PCI_SLOT_NUMBER slot_num;
698 NTSTATUS status;
699
700
701 pdev = uhci_create_device(drvr_obj, dev_mgr);
702 if (pdev == NULL)
703 return pdev;
704 pdev_ext = pdev->DeviceExtension;
705
706 pdev_ext->pci_addr = bus_addr;
707 bus = (bus_addr >> 8);
708
709 slot_num.u.AsULONG = 0;
710 slot_num.u.bits.DeviceNumber = ((bus_addr & 0xff) >> 3);
711 slot_num.u.bits.FunctionNumber = (bus_addr & 0x07);
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 KeInitializeDpc(&pdev_ext->uhci_dpc, uhci_dpc_callback, (PVOID) pdev_ext->uhci);
844
845 //connect the interrupt
846 DbgPrint("uhci_alloc(): the int=0x%x\n", vector);
847 if (IoConnectInterrupt(&pdev_ext->uhci_int,
848 uhci_isr,
849 pdev_ext->uhci,
850 NULL, //&pdev_ext->uhci->frame_list_lock,
851 vector,
852 irql,
853 irql,
854 LevelSensitive,
855 TRUE, //share the vector
856 affinity,
857 FALSE) //No float save
858 != STATUS_SUCCESS)
859 {
860 uhci_release(pdev);
861 return NULL;
862 }
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, &purb->urb_link);
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, &pending_endp->endp_link );
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(&purb->urb_link);
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, &purb->urb_link);
1747 }
1748
1749 pending_endp = alloc_pending_endp(&uhci->pending_endp_pool, 1);
1750 if (!pending_endp)
1751 {
1752 unlock_dev(pdev, TRUE);
1753 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1754 return;
1755 }
1756
1757 pending_endp->pendp = pendp;
1758 InsertTailList(&uhci->pending_endp_list, &pending_endp->endp_link);
1759
1760 unlock_dev(pdev, TRUE);
1761 KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
1762 }
1763
1764 //ah...exhausted, let's find some in the pending_endp_list to rock
1765 uhci_process_pending_endp(uhci);
1766 return;
1767 }
1768
1769 BOOLEAN
1770 uhci_add_device(PUHCI_DEV uhci, PUSB_DEV dev)
1771 {
1772 if (dev == NULL || uhci == NULL)
1773 return FALSE;
1774
1775 return TRUE;
1776 }
1777
1778 BOOLEAN NTAPI
1779 uhci_sync_cancel_urbs_dev(PVOID context)
1780 {
1781 //cancel all the urbs on one dev
1782 PUHCI_DEV uhci;
1783 PUSB_DEV pdev, dest_dev;
1784 PSYNC_PARAM sync_param;
1785 PLIST_ENTRY pthis, pnext;
1786 LONG count;
1787
1788 sync_param = (PSYNC_PARAM) context;
1789 dest_dev = (PUSB_DEV) sync_param->context;
1790 uhci = sync_param->uhci;
1791
1792 if (uhci == NULL || dest_dev == NULL)
1793 {
1794 return (UCHAR) (sync_param->ret = FALSE);
1795 }
1796 count = 0;
1797 ListFirst(&uhci->urb_list, pthis);
1798 while (pthis)
1799 {
1800 pdev = dev_from_endp(((PURB) pthis)->pendp);
1801 if (pdev == dest_dev)
1802 {
1803 ((PURB) pthis)->flags |= URB_FLAG_FORCE_CANCEL;
1804 }
1805 ListNext(&uhci->urb_list, pthis, pnext);
1806 pthis = pnext;
1807 count++;
1808 }
1809 if (count)
1810 uhci->skel_term_td->status |= TD_CTRL_IOC;
1811
1812 return (UCHAR) (sync_param->ret = TRUE);
1813 }
1814
1815 BOOLEAN
1816 uhci_remove_device(PUHCI_DEV uhci, PUSB_DEV dev)
1817 {
1818 PUHCI_PENDING_ENDP ppending_endp;
1819 PLIST_ENTRY pthis, pnext;
1820 PURB purb;
1821 LIST_HEAD temp_list;
1822 int i, j, k;
1823 SYNC_PARAM sync_param;
1824
1825 USE_BASIC_IRQL;
1826
1827 if (uhci == NULL || dev == NULL)
1828 return FALSE;
1829
1830 InitializeListHead(&temp_list);
1831
1832 //free pending endp that has urb queued from pending endp list
1833 lock_pending_endp_list(&uhci->pending_endp_list_lock);
1834
1835 ListFirst(&uhci->pending_endp_list, pthis);
1836
1837 while (pthis)
1838 {
1839 ppending_endp = (PUHCI_PENDING_ENDP) pthis;
1840 ListNext(&uhci->pending_endp_list, pthis, pnext);
1841 if (dev_from_endp(ppending_endp->pendp) == dev)
1842 {
1843 RemoveEntryList(pthis);
1844 free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1845 }
1846 pthis = pnext;
1847 }
1848 unlock_pending_endp_list(&uhci->pending_endp_list_lock);
1849
1850 //cancel all the urbs in the urb-list
1851 sync_param.uhci = uhci;
1852 sync_param.context = (PVOID) dev;
1853
1854 KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_cancel_urbs_dev, &sync_param);
1855
1856 //cancel all the urb in the endp's urb-list
1857 k = 0;
1858 lock_dev(dev, FALSE);
1859 if (dev->usb_config)
1860 {
1861 //only for configed dev
1862 for(i = 0; i < dev->usb_config->if_count; i++)
1863 {
1864 for(j = 0; j < dev->usb_config->interf[i].endp_count; j++)
1865 {
1866 ListFirst(&dev->usb_config->interf[i].endp[j].urb_list, pthis);
1867 while (pthis)
1868 {
1869 ListNext(&dev->usb_config->interf[i].endp[j].urb_list, pthis, pnext);
1870
1871 RemoveEntryList(pthis);
1872 InsertHeadList(&temp_list, pthis);
1873 pthis = pnext;
1874 k++;
1875 }
1876
1877 }
1878 }
1879 }
1880 ListFirst(&dev->default_endp.urb_list, pthis);
1881
1882 while (pthis)
1883 {
1884 ListNext(&dev->default_endp.urb_list, pthis, pnext);
1885
1886 RemoveEntryList(pthis);
1887 InsertHeadList(&temp_list, pthis);
1888 pthis = pnext;
1889 k++;
1890 }
1891 unlock_dev(dev, FALSE);
1892
1893 if (IsListEmpty(&temp_list) == FALSE)
1894 {
1895 for(i = 0; i < k; i++)
1896 {
1897 //complete those urbs with error
1898 pthis = RemoveHeadList(&temp_list);
1899 purb = (PURB) pthis;
1900 purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1901 {
1902 uhci_generic_urb_completion(purb, purb->context);
1903 }
1904 }
1905 }
1906
1907 lock_dev(dev, FALSE) dev->ref_count -= k;
1908 unlock_dev(dev, FALSE);
1909
1910 return TRUE;
1911 }
1912
1913
1914 //
1915 // assume that the urb has its rest_bytes and bytes_to_transfer set
1916 // and bytes_transfered is zeroed.
1917 // dev_lock must be acquired outside
1918 // urb comes from dev's endpoint urb-list. it is already removed from
1919 // the endpoint urb-list.
1920 //
1921 NTSTATUS
1922 uhci_internal_submit_bulk(PUHCI_DEV uhci, PURB urb)
1923 {
1924
1925 LONG max_packet_size, td_count, offset, bytes_to_transfer, data_load;
1926 PBYTE start_addr;
1927 PUHCI_TD ptd;
1928 PUHCI_QH pqh;
1929 LIST_ENTRY td_list, *pthis, *pnext;
1930 BOOLEAN old_toggle, toggle, ret;
1931 UCHAR pid;
1932
1933 if (uhci == NULL || urb == NULL)
1934 return STATUS_INVALID_PARAMETER;
1935
1936 max_packet_size = endp_max_packet_size(urb->pendp);
1937 if (urb->bytes_to_transfer == 0)
1938 {
1939 return STATUS_INVALID_PARAMETER;
1940 }
1941
1942 td_count = (urb->bytes_to_transfer + max_packet_size - 1) / max_packet_size;
1943
1944 lock_td_pool(&uhci->td_pool, TRUE);
1945 if (can_transfer(&uhci->td_pool, td_count) == FALSE)
1946 {
1947 unlock_td_pool(&uhci->td_pool, TRUE);
1948 return STATUS_NO_MORE_ENTRIES;
1949 }
1950
1951 ptd = alloc_tds(&uhci->td_pool, td_count);
1952 unlock_td_pool(&uhci->td_pool, TRUE);
1953
1954 if (ptd == NULL)
1955 {
1956 return STATUS_UNSUCCESSFUL;
1957 }
1958
1959 InitializeListHead(&td_list);
1960 InsertTailList(&ptd->ptde->vert_link, &td_list);
1961
1962 ListFirst(&td_list, pthis);
1963 ListNext(&td_list, pthis, pnext);
1964
1965 start_addr = &urb->data_buffer[urb->data_length - urb->rest_bytes];
1966 offset = 0;
1967
1968 old_toggle = toggle = urb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE ? TRUE : FALSE;
1969 bytes_to_transfer = urb->bytes_to_transfer;
1970
1971 urb->pipe = ((max_packet_size - 1) << 21)
1972 | ((ULONG) endp_num(urb->pendp) << 15)
1973 | (dev_from_endp(urb->pendp)->dev_addr << 8)
1974 | ((ULONG) endp_dir(urb->pendp)) | USB_ENDPOINT_XFER_BULK;
1975
1976 pid = (((ULONG) urb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT);
1977 while (pthis)
1978 {
1979 ptd = ((PTD_EXTENSION) pthis)->ptd;
1980
1981 data_load = max_packet_size < bytes_to_transfer ? max_packet_size : bytes_to_transfer;
1982 ptd->purb = urb;
1983 uhci_fill_td(ptd,
1984 (3 << TD_CTRL_C_ERR_SHIFT)
1985 | (TD_CTRL_ACTIVE),
1986 ((data_load - 1) << 21)
1987 | (toggle << 19)
1988 | ((ULONG) endp_num(urb->pendp) << 15)
1989 | (dev_from_endp(urb->pendp)->dev_addr << 8)
1990 | pid, MmGetPhysicalAddress(start_addr + offset).LowPart);
1991
1992 bytes_to_transfer -= data_load;
1993 offset += data_load;
1994
1995 if (pnext)
1996 {
1997 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
1998 }
1999 else
2000 {
2001 //Last one, enable ioc and short packet detect if necessary
2002 ptd->link = UHCI_PTR_TERM;
2003 ptd->status |= TD_CTRL_IOC;
2004 if (bytes_to_transfer < max_packet_size && (pid == USB_PID_IN))
2005 {
2006 //ptd->status |= TD_CTRL_SPD;
2007 }
2008 }
2009
2010 pthis = pnext;
2011 toggle ^= 1;
2012 if (pthis)
2013 ListNext(&td_list, pthis, pnext);
2014
2015 }
2016
2017 ListFirst(&td_list, pthis);
2018 RemoveEntryList(&td_list);
2019
2020 lock_qh_pool(&uhci->qh_pool, TRUE);
2021 pqh = alloc_qh(&uhci->qh_pool);
2022 unlock_qh_pool(&uhci->qh_pool, TRUE);
2023
2024 if (pqh == NULL)
2025 {
2026 lock_td_pool(&uhci->td_pool, TRUE);
2027
2028 if (pthis)
2029 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2030
2031 unlock_td_pool(&uhci->td_pool, TRUE);
2032 return STATUS_NO_MORE_ENTRIES;
2033
2034 }
2035
2036 urb->td_count = td_count;
2037
2038 uhci_insert_tds_qh(pqh, ((PTD_EXTENSION) pthis)->ptd);
2039 uhci_insert_qh_urb(urb, pqh);
2040 urb->pendp->flags =
2041 (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
2042 usb_endp_busy_count_inc(urb->pendp);
2043 uhci_insert_urb_to_schedule(uhci, urb, ret);
2044
2045 if (ret == FALSE)
2046 {
2047 // undo all we have done
2048 RemoveEntryList(&pqh->pqhe->vert_link); //remove qh from td_chain
2049 RemoveEntryList(&urb->trasac_list);
2050
2051 lock_td_pool(&uhci->td_pool, TRUE);
2052 if (pthis)
2053 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2054 unlock_td_pool(&uhci->td_pool, TRUE);
2055
2056 lock_qh_pool(&uhci->qh_pool, TRUE);
2057 if (pqh)
2058 free_qh(&uhci->qh_pool, pqh);
2059 unlock_qh_pool(&uhci->qh_pool, TRUE);
2060
2061 InitializeListHead(&urb->trasac_list);
2062 usb_endp_busy_count_dec(urb->pendp);
2063 urb->pendp->flags =
2064 (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (old_toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
2065 return STATUS_UNSUCCESSFUL;
2066 }
2067 return STATUS_SUCCESS;
2068 }
2069
2070 NTSTATUS
2071 uhci_internal_submit_ctrl(PUHCI_DEV uhci, PURB urb)
2072 {
2073 LIST_ENTRY td_list, *pthis, *pnext;
2074 LONG i, td_count;
2075 LONG toggle;
2076 LONG max_packet_size, bytes_to_transfer, bytes_rest, start_idx;
2077 PUHCI_TD ptd;
2078 PUHCI_QH pqh;
2079 ULONG dev_addr;
2080 PUSB_DEV pdev;
2081 BOOLEAN ret;
2082
2083 if (uhci == NULL || urb == NULL)
2084 return STATUS_INVALID_PARAMETER;
2085
2086 toggle = 0;
2087 bytes_rest = urb->rest_bytes;
2088 bytes_to_transfer = urb->bytes_to_transfer;
2089 max_packet_size = endp_max_packet_size(urb->pendp);
2090 start_idx = urb->data_length - urb->rest_bytes;
2091 td_count = 2 + (urb->bytes_to_transfer + max_packet_size - 1) / max_packet_size;
2092
2093 lock_td_pool(&uhci->td_pool, TRUE);
2094
2095 if (can_transfer(&uhci->td_pool, td_count) == FALSE)
2096 {
2097 unlock_td_pool(&uhci->td_pool, TRUE);
2098 return STATUS_NO_MORE_ENTRIES;
2099 }
2100
2101 ptd = alloc_tds(&uhci->td_pool, td_count);
2102 unlock_td_pool(&uhci->td_pool, TRUE);
2103
2104 if (ptd == NULL)
2105 {
2106 return STATUS_UNSUCCESSFUL;
2107 }
2108
2109 InsertTailList(&ptd->ptde->vert_link, &td_list);
2110
2111 ListFirst(&td_list, pthis);
2112 ListNext(&td_list, pthis, pnext);
2113
2114 ptd = ((PTD_EXTENSION) pthis)->ptd;
2115
2116 pdev = dev_from_endp(urb->pendp);
2117 dev_addr = pdev->dev_addr;
2118
2119 if (dev_state(pdev) <= USB_DEV_STATE_RESET)
2120 dev_addr = 0;
2121
2122 usb_dbg_print(DBGLVL_MAXIMUM, ("uhci_internal_submit_ctrl(): dev_addr =0x%x\n", dev_addr));
2123
2124 RtlCopyMemory(uhci->io_buf, urb->setup_packet, 8);
2125
2126 if ((urb->setup_packet[0] & USB_DIR_IN) == 0) //out
2127 RtlCopyMemory(&uhci->io_buf[8], urb->data_buffer, bytes_to_transfer);
2128 else
2129 RtlZeroMemory(&uhci->io_buf[8], bytes_to_transfer);
2130
2131 uhci_fill_td(ptd,
2132 (3 << TD_CTRL_C_ERR_SHIFT) | (TD_CTRL_ACTIVE),
2133 (7 << 21) | (((ULONG) endp_num(urb->pendp)) << 15) | (dev_addr << 8) | (USB_PID_SETUP),
2134 //uhci->io_buf_logic_addr.LowPart);
2135 MmGetPhysicalAddress(urb->setup_packet).LowPart);
2136
2137 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
2138 pthis = pnext;
2139 ListNext(&td_list, pthis, pnext);
2140
2141 urb->pipe = ((max_packet_size - 1) << 21)
2142 | ((ULONG) endp_num(urb->pendp) << 15)
2143 | (dev_addr << 8) | (pdev->flags & USB_DEV_FLAG_LOW_SPEED) | USB_ENDPOINT_XFER_CONTROL;
2144
2145 for(i = 0, toggle = 1; ((i < td_count - 2) && pthis); i++, toggle ^= 1)
2146 {
2147 //construct tds for DATA packets of data stage.
2148 ptd = ((PTD_EXTENSION) pthis)->ptd;
2149 uhci_fill_td(ptd,
2150 (3 << TD_CTRL_C_ERR_SHIFT)
2151 | (TD_CTRL_ACTIVE),
2152 ((bytes_to_transfer >
2153 max_packet_size ? max_packet_size - 1 : bytes_to_transfer -
2154 1) << 21) | (toggle << 19) | (((ULONG) endp_num(urb->
2155 pendp)) << 15) | (dev_addr << 8) |
2156 ((urb->setup_packet[0] & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT),
2157 //uhci->io_buf_logic_addr.LowPart + 8 + i * max_packet_size );
2158 MmGetPhysicalAddress(&urb->data_buffer[start_idx + i * max_packet_size]).LowPart);
2159
2160 if (pnext)
2161 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
2162
2163 if (i < td_count - 3)
2164 {
2165 bytes_to_transfer -= max_packet_size;
2166 }
2167 else
2168 {
2169 if (bytes_to_transfer > 0)
2170 {
2171 if (bytes_to_transfer < max_packet_size && (urb->setup_packet[0] & USB_DIR_IN))
2172 ptd->status |= TD_CTRL_SPD;
2173 }
2174 }
2175 pthis = pnext;
2176
2177 if (pthis)
2178 ListNext(&td_list, pthis, pnext);
2179 }
2180
2181 if (pnext)
2182 ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
2183
2184 ListFirstPrev(&td_list, pthis);
2185 ptd = ((PTD_EXTENSION) pthis)->ptd;
2186
2187 //the last is an IN transaction
2188 uhci_fill_td(ptd,
2189 (3 << TD_CTRL_C_ERR_SHIFT)
2190 | (TD_CTRL_ACTIVE | TD_CTRL_IOC),
2191 (UHCI_NULL_DATA_SIZE << 21)
2192 | (1 << 19)
2193 | (((ULONG) endp_num(urb->pendp)) << 15)
2194 | (dev_addr << 8)
2195 | ((td_count > 2)
2196 ? ((urb->setup_packet[0] & USB_DIR_IN) ? USB_PID_OUT : USB_PID_IN) : USB_PID_IN), 0);
2197
2198 ptd->link = UHCI_PTR_TERM;
2199
2200 ListFirst(&td_list, pthis);
2201 RemoveEntryList(&td_list);
2202
2203 lock_qh_pool(&uhci->qh_pool, TRUE);
2204 pqh = alloc_qh(&uhci->qh_pool);
2205 unlock_qh_pool(&uhci->qh_pool, TRUE);
2206
2207 if (pqh == NULL)
2208 {
2209 lock_td_pool(&uhci->td_pool, TRUE);
2210 if (pthis)
2211 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2212 unlock_td_pool(&uhci->td_pool, TRUE);
2213
2214 return STATUS_NO_MORE_ENTRIES;
2215 }
2216
2217 urb->td_count = td_count;
2218
2219 uhci_insert_tds_qh(pqh, ((PTD_EXTENSION) pthis)->ptd);
2220 uhci_insert_qh_urb(urb, pqh);
2221
2222 usb_endp_busy_count_inc(urb->pendp);
2223 uhci_insert_urb_to_schedule(uhci, urb, ret);
2224 if (ret == FALSE)
2225 {
2226 RemoveEntryList(&pqh->pqhe->vert_link);
2227 RemoveEntryList(&urb->trasac_list);
2228
2229 lock_td_pool(&uhci->td_pool, TRUE);
2230 if (pthis)
2231 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2232 unlock_td_pool(&uhci->td_pool, TRUE);
2233
2234 lock_qh_pool(&uhci->qh_pool, TRUE);
2235 if (pqh)
2236 free_qh(&uhci->qh_pool, pqh);
2237 unlock_qh_pool(&uhci->qh_pool, TRUE);
2238
2239 InitializeListHead(&urb->trasac_list);
2240 usb_endp_busy_count_dec(urb->pendp);
2241 return STATUS_UNSUCCESSFUL;
2242 }
2243
2244 return STATUS_SUCCESS;
2245 }
2246
2247 NTSTATUS
2248 uhci_internal_submit_int(PUHCI_DEV uhci, PURB urb)
2249 {
2250 LONG i;
2251 LONG toggle = 0;
2252 LONG max_packet_size;
2253 PUHCI_TD ptd;
2254 BOOLEAN ret;
2255
2256 if (uhci == NULL || urb == NULL)
2257 {
2258 uhci_dbg_print(DBGLVL_MEDIUM,
2259 ("uhci_internal_submit_int(): uhci=0x%x, urb=0x%x "
2260 "returning STATUS_INVALID_PARAMETER!\n", uhci, urb));
2261 return STATUS_INVALID_PARAMETER;
2262 }
2263
2264 toggle = (urb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE) ? TRUE : FALSE;
2265 max_packet_size = endp_max_packet_size(urb->pendp);
2266
2267 if (max_packet_size < urb->data_length || max_packet_size == 0 || max_packet_size > 64)
2268 {
2269 uhci_dbg_print(DBGLVL_MEDIUM,
2270 ("uhci_internal_submit_int(): max_packet_size=%d, urb->data_length=%d "
2271 "returning STATUS_INVALID_PARAMETER!\n", max_packet_size, urb->data_length));
2272 return STATUS_INVALID_PARAMETER;
2273 }
2274
2275 lock_td_pool(&uhci->td_pool, TRUE);
2276 ptd = alloc_td(&uhci->td_pool);
2277 unlock_td_pool(&uhci->td_pool, TRUE);
2278
2279 if (ptd == NULL)
2280 return STATUS_NO_MORE_ENTRIES;
2281
2282 for(i = 1; i <= 7; i++)
2283 {
2284 if (((ULONG) max_packet_size) >> i)
2285 continue;
2286 else
2287 break;
2288 }
2289
2290 i--;
2291 i &= 7;
2292
2293 urb->pipe = (((ULONG) urb->pendp->pusb_endp_desc->bInterval) << 24)
2294 | (i << 21)
2295 | (toggle << 19)
2296 | ((ULONG) endp_num(urb->pendp) << 15)
2297 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr) << 8)
2298 | USB_DIR_IN | (dev_from_endp(urb->pendp)->flags & USB_DEV_FLAG_LOW_SPEED) | USB_ENDPOINT_XFER_INT;
2299
2300 uhci_fill_td(ptd,
2301 (3 << TD_CTRL_C_ERR_SHIFT)
2302 | (TD_CTRL_ACTIVE)
2303 | ((urb->data_length < max_packet_size ? TD_CTRL_SPD : 0))
2304 | (TD_CTRL_IOC),
2305 (((ULONG) max_packet_size - 1) << 21)
2306 | (toggle << 19)
2307 | ((ULONG) endp_num(urb->pendp) << 15)
2308 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr & 0x7f) << 8)
2309 | USB_PID_IN, MmGetPhysicalAddress(urb->data_buffer).LowPart);
2310
2311 toggle ^= 1;
2312 urb->td_count = 1;
2313
2314 InitializeListHead(&urb->trasac_list);
2315 InsertTailList(&urb->trasac_list, &ptd->ptde->vert_link);
2316
2317 //indirectly guarded by pending_endp_list_lock
2318 if (uhci_claim_bandwidth(uhci, urb, TRUE) == FALSE)
2319 {
2320 InitializeListHead(&urb->trasac_list);
2321
2322 lock_td_pool(&uhci->td_pool, TRUE);
2323 free_td(&uhci->td_pool, ptd);
2324 unlock_td_pool(&uhci->td_pool, TRUE);
2325
2326 return STATUS_NO_MORE_ENTRIES;
2327 }
2328
2329 urb->pendp->flags = (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle << 31);
2330 usb_endp_busy_count_inc(urb->pendp);
2331
2332 uhci_insert_urb_to_schedule(uhci, urb, ret);
2333
2334 if (ret == FALSE)
2335 {
2336 lock_td_pool(&uhci->td_pool, TRUE);
2337 if (ptd)
2338 free_td(&uhci->td_pool, ptd);
2339 unlock_td_pool(&uhci->td_pool, TRUE);
2340
2341 InitializeListHead(&urb->trasac_list);
2342 usb_endp_busy_count_dec(urb->pendp);
2343 urb->pendp->flags = (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | ((toggle ^ 1) << 31);
2344 uhci_claim_bandwidth(uhci, urb, FALSE);
2345 return STATUS_UNSUCCESSFUL;
2346 }
2347
2348 return STATUS_SUCCESS;
2349 }
2350
2351
2352 NTSTATUS
2353 uhci_internal_submit_iso(PUHCI_DEV uhci, PURB urb)
2354 {
2355 PUHCI_TD ptd;
2356 LIST_ENTRY td_list, *pthis, *pnext;
2357 int i;
2358 BOOLEAN toggle = FALSE, ret;
2359
2360 if (uhci == NULL || urb == NULL)
2361 return STATUS_INVALID_PARAMETER;
2362
2363 if (urb->iso_frame_count == 0)
2364 return STATUS_INVALID_PARAMETER;
2365
2366 lock_td_pool(&uhci->td_pool, TRUE);
2367
2368 if (can_transfer(&uhci->td_pool, urb->iso_frame_count) == FALSE)
2369 {
2370 unlock_td_pool(&uhci->td_pool, TRUE);
2371 return STATUS_NO_MORE_ENTRIES;
2372 }
2373
2374 ptd = alloc_tds(&uhci->td_pool, urb->iso_frame_count);
2375 unlock_td_pool(&uhci->td_pool, TRUE);
2376
2377 if (ptd == NULL)
2378 {
2379 return STATUS_UNSUCCESSFUL;
2380 }
2381
2382 InsertTailList(&ptd->ptde->vert_link, &td_list);
2383 ListFirst(&td_list, pthis);
2384
2385 urb->td_count = urb->iso_frame_count;
2386
2387 urb->pipe = (((ULONG) urb->iso_packet_desc[0].length) << 21)
2388 | ((ULONG) endp_num(urb->pendp) << 15)
2389 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr) << 8)
2390 | ((ULONG) endp_dir(urb->pendp)) | USB_ENDPOINT_XFER_ISOC;
2391
2392
2393 for(i = 0; i < urb->iso_frame_count && pthis; i++)
2394 {
2395 ptd = ((PTD_EXTENSION) pthis)->ptd;
2396 uhci_fill_td(ptd,
2397 (3 << TD_CTRL_C_ERR_SHIFT)
2398 | (TD_CTRL_ACTIVE)
2399 | (TD_CTRL_IOS),
2400 (((ULONG) urb->iso_packet_desc[i].length - 1) << 21)
2401 | (0 << 19)
2402 | ((ULONG) endp_num(urb->pendp) << 15)
2403 | (((ULONG) dev_from_endp(urb->pendp)->dev_addr) << 8)
2404 | ((urb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN)
2405 ? USB_PID_OUT : USB_PID_IN),
2406 MmGetPhysicalAddress(&urb->data_buffer[urb->iso_packet_desc[i].offset]).LowPart);
2407
2408 toggle ^= 1;
2409 ListNext(&td_list, pthis, pnext);
2410 pthis = pnext;
2411 }
2412
2413 ptd->status |= TD_CTRL_IOC; //need interrupt
2414
2415 ListFirst(&td_list, pthis);
2416 RemoveEntryList(&td_list);
2417
2418 InsertTailList(pthis, &urb->trasac_list);
2419
2420 //indirectly guarded by pending_endp_list_lock
2421 if (uhci_claim_bandwidth(uhci, urb, TRUE) == FALSE)
2422 {
2423 //bad news: we can not allocate the enough bandwidth for the urb
2424 RemoveEntryList(&urb->trasac_list);
2425 InitializeListHead(&urb->trasac_list);
2426
2427 lock_td_pool(&uhci->td_pool, TRUE);
2428 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2429 unlock_td_pool(&uhci->td_pool, TRUE);
2430 return STATUS_NO_MORE_ENTRIES;
2431
2432 }
2433
2434 usb_endp_busy_count_inc(urb->pendp);
2435 uhci_insert_urb_to_schedule(uhci, urb, ret);
2436 if (ret == FALSE)
2437 {
2438 usb_endp_busy_count_dec(urb->pendp);
2439 RemoveEntryList(&urb->trasac_list);
2440
2441 lock_td_pool(&uhci->td_pool, TRUE);
2442 free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
2443 unlock_td_pool(&uhci->td_pool, TRUE);
2444 uhci_claim_bandwidth(uhci, urb, FALSE);
2445 return STATUS_UNSUCCESSFUL;
2446 }
2447
2448 return STATUS_SUCCESS;
2449 }
2450
2451 // runs in uhci_isr
2452 BOOLEAN
2453 uhci_is_xfer_finished(PURB urb)
2454 {
2455 PLIST_ENTRY pthis, pnext;
2456 PUHCI_TD ptd;
2457 BOOLEAN ret = TRUE;
2458 PTD_EXTENSION ptde;
2459
2460 if (urb->last_finished_td == NULL)
2461 {
2462 urb->last_finished_td = &urb->trasac_list;
2463 }
2464
2465 if (&urb->trasac_list == urb->last_finished_td)
2466 ListFirst(&urb->trasac_list, pthis)
2467 else
2468 ListNext(&urb->trasac_list, urb->last_finished_td, pthis);
2469
2470 while (pthis)
2471 {
2472 if ((((PTD_EXTENSION) pthis)->flags & UHCI_ITEM_FLAG_TYPE) != UHCI_ITEM_FLAG_TD)
2473 {
2474 ListNext(&urb->trasac_list, pthis, pnext);
2475 pthis = pnext;
2476 continue;
2477 }
2478 else
2479 {
2480 ptde = (PTD_EXTENSION) pthis;
2481 ptd = ptde->ptd;
2482 ASSERT(ptd != NULL);
2483
2484 if (ptd->status & TD_CTRL_ACTIVE)
2485 {
2486 //still active
2487 ret = FALSE;
2488 break;
2489 }
2490 //let's see whether error occured
2491 if ((ptd->status & TD_CTRL_ANY_ERROR) == 0)
2492 {
2493 urb->last_finished_td = pthis;
2494 ListNext(&urb->trasac_list, pthis, pnext);
2495 pthis = pnext;
2496 continue;
2497 }
2498 else
2499 {
2500 urb->status = ptd->status;
2501 pthis = NULL;
2502 continue;
2503 }
2504 }
2505
2506 }
2507
2508 if (pthis == NULL)
2509 ret = TRUE;
2510
2511 return ret;
2512 }
2513
2514 // executed in isr, and have frame_list_lock acquired, so
2515 // never try to acquire any spin-lock
2516 // remove the bulk urb from schedule, and mark it not in
2517 // the schedule
2518 BOOLEAN
2519 uhci_remove_urb_from_schedule(PUHCI_DEV uhci, PURB urb)
2520 {
2521 BOOLEAN ret = FALSE;
2522 {
2523 switch (urb->pipe & USB_ENDPOINT_XFERTYPE_MASK)
2524 {
2525 case USB_ENDPOINT_XFER_BULK:
2526 {
2527 ret = uhci_remove_bulk_from_schedule(uhci, urb);
2528 break;
2529 }
2530 case USB_ENDPOINT_XFER_CONTROL:
2531 {
2532 ret = uhci_remove_ctrl_from_schedule(uhci, urb);
2533 break;
2534 }
2535 case USB_ENDPOINT_XFER_INT:
2536 {
2537 ret = uhci_remove_int_from_schedule(uhci, urb);
2538 break;
2539 }
2540 case USB_ENDPOINT_XFER_ISOC:
2541 {
2542 ret = uhci_remove_iso_from_schedule(uhci, urb);
2543 break;
2544 }
2545 }
2546 }
2547 return ret;
2548 }
2549
2550 // executed in isr, and have frame_list_lock acquired, so
2551 // never try to acquire any spin-lock
2552 // remove the bulk urb from schedule, and mark it not in
2553 // the schedule
2554 BOOLEAN
2555 uhci_remove_bulk_from_schedule(PUHCI_DEV uhci, PURB urb)
2556 {
2557
2558 PUHCI_QH pqh, pnext_qh, pprev_qh;
2559 PLIST_ENTRY pthis, pnext, pprev;
2560 LONG i;
2561
2562 if (uhci == NULL || urb == NULL)
2563 return FALSE;
2564
2565 ListFirst(&urb->trasac_list, pthis);
2566 pqh = ((PQH_EXTENSION) pthis)->pqh;
2567
2568 ListFirst(&pqh->pqhe->hori_link, pnext);
2569 ListFirstPrev(&pqh->pqhe->hori_link, pprev);
2570
2571 if (pprev == NULL || pnext == NULL)
2572 return FALSE;
2573
2574 pnext_qh = struct_ptr(pnext, QH_EXTENSION, hori_link)->pqh;
2575 pprev_qh = struct_ptr(pprev, QH_EXTENSION, hori_link)->pqh;
2576
2577 if (pprev != pnext)
2578 {
2579 //not the last one
2580 pprev_qh->link = pnext_qh->phy_addr;
2581 }
2582 else
2583 {
2584 //only two qhs in the list
2585 for(i = 0; i < UHCI_MAX_SKELQHS; i++)
2586 {
2587 if (pprev_qh == uhci->skel_qh[i])
2588 {
2589 break;
2590 }
2591 }
2592 ASSERT(i < UHCI_MAX_SKELQHS - 1);
2593 pprev_qh->link = uhci->skel_qh[i + 1]->phy_addr;
2594 }
2595 RemoveEntryList(&pqh->pqhe->hori_link);
2596
2597 urb->flags &= ~URB_FLAG_IN_SCHEDULE;
2598
2599 if ((urb->pipe & USB_DEV_FLAG_LOW_SPEED) == 0)
2600 uhci_drop_fsbr(uhci);
2601
2602 return TRUE;
2603 }
2604
2605 BOOLEAN
2606 uhci_remove_iso_from_schedule(PUHCI_DEV uhci, PURB urb)
2607 {
2608 PUHCI_TD ptd, pprev_td;
2609 PLIST_ENTRY pthis, pnext, pprev;
2610 int i, idx;
2611
2612 if (uhci == NULL || urb == NULL)
2613 return FALSE;
2614
2615 ListFirst(&urb->trasac_list, pthis);
2616
2617 for(i = 0; i < urb->iso_frame_count && pthis; i++)
2618 {
2619 ptd = ((PTD_EXTENSION) pthis)->ptd;
2620 idx = (urb->iso_start_frame + i) & (UHCI_MAX_FRAMES - 1);
2621
2622 ListFirstPrev(&ptd->ptde->hori_link, pprev);
2623
2624 if (pprev == NULL)
2625 return FALSE;
2626
2627 if (pprev == &uhci->frame_list_cpu[idx].td_link)
2628 {
2629 uhci->frame_list[idx] = ptd->link;
2630 }
2631 else
2632 {
2633 pprev_td = struct_ptr(pprev, TD_EXTENSION, hori_link)->ptd;
2634 pprev_td->link = ptd->link;
2635 }
2636
2637 RemoveEntryList(&ptd->ptde->hori_link);
2638 ListNext(&urb->trasac_list, pthis, pnext);
2639 pthis = pnext;
2640 }
2641
2642 urb->flags &= ~URB_FLAG_IN_SCHEDULE;
2643 return TRUE;
2644 }
2645
2646 BOOLEAN
2647 uhci_remove_int_from_schedule(PUHCI_DEV uhci, PURB urb)
2648 {
2649 PUHCI_TD ptd, pnext_td, pprev_td;
2650 PLIST_ENTRY pthis, pnext, pprev;
2651 LONG i;
2652
2653 if (uhci == NULL || urb == NULL)
2654 return FALSE;
2655
2656 ListFirst(&urb->trasac_list, pthis);
2657 ptd = ((PTD_EXTENSION) pthis)->ptd;
2658 ListFirst(&ptd->ptde->hori_link, pnext);
2659 ListFirstPrev(&ptd->ptde->hori_link, pprev);
2660
2661 if (pprev == NULL || pnext == NULL)
2662 return FALSE;
2663
2664 pnext_td = struct_ptr(pnext, TD_EXTENSION, hori_link)->ptd;
2665 pprev_td = struct_ptr(pprev, TD_EXTENSION, hori_link)->ptd;
2666
2667 if (pprev_td != pnext_td)
2668 pprev_td->link = pnext_td->phy_addr;
2669 else
2670 {
2671 //the last one
2672 for(i = UHCI_MAX_SKELTDS - 2; i >= 0; i--)
2673 {
2674 //UHCI_MAX_SKELTDS -1 skel tds for int transfer
2675 if (pprev_td == uhci->skel_td[i])
2676 break;
2677 }
2678
2679 ASSERT(i >= 0);
2680 if (i == 0)
2681 {
2682 pprev_td->link = uhci->skel_qh[0]->phy_addr;
2683 }
2684 else
2685 {
2686 pprev_td->link = uhci->skel_td[i - 1]->phy_addr;
2687 }
2688 }
2689 RemoveEntryList(&ptd->ptde->hori_link);
2690
2691 urb->flags &= ~URB_FLAG_IN_SCHEDULE;
2692 return TRUE;
2693 }
2694
2695 BOOLEAN
2696 uhci_insert_tds_qh(PUHCI_QH pqh, PUHCI_TD td_chain)
2697 {
2698 if (pqh == NULL || td_chain == NULL)
2699 return FALSE;
2700
2701 InsertTailList(&td_chain->ptde->vert_link, &pqh->pqhe->vert_link);
2702 pqh->element = td_chain->phy_addr;
2703 return TRUE;
2704 }
2705
2706 BOOLEAN
2707 uhci_insert_qh_urb(PURB urb, PUHCI_QH qh_chain)
2708 {
2709 if (urb == NULL || qh_chain == NULL)
2710 return FALSE;
2711
2712 InsertTailList(&qh_chain->pqhe->vert_link, &urb->trasac_list);
2713 qh_chain->pqhe->purb = urb;
2714 return TRUE;
2715 }
2716
2717 // must have dev_lock and frame_list_lock acquired
2718 BOOLEAN
2719 uhci_insert_urb_schedule(PUHCI_DEV uhci, PURB urb)
2720 {
2721 PUHCI_QH pqh, pskel_qh, pnext_qh;
2722 PUHCI_TD ptd, plast_td;
2723 PLIST_ENTRY pthis, pnext;
2724 int i;
2725
2726 if (uhci == NULL || urb == NULL)
2727 return FALSE;
2728
2729 ListFirst(&urb->trasac_list, pthis);
2730 if (pthis == NULL)
2731 return FALSE;
2732
2733 InsertTailList(&uhci->urb_list, &urb->urb_link);
2734
2735 urb->flags &= ~URB_FLAG_STATE_MASK;
2736 urb->flags |= URB_FLAG_STATE_IN_PROCESS | URB_FLAG_IN_SCHEDULE;
2737
2738
2739 switch (endp_type(urb->pendp))
2740 {
2741 case USB_ENDPOINT_XFER_CONTROL:
2742 {
2743 pqh = ((PQH_EXTENSION) pthis)->pqh;
2744
2745 if ((dev_from_endp(urb->pendp)->flags & USB_DEV_FLAG_LOW_SPEED) == 0)
2746 {
2747 pskel_qh = uhci->skel_hs_control_qh;
2748 pnext_qh = uhci->skel_bulk_qh;
2749 }
2750 else
2751 {
2752 pskel_qh = uhci->skel_ls_control_qh;
2753 pnext_qh = uhci->skel_hs_control_qh;
2754 }
2755
2756 ListFirstPrev(&pskel_qh->pqhe->hori_link, pthis);
2757
2758 if (pthis == NULL)
2759 pthis = &pskel_qh->pqhe->hori_link;
2760
2761 InsertTailList(&pskel_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
2762 pqh->link = pnext_qh->phy_addr;
2763 struct_ptr(pthis, QH_EXTENSION, hori_link)->pqh->link = pqh->phy_addr;
2764
2765 //full speed band reclaimation
2766 if ((urb->pipe & USB_DEV_FLAG_LOW_SPEED) == 0)
2767 {
2768 uhci->fsbr_cnt++;
2769 if (uhci->fsbr_cnt == 1)
2770 {
2771 uhci->skel_term_qh->link = uhci->skel_hs_control_qh->phy_addr;
2772 }
2773 }
2774 return TRUE;
2775 }
2776 case USB_ENDPOINT_XFER_BULK:
2777 {
2778 pqh = ((PQH_EXTENSION) pthis)->pqh;
2779
2780 ListFirstPrev(&uhci->skel_bulk_qh->pqhe->hori_link, pthis);
2781
2782 if (pthis == NULL)
2783 pthis = &uhci->skel_bulk_qh->pqhe->hori_link;
2784
2785 InsertTailList(&uhci->skel_bulk_qh->pqhe->hori_link, &pqh->pqhe->hori_link);
2786
2787 pqh->link = uhci->skel_term_qh->phy_addr;
2788 struct_ptr(pthis, QH_EXTENSION, hori_link)->pqh->link = pqh->phy_addr;
2789
2790 //full speed band reclaimation
2791 uhci->fsbr_cnt++;
2792 if (uhci->fsbr_cnt == 1)
2793 {
2794 uhci->skel_term_qh->link = uhci->skel_hs_control_qh->phy_addr;
2795 }
2796
2797 return TRUE;
2798 }
2799 case USB_ENDPOINT_XFER_INT:
2800 {
2801 //bandwidth claim is done outside
2802 ptd = ((PTD_EXTENSION) pthis)->ptd;
2803
2804 get_int_idx(urb, i);
2805
2806 ListFirstPrev(&uhci->skel_td[i]->ptde->hori_link, pthis);
2807 if (pthis == NULL)
2808 pthis = &uhci->skel_td[i]->ptde->hori_link;
2809
2810 InsertTailList(&uhci->skel_td[i]->ptde->hori_link, &ptd->ptde->hori_link);
2811
2812 if (i > 0)
2813 {
2814 ptd->link = uhci->skel_td[i - 1]->phy_addr;
2815 }
2816 else if (i == 0)
2817 {
2818 ptd->link = uhci->skel_qh[0]->phy_addr;
2819 }
2820 //finally link the previous td to this td
2821 struct_ptr(pthis, TD_EXTENSION, hori_link)->ptd->link = ptd->phy_addr;
2822 return TRUE;
2823 }
2824 case USB_ENDPOINT_XFER_ISOC:
2825 {
2826
2827 for(i = 0; i < urb->iso_frame_count; i++)
2828 {
2829 ptd = ((PTD_EXTENSION) pthis)->ptd;
2830 InsertTailList(&uhci->frame_list_cpu[(urb->iso_start_frame + i) & 0x3ff].td_link,
2831 &ptd->ptde->hori_link);
2832
2833 if (IsListEmpty(&uhci->frame_list_cpu[(urb->iso_start_frame + i) & 0x3ff].td_link) == TRUE)
2834 {
2835 ptd->link = uhci->frame_list[(urb->iso_start_frame + i) & 0x3ff];
2836 uhci->frame_list[i] = ptd->phy_addr;
2837 }
2838 else
2839 {
2840 ListFirstPrev(&uhci->frame_list_cpu[(urb->iso_start_frame + i) & 0x3ff].td_link, pnext);
2841 plast_td = struct_ptr(pnext, TD_EXTENSION, hori_link)->ptd;
2842 ptd->link = plast_td->link;
2843 plast_td->link = ptd->phy_addr;
2844 }
2845
2846 ListNext(&urb->trasac_list, pthis, pnext);
2847 pthis = pnext;
2848 }
2849 return TRUE;
2850
2851 }
2852 }
2853 return FALSE;
2854 }
2855
2856 //this function used as the KeSynchronizeExecution param to delegate control to uhci_insert_urb_schedule
2857 BOOLEAN NTAPI
2858 uhci_sync_insert_urb_schedule(PVOID context)
2859 {
2860 PSYNC_PARAM sync_param;
2861 PUHCI_DEV uhci;
2862 PURB purb;
2863
2864 sync_param = (PSYNC_PARAM) context;
2865 if (sync_param == NULL)
2866 return FALSE;
2867
2868 uhci = sync_param->uhci;
2869 purb = (PURB) sync_param->context;
2870
2871 if (uhci == NULL || purb == NULL)
2872 return (UCHAR) (sync_param->ret = FALSE);
2873
2874 return (UCHAR) (sync_param->ret = uhci_insert_urb_schedule(uhci, purb));
2875 }
2876
2877 // be sure pending_endp_list_lock acquired
2878 BOOLEAN
2879 uhci_claim_bandwidth(PUHCI_DEV uhci,
2880 PURB urb,
2881 BOOLEAN claim_bw //true to claim bandwidth, false to free bandwidth
2882 )
2883 {
2884
2885 UCHAR type;
2886 BOOLEAN ls, can_alloc;
2887 LONG bus_time, us;
2888 LONG i, idx, j, start_frame, interval;
2889
2890 if (urb == NULL)
2891 return FALSE;
2892
2893 can_alloc = TRUE;
2894
2895 type = (UCHAR) (urb->pipe & USB_ENDPOINT_XFERTYPE_MASK);
2896 if (type == USB_ENDPOINT_XFER_BULK || type == USB_ENDPOINT_XFER_CONTROL)
2897 {
2898 return FALSE;
2899 }
2900
2901 ls = (urb->pipe & USB_DEV_FLAG_LOW_SPEED) ? TRUE : FALSE;
2902
2903 if (type == USB_ENDPOINT_XFER_INT)
2904 {
2905 start_frame = 0;
2906 i = urb->data_length;
2907 bus_time = usb_calc_bus_time(ls, FALSE, FALSE, i);
2908 us = ns_to_us(bus_time);
2909
2910 i = (urb->pipe >> 24); //polling interval
2911
2912 for(interval = 0, j = 0; j < 8; j++)
2913 {
2914 if (i & (1 << j))
2915 {
2916 interval = j;
2917 }
2918 }
2919
2920 interval = 1 << interval;
2921 start_frame = interval - 1;
2922
2923 if (claim_bw)
2924 {
2925
2926 for(idx = 0; idx < UHCI_MAX_FRAMES; idx += interval)
2927 {
2928 if (uhci->frame_bw[idx] < us)
2929 {
2930 can_alloc = FALSE;
2931 break;
2932 }
2933 }
2934
2935 if (!can_alloc)
2936 {
2937 return FALSE;
2938 }
2939
2940 for(idx = start_frame; idx < UHCI_MAX_FRAMES; idx += interval)
2941 {
2942 uhci->frame_bw[idx] -= us;
2943 }
2944 }
2945 else
2946 {
2947 for(idx = start_frame; idx < UHCI_MAX_FRAMES; idx += interval)
2948 {
2949 uhci->frame_bw[idx] += us;
2950 }
2951 }
2952
2953 }
2954 else if (type == USB_ENDPOINT_XFER_ISOC)
2955 {
2956 if (claim_bw)
2957 {
2958 for(i = 0; i < urb->iso_frame_count; i++)
2959 {
2960 bus_time = usb_calc_bus_time(FALSE,
2961 (urb->pipe & USB_DIR_IN)
2962 ? TRUE : FALSE, TRUE, urb->iso_packet_desc[i].length);
2963
2964 urb->iso_packet_desc[i].bus_time = ns_to_us(bus_time);
2965 }
2966
2967 for(i = 0; i < urb->iso_frame_count; i++)
2968 {
2969 if (uhci->frame_bw[(urb->iso_start_frame + i) & 0x3ff] < urb->iso_packet_desc[i].bus_time)
2970 {
2971 can_alloc = FALSE;
2972 break;
2973 }
2974 }
2975
2976 if (!can_alloc)
2977 {
2978 return FALSE;
2979 }
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 else
2987 {
2988 for(i = 0; i < urb->iso_frame_count; i++)
2989 {
2990 uhci->frame_bw[(urb->iso_start_frame + i) & 0x3ff] += urb->iso_packet_desc[i].bus_time;
2991 }
2992 }
2993
2994 }
2995
2996 return TRUE;
2997 }
2998
2999
3000 //cancel a single urb
3001 BOOLEAN NTAPI
3002 uhci_sync_cancel_urb(PVOID context)
3003 {
3004 PUHCI_DEV uhci;
3005 PSYNC_PARAM sync_param;
3006 PURB purb2, dest_urb;
3007 PLIST_ENTRY pthis, pnext;
3008 BOOLEAN found = FALSE;
3009
3010 if (context == NULL)
3011 return FALSE;
3012
3013 sync_param = (PSYNC_PARAM) context;
3014 uhci = sync_param->uhci;
3015 dest_urb = (PURB) sync_param->context;
3016
3017 if (uhci == NULL || dest_urb == NULL)
3018 return (UCHAR) (sync_param->ret = FALSE);
3019
3020 ListFirst(&uhci->urb_list, pthis);
3021 while (pthis)
3022 {
3023 purb2 = (PURB) pthis;
3024 if (purb2 == dest_urb)
3025 {
3026 found = TRUE;
3027 purb2->flags |= URB_FLAG_FORCE_CANCEL;
3028 break;
3029 }
3030 ListNext(&uhci->urb_list, pthis, pnext);
3031 pthis = pnext;
3032 }
3033 if (found)
3034 uhci->skel_term_td->status |= TD_CTRL_IOC;
3035
3036 return (UCHAR) (sync_param->ret = found);
3037 }
3038
3039 //note any fields of the purb can not be referenced unless it is found in some queue
3040 NTSTATUS
3041 uhci_cancel_urb(PUHCI_DEV uhci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
3042 {
3043 PLIST_ENTRY pthis, pnext;
3044 BOOLEAN found;
3045 PURB purb2;
3046
3047 SYNC_PARAM sync_param;
3048
3049 USE_BASIC_NON_PENDING_IRQL;
3050
3051 if (uhci == NULL || purb == NULL || pdev == NULL || pendp == NULL)
3052 return STATUS_INVALID_PARAMETER;
3053
3054 lock_dev(pdev, FALSE);
3055
3056 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
3057 {
3058 unlock_dev(pdev, FALSE);
3059 //delegate to remove device for this job
3060 return STATUS_DEVICE_DOES_NOT_EXIST;
3061 }
3062
3063 if (dev_from_endp(pendp) != pdev)
3064 {
3065 unlock_dev(pdev, FALSE);
3066 return STATUS_INVALID_PARAMETER;
3067 }
3068
3069 if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
3070 {
3071 //it will be canceled in uhci_process_pending_endp
3072 unlock_dev(pdev, FALSE);
3073 return USB_STATUS_ENDPOINT_HALTED;
3074 }
3075
3076 found = FALSE;
3077 ListFirst(&pendp->urb_list, pthis);
3078 while (pthis)
3079 {
3080 purb2 = (PURB) pthis;
3081 if (purb2 == purb)
3082 {
3083 found = TRUE;
3084 RemoveEntryList(pthis);
3085 InitializeListHead(pthis);
3086 break;
3087 }
3088 ListNext(&pendp->urb_list, pthis, pnext);
3089 pthis = pnext;
3090 }
3091 unlock_dev(pdev, FALSE);
3092
3093 if (found)
3094 {
3095 purb->status = STATUS_CANCELLED;
3096
3097 uhci_generic_urb_completion(purb, purb->context);
3098
3099 lock_dev(pdev, FALSE);
3100 pdev->ref_count--;
3101 unlock_dev(pdev, FALSE);
3102 return STATUS_SUCCESS;
3103 }
3104
3105 // search the urb in the urb-list and try to cancel
3106 sync_param.uhci = uhci;
3107 sync_param.context = purb;
3108
3109 KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_cancel_urb, &sync_param);
3110
3111 found = (BOOLEAN) sync_param.ret;
3112
3113 if (found)
3114 return USB_STATUS_CANCELING;
3115
3116 return STATUS_INVALID_PARAMETER;
3117 }
3118
3119 VOID
3120 uhci_generic_urb_completion(PURB purb, PVOID context)
3121 {
3122 PUSB_DEV pdev;
3123 USE_NON_PENDING_IRQL;
3124
3125 old_irql = KeGetCurrentIrql();