2 * uhci.c - USB driver stack project for Windows NT 4.0
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
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.
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.
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
22 #include "usbdriver.h"
24 //----------------------------------------------------------
30 #define rh_port1_status rh_port_status[ 1 ]
31 #define rh_port2_status rh_port_status[ 2 ]
33 extern PDEVICE_OBJECT
ehci_probe(PDRIVER_OBJECT drvr_obj
, PUNICODE_STRING reg_path
, PUSB_DEV_MANAGER dev_mgr
);
37 #define DEFAULT_ENDP( enDP ) \
38 ( enDP->flags & USB_ENDP_FLAG_DEFAULT_ENDP )
40 #define dev_from_endp( enDP ) \
41 ( DEFAULT_ENDP( enDP )\
42 ? ( ( PUSB_DEV )( enDP )->pusb_if )\
43 : ( ( enDP )->pusb_if->pusb_config->pusb_dev ) )
45 #define endp_state( enDP ) ( ( enDP )->flags & USB_ENDP_FLAG_STAT_MASK )
47 #define endp_num( enDP ) \
48 ( DEFAULT_ENDP( enDP )\
50 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & 0x0f ) )
52 #define endp_dir( enDP ) \
53 ( DEFAULT_ENDP( enDP )\
55 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & USB_DIR_IN ) )
57 #define dev_set_state( pdEV, staTE ) \
58 ( pdEV->flags = ( ( pdEV )->flags & ( ~USB_DEV_STATE_MASK ) ) | ( staTE ) )
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\
65 : enDP->pusb_endp_desc->wMaxPacketSize )
68 #define release_adapter( padapTER ) HalPutDmaAdapter(padapTER)
71 #define get_int_idx( _urb, _idx ) \
74 interVAL = ( UCHAR )( ( _urb )->pipe >> 24 );\
75 for( _idx = 1; _idx < 9; _idx++ )\
84 #define uhci_insert_urb_to_schedule( uHCI, pURB, rET ) \
86 SYNC_PARAM sync_param;\
87 sync_param.uhci = uHCI;\
88 sync_param.context = pURB;\
90 rET = KeSynchronizeExecution( uHCI->pdev_ext->uhci_int, uhci_sync_insert_urb_schedule, &sync_param );\
99 } SYNC_PARAM
, *PSYNC_PARAM
;
102 uhci_alloc(PDRIVER_OBJECT drvr_obj
, PUNICODE_STRING reg_path
, ULONG bus_addr
, PUSB_DEV_MANAGER dev_mgr
);
104 BOOLEAN
uhci_init_schedule(PUHCI_DEV uhci
, PADAPTER_OBJECT padapter
);
106 BOOLEAN
uhci_release(PDEVICE_OBJECT pdev
);
108 static VOID
uhci_stop(PUHCI_DEV uhci
);
110 BOOLEAN
uhci_destroy_schedule(PUHCI_DEV uhci
);
112 BOOLEAN NTAPI
uhci_sync_insert_urb_schedule(PVOID context
);
114 VOID
uhci_init_hcd_interface(PUHCI_DEV uhci
);
116 NTSTATUS
uhci_rh_submit_urb(PUSB_DEV rh
, PURB purb
);
118 NTSTATUS
uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject
, IN PIRP irp
);
120 extern VOID
rh_timer_svc_reset_port_completion(PUSB_DEV dev
, PVOID context
);
122 extern VOID
rh_timer_svc_int_completion(PUSB_DEV dev
, PVOID context
);
124 ULONG debug_level
= DBGLVL_MINIMUM
;//DBGLVL_MAXIMUM;
125 PDRIVER_OBJECT usb_driver_obj
= NULL
;
126 extern USB_DEV_MANAGER g_dev_mgr
;
128 //pending endpoint pool funcs
130 uhci_wait_ms(PUHCI_DEV uhci
, LONG ms
)
136 lms
.QuadPart
= -10 * ms
;
137 KeSetTimer(&uhci
->reset_timer
, lms
, NULL
);
139 KeWaitForSingleObject(&uhci
->reset_timer
, Executive
, KernelMode
, FALSE
, NULL
);
145 init_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool
)
151 pool
->pending_endp_array
=
152 usb_alloc_mem(NonPagedPool
, sizeof(UHCI_PENDING_ENDP
) * UHCI_MAX_PENDING_ENDPS
);
153 InitializeListHead(&pool
->free_que
);
154 pool
->free_count
= 0;
155 pool
->total_count
= UHCI_MAX_PENDING_ENDPS
;
156 KeInitializeSpinLock(&pool
->pool_lock
);
158 for(i
= 0; i
< MAX_TIMER_SVCS
; i
++)
160 free_pending_endp(pool
, &pool
->pending_endp_array
[i
]);
168 free_pending_endp(PUHCI_PENDING_ENDP_POOL pool
, PUHCI_PENDING_ENDP pending_endp
)
170 if (pool
== NULL
|| pending_endp
== NULL
)
175 RtlZeroMemory(pending_endp
, sizeof(UHCI_PENDING_ENDP
));
176 InsertTailList(&pool
->free_que
, &pending_endp
->endp_link
);
183 alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool
, LONG count
)
185 PUHCI_PENDING_ENDP new_endp
;
186 if (pool
== NULL
|| count
!= 1)
189 if (pool
->free_count
<= 0)
192 new_endp
= (PUHCI_PENDING_ENDP
) RemoveHeadList(&pool
->free_que
);
198 destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool
)
203 InitializeListHead(&pool
->free_que
);
204 pool
->free_count
= pool
->total_count
= 0;
205 usb_free_mem(pool
->pending_endp_array
);
206 pool
->pending_endp_array
= NULL
;
213 //end of pending endpoint pool funcs
216 uhci_fill_td(PUHCI_TD td
, ULONG status
, ULONG info
, ULONG buffer
)
224 uhci_insert_td_fl(PUHCI_TD prev_td
, PUHCI_TD ptd
)
226 PLIST_ENTRY temp_entry
;
228 if (prev_td
== NULL
|| ptd
== NULL
)
231 temp_entry
= &prev_td
->ptde
->hori_link
;
233 ptd
->link
= (struct_ptr(temp_entry
, TD_EXTENSION
, hori_link
))->ptd
->phy_addr
;
234 prev_td
->link
= ptd
->phy_addr
;
236 InsertHeadList(&prev_td
->ptde
->hori_link
, &ptd
->ptde
->hori_link
);
241 uhci_remove_td_fl(PUHCI_TD ptd
)
248 prev_td
= (struct_ptr(ptd
->ptde
->hori_link
.Blink
, TD_EXTENSION
, hori_link
))->ptd
;
249 prev_td
->link
= ptd
->link
;
250 ptd
->link
= UHCI_PTR_TERM
;
252 RemoveEntryList(&ptd
->ptde
->hori_link
);
258 uhci_insert_qh_fl(PVOID prev_item
, PUHCI_QH pqh
)
260 //only horizontal link allowed
263 PLIST_ENTRY temp_entry
;
265 if (prev_item
== NULL
|| pqh
== NULL
)
268 if ((((PUHCI_TD
) prev_item
)->ptde
->flags
& UHCI_ITEM_FLAG_TYPE
) == UHCI_ITEM_FLAG_QH
)
270 pprev_qh
= (PUHCI_QH
) prev_item
;
271 temp_entry
= pprev_qh
->pqhe
->hori_link
.Flink
;
272 pqh
->link
= (struct_ptr(temp_entry
, TD_EXTENSION
, hori_link
))->ptd
->phy_addr
;
273 pprev_qh
->link
= pqh
->phy_addr
;
275 InsertHeadList(&pprev_qh
->pqhe
->hori_link
, &pqh
->pqhe
->hori_link
);
279 pprev_td
= ((PUHCI_TD
) prev_item
);
281 temp_entry
= pprev_td
->ptde
->hori_link
.Flink
;
282 pprev_td
->link
= pqh
->phy_addr
;
283 pqh
->link
= (struct_ptr(temp_entry
, TD_EXTENSION
, hori_link
))->ptd
->phy_addr
;
285 InsertHeadList(&pprev_td
->ptde
->hori_link
, &pqh
->pqhe
->hori_link
);
292 uhci_remove_qh_fl(PUHCI_QH pqh
)
301 prev_item
= (struct_ptr(pqh
->pqhe
->hori_link
.Blink
, TD_EXTENSION
, hori_link
))->ptd
;
303 if ((((PUHCI_TD
) prev_item
)->ptde
->flags
& UHCI_ITEM_FLAG_TYPE
) == UHCI_ITEM_FLAG_QH
)
305 pprevqh
= (PUHCI_QH
) prev_item
;
306 pprevqh
->link
= pqh
->link
;
310 pprevtd
= ((PUHCI_TD
) prev_item
);
311 pprevtd
->link
= pqh
->link
;
314 RemoveEntryList(&pqh
->pqhe
->hori_link
);
316 pqh
->link
= UHCI_PTR_TERM
;
317 pqh
->pqhe
->hori_link
.Flink
= pqh
->pqhe
->hori_link
.Blink
= NULL
;
323 uhci_init_frame_list(PUHCI_DEV uhci
, PADAPTER_OBJECT padapter
)
326 if (uhci
== NULL
|| padapter
== NULL
)
329 //note: frame_list_lock will be connected to interrupt
330 KeInitializeSpinLock(&uhci
->frame_list_lock
);
332 uhci
->io_buf
= HalAllocateCommonBuffer(padapter
, 4096, &uhci
->io_buf_logic_addr
, FALSE
);
334 if (uhci
->io_buf
== NULL
)
338 HalAllocateCommonBuffer(padapter
,
339 sizeof(ULONG
) * UHCI_MAX_FRAMES
, &uhci
->frame_list_logic_addr
, FALSE
);
341 if (uhci
->frame_list
== NULL
)
344 RtlZeroMemory(uhci
->frame_list
, sizeof(ULONG
) * UHCI_MAX_FRAMES
);
346 uhci
->frame_list_cpu
= usb_alloc_mem(NonPagedPool
, sizeof(FRAME_LIST_CPU_ENTRY
) * UHCI_MAX_FRAMES
);
348 if (uhci
->frame_list_cpu
== NULL
)
351 for(i
= 0; i
< UHCI_MAX_FRAMES
; i
++)
352 InitializeListHead(&uhci
->frame_list_cpu
[i
].td_link
);
354 uhci
->frame_bw
= usb_alloc_mem(NonPagedPool
, sizeof(LONG
) * UHCI_MAX_FRAMES
);
356 if (uhci
->frame_bw
== NULL
)
359 for(i
= 0; i
< UHCI_MAX_FRAMES
; i
++)
361 uhci
->frame_bw
[i
] = FRAME_TIME_MAX_USECS_ALLOC
;
370 uhci_destroy_frame_list(PUHCI_DEV uhci
)
375 if (uhci
->frame_list
)
376 HalFreeCommonBuffer(uhci
->pdev_ext
->padapter
,
377 sizeof(ULONG
) * UHCI_MAX_FRAMES
,
378 uhci
->frame_list_logic_addr
, uhci
->frame_list
, FALSE
);
380 uhci
->frame_list
= NULL
;
381 uhci
->frame_list_logic_addr
.LowPart
= 0;
382 uhci
->frame_list_logic_addr
.HighPart
= 0;
384 if (uhci
->frame_list_cpu
)
385 usb_free_mem(uhci
->frame_list_cpu
);
387 uhci
->frame_list_cpu
= NULL
;
390 usb_free_mem(uhci
->frame_bw
);
392 uhci
->frame_bw
= NULL
;
398 uhci_create_device(PDRIVER_OBJECT drvr_obj
, PUSB_DEV_MANAGER dev_mgr
)
402 PDEVICE_EXTENSION pdev_ext
;
404 UNICODE_STRING dev_name
;
405 UNICODE_STRING symb_name
;
407 STRING string
, another_string
;
408 CHAR str_dev_name
[64], str_symb_name
[64];
410 if (drvr_obj
== NULL
)
413 ASSERT(dev_mgr
!= NULL
);
415 //note: hcd count wont increment till the hcd is registered in dev_mgr
416 sprintf(str_dev_name
, "%s%d", UHCI_DEVICE_NAME
, dev_mgr
->hcd_count
);
417 sprintf(str_symb_name
, "%s%d", DOS_DEVICE_NAME
, dev_mgr
->hcd_count
);
419 RtlInitString(&string
, str_dev_name
);
420 RtlAnsiStringToUnicodeString(&dev_name
, &string
, TRUE
);
423 status
= IoCreateDevice(drvr_obj
,
424 sizeof(DEVICE_EXTENSION
) + sizeof(UHCI_DEV
),
425 &dev_name
, FILE_UHCI_DEV_TYPE
, 0, FALSE
, &pdev
);
427 if (status
!= STATUS_SUCCESS
|| pdev
== NULL
)
429 RtlFreeUnicodeString(&dev_name
);
433 pdev_ext
= pdev
->DeviceExtension
;
434 RtlZeroMemory(pdev_ext
, sizeof(DEVICE_EXTENSION
) + sizeof(UHCI_DEV
));
436 pdev_ext
->dev_ext_hdr
.type
= NTDEV_TYPE_HCD
;
437 pdev_ext
->dev_ext_hdr
.dispatch
= uhci_dispatch_irp
;
438 pdev_ext
->dev_ext_hdr
.start_io
= NULL
; //we do not support startio
439 pdev_ext
->dev_ext_hdr
.dev_mgr
= dev_mgr
;
441 pdev_ext
->pdev_obj
= pdev
;
442 pdev_ext
->pdrvr_obj
= drvr_obj
;
444 pdev_ext
->uhci
= (PUHCI_DEV
) & (pdev_ext
[1]);
446 RtlInitString(&another_string
, str_symb_name
);
447 RtlAnsiStringToUnicodeString(&symb_name
, &another_string
, TRUE
);
449 IoCreateSymbolicLink(&symb_name
, &dev_name
);
451 uhci_dbg_print(DBGLVL_MAXIMUM
,
452 ("uhci_create_device(): dev=0x%x\n, pdev_ext= 0x%x, uhci=0x%x, dev_mgr=0x%x\n", pdev
,
453 pdev_ext
, pdev_ext
->uhci
, dev_mgr
));
455 RtlFreeUnicodeString(&dev_name
);
456 RtlFreeUnicodeString(&symb_name
);
462 uhci_delete_device(PDEVICE_OBJECT pdev
)
465 UNICODE_STRING symb_name
;
466 PDEVICE_EXTENSION pdev_ext
;
467 CHAR str_symb_name
[64];
473 pdev_ext
= pdev
->DeviceExtension
;
475 sprintf(str_symb_name
,
476 "%s%d", DOS_DEVICE_NAME
, pdev_ext
->uhci
->hcd_interf
.hcd_get_id(&pdev_ext
->uhci
->hcd_interf
));
477 RtlInitString(&string
, str_symb_name
);
478 RtlAnsiStringToUnicodeString(&symb_name
, &string
, TRUE
);
479 IoDeleteSymbolicLink(&symb_name
);
480 RtlFreeUnicodeString(&symb_name
);
482 if (pdev_ext
->res_list
)
483 ExFreePool(pdev_ext
->res_list
); // not allocated by usb_alloc_mem
485 IoDeleteDevice(pdev
);
486 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_delete_device(): device deleted\n"));
490 // we can not use endp here for it is within the dev scope, and
491 // we can not acquire the dev-lock, fortunately we saved some
492 // info in urb->pipe in uhci_internal_submit_XXX.
494 uhci_isr(PKINTERRUPT interrupt
, PVOID context
)
498 PLIST_ENTRY pthis
, pnext
;
501 UNREFERENCED_PARAMETER(interrupt
);
502 UNREFERENCED_PARAMETER(context
);
504 uhci_dbg_print(DBGLVL_ULTRA
, ("uhci_isr(): context=0x%x\n", context
));
507 * Read the interrupt status, and write it back to clear the
510 uhci
= (PUHCI_DEV
) context
;
514 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBSTS
));
515 if (!status
) /* shared interrupt, not mine */
520 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_isr(): current uhci status=0x%x\n", status
));
524 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_isr(): congratulations, no error occurs\n"));
528 WRITE_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBSTS
), status
);
530 if (status
& ~(USBSTS_USBINT
| USBSTS_ERROR
| USBSTS_RD
))
532 if (status
& USBSTS_HSE
)
534 DbgPrint("uhci_isr(): host system error, PCI problems?\n");
537 if (status
& USBSTS_HCPE
)
539 DbgPrint("uhci_isr(): host controller process error. something bad happened\n");
543 if ((status
& USBSTS_HCH
)) //&& !uhci->is_suspended
545 DbgPrint("uhci_isr(): host controller halted. very bad\n");
546 /* FIXME: Reset the controller, fix the offending TD */
550 // don't no how to handle it yet
551 //if (status & USBSTS_RD)
556 //let's remove those force-cancel urbs from the schedule first
557 ListFirst(&uhci
->urb_list
, pthis
);
561 if (purb
->flags
& URB_FLAG_FORCE_CANCEL
)
563 uhci_remove_urb_from_schedule(uhci
, purb
);
565 ListNext(&uhci
->urb_list
, pthis
, pnext
);
569 //clear the interrupt if the urb is force canceled
570 uhci
->skel_term_td
->status
&= ~TD_CTRL_IOC
;
572 //next we need to find if anything fininshed
573 ListFirst(&uhci
->urb_list
, pthis
);
577 if (purb
->flags
& URB_FLAG_IN_SCHEDULE
)
579 if (uhci_is_xfer_finished(purb
))
580 uhci_remove_urb_from_schedule(uhci
, purb
);
582 ListNext(&uhci
->urb_list
, pthis
, pnext
);
586 KeInsertQueueDpc(&uhci
->pdev_ext
->uhci_dpc
, uhci
, 0);
591 uhci_cal_cpu_freq(PVOID context
)
593 UNREFERENCED_PARAMETER(context
);
600 uhci_probe(PDRIVER_OBJECT drvr_obj
, PUNICODE_STRING reg_path
, PUSB_DEV_MANAGER dev_mgr
)
602 LONG bus
, i
, j
, ret
= 0;
603 PCI_SLOT_NUMBER slot_num
;
604 PPCI_COMMON_CONFIG pci_config
;
606 BYTE buffer
[sizeof(PCI_COMMON_CONFIG
)];
608 PDEVICE_EXTENSION pdev_ext
;
610 slot_num
.u
.AsULONG
= 0;
611 pci_config
= (PPCI_COMMON_CONFIG
) buffer
;
615 //scan the PCI buses to find uhci controller
616 for (bus
= 0; bus
<= PCI_MAX_BRIDGE_NUMBER
; bus
++)
618 for(i
= 0; i
<= PCI_MAX_DEVICES
; i
++)
620 slot_num
.u
.bits
.DeviceNumber
= i
;
621 for(j
= 0; j
<= PCI_MAX_FUNCTION
; j
++)
623 slot_num
.u
.bits
.FunctionNumber
= j
;
625 ret
= HalGetBusData(PCIConfiguration
,
626 bus
, slot_num
.u
.AsULONG
, pci_config
, PCI_COMMON_HDR_LENGTH
);
628 if (ret
== 0) /*no this bus */
631 if (ret
== 2) /*no device on the slot */
634 if (pci_config
->BaseClass
== 0x0c && pci_config
->SubClass
== 0x03 &&
635 pci_config
->ProgIf
== 0x00)
637 // well, we find our usb host controller, create device
638 pdev
= uhci_alloc(drvr_obj
, reg_path
, ((bus
<< 8) | (i
<< 3) | j
), dev_mgr
);
655 DbgPrint("Found %d UHCI controllers\n", count
);
659 pdev_ext
= pdev
->DeviceExtension
;
662 // acquire higher irql to eliminate pre-empty
663 KeSynchronizeExecution(pdev_ext
->uhci_int
, uhci_cal_cpu_freq
, NULL
);
670 uhci_alloc(PDRIVER_OBJECT drvr_obj
, PUNICODE_STRING reg_path
, ULONG bus_addr
, PUSB_DEV_MANAGER dev_mgr
)
672 LONG frd_num
, prd_num
;
674 PDEVICE_EXTENSION pdev_ext
;
675 ULONG vector
, addr_space
;
680 DEVICE_DESCRIPTION dev_desc
;
681 CM_PARTIAL_RESOURCE_DESCRIPTOR
*pprd
;
682 PCI_SLOT_NUMBER slot_num
;
687 pdev
= uhci_create_device(drvr_obj
, dev_mgr
);
690 pdev_ext
= pdev
->DeviceExtension
;
692 pdev_ext
->pci_addr
= bus_addr
;
693 bus
= (bus_addr
>> 8);
695 slot_num
.u
.AsULONG
= 0;
696 slot_num
.u
.bits
.DeviceNumber
= ((bus_addr
& 0xff) >> 3);
697 slot_num
.u
.bits
.FunctionNumber
= (bus_addr
& 0x07);
699 //now create adapter object
700 RtlZeroMemory(&dev_desc
, sizeof(dev_desc
));
702 dev_desc
.Version
= DEVICE_DESCRIPTION_VERSION
;
703 dev_desc
.Master
= TRUE
;
704 dev_desc
.ScatterGather
= TRUE
;
705 dev_desc
.Dma32BitAddresses
= TRUE
;
706 dev_desc
.BusNumber
= bus
;
707 dev_desc
.InterfaceType
= PCIBus
;
708 dev_desc
.MaximumLength
=
709 UHCI_MAX_POOL_TDS
* sizeof(UHCI_TD
) * UHCI_MAX_TD_POOLS
710 + sizeof(UHCI_QH
) * UHCI_MAX_POOL_QHS
+ sizeof(ULONG
) * UHCI_MAX_FRAMES
;
712 pdev_ext
->map_regs
= 2; // UHCI_MAX_TD_POOLS +
713 //+ BYTES_TO_PAGES( ( UHCI_MAX_POOL_TDS * 64 ) * UHCI_MAX_TD_POOLS ) ;
715 pdev_ext
->padapter
= HalGetAdapter(&dev_desc
, &pdev_ext
->map_regs
);
717 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_alloc(): padapter=0x%x\n", pdev_ext
->padapter
));
718 if (pdev_ext
->padapter
== NULL
)
721 uhci_delete_device(pdev
);
725 DbgPrint("uhci_alloc(): reg_path=%p, \n \
726 uhci_alloc(): PCIBus=0x%x, bus=0x%x, bus_addr=0x%x \n \
727 uhci_alloc(): slot_num=0x%x, &res_list=%p \n", reg_path
, (DWORD
) PCIBus
, (DWORD
) bus
,
728 (DWORD
) bus_addr
, (DWORD
) slot_num
.u
.AsULONG
, & pdev_ext
->res_list
);
730 //let's allocate resources for this device
731 DbgPrint("uhci_alloc(): about to assign slot res\n");
732 if ((status
= HalAssignSlotResources(reg_path
, NULL
, //no class name yet
733 drvr_obj
, NULL
, //no support of another uhci controller
735 bus
, slot_num
.u
.AsULONG
, &pdev_ext
->res_list
)) != STATUS_SUCCESS
)
737 DbgPrint("uhci_alloc(): error assign slot res, 0x%x\n", status
);
738 release_adapter(pdev_ext
->padapter
);
739 pdev_ext
->padapter
= NULL
;
740 uhci_delete_device(pdev
);
744 //parse the resource list
745 for(frd_num
= 0; frd_num
< (LONG
) pdev_ext
->res_list
->Count
; frd_num
++)
747 for(prd_num
= 0; prd_num
< (LONG
) pdev_ext
->res_list
->List
[frd_num
].PartialResourceList
.Count
;
750 pprd
= &pdev_ext
->res_list
->List
[frd_num
].PartialResourceList
.PartialDescriptors
[prd_num
];
751 if (pprd
->Type
== CmResourceTypePort
)
753 RtlCopyMemory(&pdev_ext
->res_port
, &pprd
->u
.Port
, sizeof(pprd
->u
.Port
));
755 else if (pprd
->Type
== CmResourceTypeInterrupt
)
757 RtlCopyMemory(&pdev_ext
->res_interrupt
, &pprd
->u
.Interrupt
, sizeof(pprd
->u
.Interrupt
));
762 //for port, translate them to system address
764 if (HalTranslateBusAddress(PCIBus
, bus
, pdev_ext
->res_port
.Start
, &addr_space
, //io space
765 &pdev_ext
->uhci
->uhci_reg_base
) != (BOOLEAN
) TRUE
)
767 DbgPrint("uhci_alloc(): error, can not translate bus address\n");
768 release_adapter(pdev_ext
->padapter
);
769 pdev_ext
->padapter
= NULL
;
770 uhci_delete_device(pdev
);
774 DbgPrint("uhci_alloc(): address space=0x%x\n, reg_base=0x%x\n",
775 addr_space
, pdev_ext
->uhci
->uhci_reg_base
.u
.LowPart
);
779 //port has been mapped to memory space
780 pdev_ext
->uhci
->port_mapped
= TRUE
;
781 pdev_ext
->uhci
->port_base
= (PBYTE
) MmMapIoSpace(pdev_ext
->uhci
->uhci_reg_base
,
782 pdev_ext
->res_port
.Length
, FALSE
);
784 //fatal error can not map the registers
785 if (pdev_ext
->uhci
->port_base
== NULL
)
787 release_adapter(pdev_ext
->padapter
);
788 pdev_ext
->padapter
= NULL
;
789 uhci_delete_device(pdev
);
796 pdev_ext
->uhci
->port_mapped
= FALSE
;
797 pdev_ext
->uhci
->port_base
= (PBYTE
) pdev_ext
->uhci
->uhci_reg_base
.LowPart
;
800 //before we connect the interrupt, we have to init uhci
801 pdev_ext
->uhci
->fsbr_cnt
= 0;
802 pdev_ext
->uhci
->pdev_ext
= pdev_ext
;
804 if (uhci_init_schedule(pdev_ext
->uhci
, pdev_ext
->padapter
) == FALSE
)
806 release_adapter(pdev_ext
->padapter
);
807 pdev_ext
->padapter
= NULL
;
808 uhci_delete_device(pdev
);
812 InitializeListHead(&pdev_ext
->uhci
->urb_list
);
813 KeInitializeSpinLock(&pdev_ext
->uhci
->pending_endp_list_lock
);
814 InitializeListHead(&pdev_ext
->uhci
->pending_endp_list
);
816 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_alloc(): pending_endp_list=0x%x\n",
817 &pdev_ext
->uhci
->pending_endp_list
));
819 init_pending_endp_pool(&pdev_ext
->uhci
->pending_endp_pool
);
820 KeInitializeTimer(&pdev_ext
->uhci
->reset_timer
);
822 vector
= HalGetInterruptVector(PCIBus
,
824 pdev_ext
->res_interrupt
.level
,
825 pdev_ext
->res_interrupt
.vector
,
829 KeInitializeDpc(&pdev_ext
->uhci_dpc
, uhci_dpc_callback
, (PVOID
) pdev_ext
->uhci
);
831 //connect the interrupt
832 DbgPrint("uhci_alloc(): the int=0x%x\n", vector
);
833 if (IoConnectInterrupt(&pdev_ext
->uhci_int
,
836 NULL
, //&pdev_ext->uhci->frame_list_lock,
841 TRUE
, //share the vector
843 FALSE
) //No float save
850 //register with dev_mgr
851 uhci_init_hcd_interface(pdev_ext
->uhci
);
852 hcd_id
= dev_mgr_register_hcd(dev_mgr
, &pdev_ext
->uhci
->hcd_interf
);
854 pdev_ext
->uhci
->hcd_interf
.hcd_set_id(&pdev_ext
->uhci
->hcd_interf
, hcd_id
);
855 pdev_ext
->uhci
->hcd_interf
.hcd_set_dev_mgr(&pdev_ext
->uhci
->hcd_interf
, dev_mgr
);
861 uhci_release(PDEVICE_OBJECT pdev
)
863 PDEVICE_EXTENSION pdev_ext
;
869 pdev_ext
= pdev
->DeviceExtension
;
871 if (pdev_ext
== NULL
)
874 uhci
= pdev_ext
->uhci
;
879 //pdev_ext->uhci->conn_count = 0;
880 pdev_ext
->uhci
->fsbr_cnt
= 0;
882 if (pdev_ext
->uhci_int
)
884 IoDisconnectInterrupt(pdev_ext
->uhci_int
);
885 pdev_ext
->uhci_int
= NULL
;
889 destroy_pending_endp_pool(&pdev_ext
->uhci
->pending_endp_pool
);
890 //pdev_ext->uhci->pending_endp_pool = NULL;
892 uhci_destroy_schedule(uhci
);
894 release_adapter(pdev_ext
->padapter
);
895 pdev_ext
->padapter
= NULL
;
897 uhci_delete_device(pdev
);
903 // send cmds to start the uhc
904 // shamelessly copied from linux's uhci.c (reset_hc(), configure_hc() routines)
911 PCI_SLOT_NUMBER SlotNum
;
914 uhci
= uhci_from_hcd(hcd
);
915 io_addr
= uhci
->port_base
;
918 * Reset the HC - this will force us to get a
919 * new notification of any already connected
920 * ports due to the virtual disconnect that it
923 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_HCRESET
);
924 while (READ_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
)) & USBCMD_HCRESET
)
932 /* Turn on all interrupts */
933 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBINTR
),
934 USBINTR_TIMEOUT
| USBINTR_RESUME
| USBINTR_IOC
| USBINTR_SP
);
936 /* Start at frame 0 */
937 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBFRNUM
), 0);
938 WRITE_PORT_ULONG((PULONG
) (io_addr
+ USBFLBASEADD
), uhci
->frame_list_logic_addr
.LowPart
);
940 /* Run and mark it configured with a 64-byte max packet */
941 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_RS
| USBCMD_CF
| USBCMD_MAXP
);
943 DbgPrint("uhci_start(): current uhci status=0x%x\n", uhci_status(uhci
));
946 pirq
= USBLEGSUP_DEFAULT
;
947 SlotNum
.u
.AsULONG
= 0;
948 SlotNum
.u
.bits
.DeviceNumber
= ((uhci
->pdev_ext
->pci_addr
& 0xff) >> 3);
949 SlotNum
.u
.bits
.FunctionNumber
= (uhci
->pdev_ext
->pci_addr
& 0x07);
951 DbgPrint("uhci_start(): set bus %d data at slot 0x%x\n", (uhci
->pdev_ext
->pci_addr
>> 8),
954 HalSetBusDataByOffset(PCIConfiguration
, (uhci
->pdev_ext
->pci_addr
>> 8), SlotNum
.u
.AsULONG
,
955 &pirq
, USBLEGSUP
, sizeof(pirq
));
961 uhci_stop(PUHCI_DEV uhci
)
963 PBYTE io_addr
= uhci
->port_base
;
964 // turn off all the interrupt
965 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBINTR
), 0);
966 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), 0);
970 uhci_reset(PUHCI_DEV uhci
)
972 PBYTE io_addr
= uhci
->port_base
;
975 /* Global reset for 50ms */
976 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_GRESET
);
977 //uhci_wait_ms( uhci, 50 );
980 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), 0);
981 //uhci_wait_ms( uhci, 10 );
986 uhci_suspend(PUHCI_DEV uhci
)
988 PBYTE io_addr
= uhci
->port_base
;
990 //uhci->is_suspended = 1;
991 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_EGSM
);
996 uhci_wakeup(PUHCI_DEV uhci
)
1001 io_addr
= uhci
->port_base
;
1003 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), 0);
1005 /* wait for EOP to be sent */
1006 status
= READ_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
));
1007 while (status
& USBCMD_FGR
)
1008 status
= READ_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
));
1010 //uhci->is_suspended = 0;
1012 /* Run and mark it configured with a 64-byte max packet */
1013 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_RS
| USBCMD_CF
| USBCMD_MAXP
);
1018 uhci_init_schedule(PUHCI_DEV uhci
, PADAPTER_OBJECT padapter
)
1022 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_init_schedule(): entering..., uhci=0x%x\n", uhci
));
1023 if (uhci
== NULL
|| padapter
== NULL
)
1026 if (init_td_pool_list(&uhci
->td_pool
, padapter
) == FALSE
)
1030 if (init_qh_pool(&uhci
->qh_pool
, padapter
) == FALSE
)
1035 //since uhci is not started we can freely access all resources.
1036 for(i
= 0; i
< UHCI_MAX_SKELTDS
; i
++)
1038 uhci
->skel_td
[i
] = alloc_td(&uhci
->td_pool
);
1039 uhci_fill_td(uhci
->skel_td
[i
], 0, (UHCI_NULL_DATA_SIZE
<< 21) | (0x7f << 8) | USB_PID_IN
, 0);
1043 uhci
->skel_td
[i
]->link
= uhci
->skel_td
[i
- 1]->phy_addr
;
1047 /*for( i = UHCI_MAX_SKELTDS - 3; i >= 0; i-- )
1049 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1050 &uhci->skel_td[ i ]->ptde->hori_link );
1053 for(i
= 0; i
< UHCI_MAX_SKELQHS
; i
++)
1055 uhci
->skel_qh
[i
] = alloc_qh(&uhci
->qh_pool
);
1058 uhci
->skel_qh
[i
- 1]->link
= uhci
->skel_qh
[i
]->phy_addr
;
1061 uhci
->skel_qh
[i
]->element
= UHCI_PTR_TERM
;
1064 uhci
->skel_int1_td
->link
= uhci
->skel_ls_control_qh
->phy_addr
;
1067 uhci_fill_td(uhci
->skel_term_td
, 0, (UHCI_NULL_DATA_SIZE
<< 21) | (0x7f << 8) | USB_PID_IN
, 0);
1068 uhci
->skel_term_td
->link
= uhci
->skel_term_td
->phy_addr
;
1070 uhci
->skel_term_qh
->link
= UHCI_PTR_TERM
;
1071 uhci
->skel_term_qh
->element
= uhci
->skel_term_td
->phy_addr
;
1073 InsertTailList(&uhci
->skel_term_qh
->pqhe
->vert_link
, &uhci
->skel_term_td
->ptde
->vert_link
);
1075 /*for( i = 0; i < UHCI_MAX_SKELQHS; i++ )
1077 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1078 &uhci->skel_qh[ i ]->pqhe->hori_link );
1081 if (uhci_init_frame_list(uhci
, uhci
->pdev_ext
->padapter
) == FALSE
)
1082 uhci_destroy_frame_list(uhci
);
1084 //well all have been chained, now scatter the int tds to frame-list
1085 //shamelessly pasted from linux's uhci.c :-)
1086 for(i
= 0; i
< UHCI_MAX_FRAMES
; i
++)
1116 /* Only place we don't use the frame list routines */
1117 uhci
->frame_list
[i
] = uhci
->skel_td
[irq
]->phy_addr
;
1123 uhci_destroy_schedule(PUHCI_DEV uhci
)
1127 ret
= uhci_destroy_frame_list(uhci
);
1128 ret
= destroy_qh_pool(&uhci
->qh_pool
);
1129 ret
= destroy_td_pool_list(&uhci
->td_pool
);
1136 uhci_cancel_pending_endp_urb(IN PVOID Parameter
)
1138 PLIST_ENTRY abort_list
;
1141 USE_BASIC_NON_PENDING_IRQL
;
1143 abort_list
= (PLIST_ENTRY
) Parameter
;
1145 if (abort_list
== NULL
)
1148 while (IsListEmpty(abort_list
) == FALSE
)
1150 //these devs are protected by urb's ref-count
1151 purb
= (PURB
) RemoveHeadList(abort_list
);
1153 // purb->status is set when they are added to abort_list
1155 uhci_generic_urb_completion(purb
, purb
->context
);
1157 lock_dev(pdev
, FALSE
);
1159 unlock_dev(pdev
, FALSE
);
1161 usb_free_mem(abort_list
);
1166 uhci_process_pending_endp(PUHCI_DEV uhci
)
1169 LIST_ENTRY temp_list
, abort_list
;
1172 PUSB_ENDPOINT pendp
;
1173 NTSTATUS can_submit
= STATUS_UNSUCCESSFUL
;
1174 PWORK_QUEUE_ITEM pwork_item
;
1175 PLIST_ENTRY cancel_list
;
1181 InitializeListHead(&temp_list
);
1182 InitializeListHead(&abort_list
);
1185 uhci_dbg_print(DBGLVL_MEDIUM
, ("uhci_process_pending_endp(): entering..., uhci=0x%x\n", uhci
));
1187 lock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1188 while (IsListEmpty(&uhci
->pending_endp_list
) == FALSE
)
1191 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_process_pending_endp(): pending_endp_list=0x%x\n",
1192 &uhci
->pending_endp_list
));
1194 pthis
= RemoveHeadList(&uhci
->pending_endp_list
);
1195 pendp
= ((PUHCI_PENDING_ENDP
) pthis
)->pendp
;
1196 pdev
= dev_from_endp(pendp
);
1198 lock_dev(pdev
, TRUE
);
1200 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
1202 unlock_dev(pdev
, TRUE
);
1203 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1204 //delegate to uhci_remove_device for removing the urb queue on the endpoint
1208 if (endp_state(pendp
) == USB_ENDP_FLAG_STALL
)
1210 while (IsListEmpty(&pendp
->urb_list
) == FALSE
)
1212 purb
= (PURB
) RemoveHeadList(&pendp
->urb_list
);
1213 purb
->status
= USB_STATUS_ENDPOINT_HALTED
;
1214 InsertTailList(&abort_list
, (LIST_ENTRY
*) purb
);
1216 InitializeListHead(&pendp
->urb_list
);
1217 unlock_dev(pdev
, TRUE
);
1218 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1223 if (IsListEmpty(&pendp
->urb_list
) == FALSE
)
1225 purb
= (PURB
) RemoveHeadList(&pendp
->urb_list
);
1230 InitializeListHead(&pendp
->urb_list
);
1231 unlock_dev(pdev
, TRUE
);
1232 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1236 // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
1237 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_process_pending_endp(): endp_type=0x%x\n",
1239 switch (endp_type(pendp
))
1241 case USB_ENDPOINT_XFER_BULK
:
1244 can_submit
= STATUS_UNSUCCESSFUL
;
1246 can_submit
= uhci_internal_submit_bulk(uhci
, purb
);
1250 case USB_ENDPOINT_XFER_CONTROL
:
1252 can_submit
= uhci_internal_submit_ctrl(uhci
, purb
);
1255 case USB_ENDPOINT_XFER_INT
:
1257 can_submit
= uhci_internal_submit_int(uhci
, purb
);
1260 case USB_ENDPOINT_XFER_ISOC
:
1262 can_submit
= uhci_internal_submit_iso(uhci
, purb
);
1267 if (can_submit
== STATUS_NO_MORE_ENTRIES
)
1269 //no enough bandwidth or tds
1270 InsertHeadList(&pendp
->urb_list
, &purb
->urb_link
);
1271 InsertTailList(&temp_list
, pthis
);
1275 // other error or success
1276 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1278 if (can_submit
!= STATUS_SUCCESS
)
1281 InsertTailList(&abort_list
, (LIST_ENTRY
*) purb
);
1282 uhci_dbg_print(DBGLVL_MEDIUM
, ("uhci_process_pending_endp(): unable to submit urb 0x%x, "
1283 "with status=0x%x\n", purb
, can_submit
));
1284 purb
->status
= can_submit
;
1288 unlock_dev(pdev
, TRUE
);
1291 if (IsListEmpty(&temp_list
) == FALSE
)
1293 //re-append them to the pending_endp_list
1294 ListFirst(&temp_list
, pthis
);
1295 RemoveEntryList(&temp_list
);
1296 MergeList(&uhci
->pending_endp_list
, pthis
);
1298 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1300 if (IsListEmpty(&abort_list
) == FALSE
)
1303 cancel_list
= (PLIST_ENTRY
) usb_alloc_mem(NonPagedPool
, sizeof(WORK_QUEUE_ITEM
) + sizeof(LIST_ENTRY
));
1304 ASSERT(cancel_list
);
1306 ListFirst(&abort_list
, pthis
);
1307 RemoveEntryList(&abort_list
);
1308 InsertTailList(pthis
, cancel_list
);
1310 pwork_item
= (PWORK_QUEUE_ITEM
) (cancel_list
+ 1);
1312 // we do not need to worry the uhci_cancel_pending_endp_urb running when the
1313 // driver is unloading since it will prevent the dev_mgr to quit till all the
1314 // reference count to the dev drop to zero.
1315 ExInitializeWorkItem(pwork_item
, uhci_cancel_pending_endp_urb
, (PVOID
) cancel_list
);
1316 ExQueueWorkItem(pwork_item
, DelayedWorkQueue
);
1322 uhci_submit_urb(PUHCI_DEV uhci
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
1325 PUHCI_PENDING_ENDP pending_endp
;
1329 if (uhci
== NULL
|| pdev
== NULL
|| pendp
== NULL
|| purb
== NULL
)
1331 uhci_dbg_print(DBGLVL_MEDIUM
,
1332 ("uhci_submit_urb(): uhci=0x%x, pdev=0x%x, pendp=0x%x, purb=0x%x "
1333 "called with invalid param!\n", uhci
, pdev
, pendp
, purb
));
1334 return STATUS_INVALID_PARAMETER
;
1337 lock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1338 lock_dev(pdev
, TRUE
);
1340 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
1342 status
= purb
->status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1346 if (dev_class(pdev
) == USB_DEV_CLASS_ROOT_HUB
)
1348 unlock_dev(pdev
, TRUE
);
1349 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1350 status
= uhci_rh_submit_urb(pdev
, purb
);
1355 purb
->pendp
= pendp
;
1357 purb
->pendp
= &pdev
->default_endp
;
1359 if (dev_from_endp(purb
->pendp
) != pdev
)
1361 uhci_dbg_print(DBGLVL_MEDIUM
,
1362 ("uhci_submit_urb(): dev_from_endp=0x%x\n, pdev=0x%x, pendp=0x%x "
1363 "devices mismatch!\n", dev_from_endp(purb
->pendp
), pdev
, pendp
));
1365 status
= purb
->status
= STATUS_INVALID_PARAMETER
;
1369 if (endp_state(purb
->pendp
) == USB_ENDP_FLAG_STALL
)
1371 status
= purb
->status
= USB_STATUS_ENDPOINT_HALTED
;
1376 purb
->rest_bytes
= purb
->data_length
;
1378 if (endp_type(purb
->pendp
) == USB_ENDPOINT_XFER_BULK
)
1379 purb
->bytes_to_transfer
= (purb
->data_length
> purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
* UHCI_MAX_TDS_PER_TRANSFER
? purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
* UHCI_MAX_TDS_PER_TRANSFER
: purb
->data_length
); //multiple transfer for large data block
1381 purb
->bytes_to_transfer
= purb
->data_length
;
1383 uhci_dbg_print(DBGLVL_MEDIUM
, ("uhci_submit_urb(): bytes_to_transfer=0x%x\n", purb
->bytes_to_transfer
));
1385 purb
->bytes_transfered
= 0;
1386 InitializeListHead(&purb
->trasac_list
);
1387 purb
->last_finished_td
= &purb
->trasac_list
;
1388 purb
->flags
&= ~(URB_FLAG_STATE_MASK
| URB_FLAG_IN_SCHEDULE
| URB_FLAG_FORCE_CANCEL
);
1389 purb
->flags
|= URB_FLAG_STATE_PENDING
;
1392 i
= IsListEmpty(&pendp
->urb_list
);
1393 InsertTailList(&pendp
->urb_list
, &purb
->urb_link
);
1395 pdev
->ref_count
++; //for urb reference
1399 //there is urb pending, simply queue it and return
1400 status
= purb
->status
= STATUS_PENDING
;
1403 else if (usb_endp_busy_count(purb
->pendp
) && endp_type(purb
->pendp
) != USB_ENDPOINT_XFER_ISOC
)
1406 //No urb waiting but urb overlap not allowed,
1407 //so leave it in queue and return, will be scheduled
1410 status
= purb
->status
= STATUS_PENDING
;
1414 pending_endp
= alloc_pending_endp(&uhci
->pending_endp_pool
, 1);
1415 if (pending_endp
== NULL
)
1418 status
= purb
->status
= STATUS_UNSUCCESSFUL
;
1422 pending_endp
->pendp
= purb
->pendp
;
1423 InsertTailList(&uhci
->pending_endp_list
, &pending_endp
->endp_link
);
1425 unlock_dev(pdev
, TRUE
);
1426 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1428 uhci_process_pending_endp(uhci
);
1429 return STATUS_PENDING
;
1433 RemoveEntryList(&purb
->urb_link
);
1436 unlock_dev(pdev
, TRUE
);
1437 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1442 uhci_set_error_code(PURB urb
, ULONG raw_status
)
1444 if ((raw_status
& TD_CTRL_ANY_ERROR
) == 0)
1446 //test if the urb is canceled
1447 if (urb
->flags
& URB_FLAG_FORCE_CANCEL
)
1448 urb
->status
= STATUS_CANCELLED
;
1450 urb
->status
= STATUS_SUCCESS
;
1453 else if (raw_status
& TD_CTRL_BABBLE
)
1454 urb
->status
= USB_STATUS_DATA_OVERRUN
;
1456 else if (raw_status
& TD_CTRL_STALLED
)
1457 urb
->status
= USB_STATUS_STALL_PID
;
1459 else if (raw_status
& TD_CTRL_DBUFERR
)
1460 urb
->status
= USB_STATUS_BUFFER_OVERRUN
;
1462 else if (raw_status
& TD_CTRL_CRCTIMEO
)
1463 urb
->status
= USB_STATUS_CRC
;
1465 else if (raw_status
& TD_CTRL_BITSTUFF
)
1466 urb
->status
= USB_STATUS_BTSTUFF
;
1469 urb
->status
= STATUS_UNSUCCESSFUL
;
1475 uhci_sync_remove_urb_finished(PVOID context
)
1478 PLIST_ENTRY pthis
, pnext
, ptemp
;
1482 pparam
= (PSYNC_PARAM
) context
;
1483 uhci
= pparam
->uhci
;
1484 ptemp
= (PLIST_ENTRY
) pparam
->context
;
1488 return (UCHAR
) (pparam
->ret
= FALSE
);
1491 ListFirst(&uhci
->urb_list
, pthis
);
1494 //remove urbs not in the schedule
1495 ListNext(&uhci
->urb_list
, pthis
, pnext
);
1496 purb
= (PURB
) pthis
;
1498 if ((purb
->flags
& URB_FLAG_IN_SCHEDULE
) == 0)
1500 //finished or canceled( not apply for split bulk ).
1501 purb
->flags
&= ~URB_FLAG_STATE_MASK
;
1502 purb
->flags
|= URB_FLAG_STATE_FINISHED
;
1503 RemoveEntryList(pthis
);
1504 InsertTailList(ptemp
, pthis
);
1509 return (UCHAR
) TRUE
;
1513 uhci_drop_fsbr(PUHCI_DEV uhci
)
1516 return (UCHAR
) FALSE
;
1520 if (uhci
->fsbr_cnt
<= 0)
1522 uhci
->skel_term_qh
->link
= UHCI_PTR_TERM
;
1526 return (UCHAR
) TRUE
;
1530 uhci_dpc_callback(PKDPC dpc
, PVOID context
, PVOID sysarg1
, PVOID sysarg2
)
1534 LIST_HEAD temp_list
;
1535 PLIST_ENTRY pthis
, pnext
;
1538 PUHCI_PENDING_ENDP pending_endp
;
1540 PUSB_ENDPOINT pendp
;
1544 ULONG uhci_status
, urb_status
, toggle
= 0;
1546 SYNC_PARAM sync_param
;
1547 USE_BASIC_NON_PENDING_IRQL
;
1549 UNREFERENCED_PARAMETER(dpc
);
1550 UNREFERENCED_PARAMETER(sysarg2
);
1552 uhci
= (PUHCI_DEV
) context
;
1556 uhci_status
= (ULONG
) sysarg1
;
1558 InitializeListHead(&temp_list
);
1560 sync_param
.uhci
= uhci
;
1561 sync_param
.context
= (PVOID
) & temp_list
;
1563 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_dpc_callback(): entering..., uhci=0x%x\n", uhci
));
1564 //remove finished urb from uhci's urb-list
1565 KeSynchronizeExecution(uhci
->pdev_ext
->uhci_int
, uhci_sync_remove_urb_finished
, &sync_param
);
1567 //release resources( tds, and qhs ) the urb occupied
1568 while (IsListEmpty(&temp_list
) == FALSE
)
1570 //not in any public queue, if do not access into dev, no race
1571 //condition will occur
1572 purb
= (PURB
) RemoveHeadList(&temp_list
);
1573 urb_status
= purb
->status
;
1575 //the only place we do not use this lock on non-pending-endp-list data ops
1576 KeAcquireSpinLockAtDpcLevel(&uhci
->pending_endp_list_lock
);
1577 while (IsListEmpty(&purb
->trasac_list
) == FALSE
)
1579 pthis
= RemoveHeadList(&purb
->trasac_list
);
1581 if ((((PTD_EXTENSION
) pthis
)->flags
& UHCI_ITEM_FLAG_TYPE
) == UHCI_ITEM_FLAG_QH
)
1583 pqhe
= (PQH_EXTENSION
) pthis
;
1584 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
1585 free_qh(&uhci
->qh_pool
, pqhe
->pqh
);
1586 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
1590 //must be a td chain
1591 InsertHeadList(&purb
->trasac_list
, pthis
);
1592 for(i
= 0, purb
->bytes_transfered
= 0; i
< purb
->td_count
; i
++)
1595 // accumulate data transfered in tds
1596 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
1597 if ((ptd
->status
& TD_CTRL_ACTIVE
) == 0 && (ptd
->status
& TD_CTRL_ANY_ERROR
) == 0)
1599 j
= ptd
->status
& 0x7ff;
1600 purb
->bytes_transfered
+= ((j
== 0x7ff) ? 0 : (j
+ 1));
1603 ListNext(&purb
->trasac_list
, pthis
, pnext
);
1607 if (urb_status
& TD_CTRL_ANY_ERROR
)
1609 if (purb
->last_finished_td
!= NULL
&& purb
->last_finished_td
!= &purb
->trasac_list
)
1610 toggle
= (((PTD_EXTENSION
) purb
->last_finished_td
)->ptd
->info
& (1 << 19));
1612 //trick, remove trasac_list
1613 ListFirst(&purb
->trasac_list
, pthis
);
1614 RemoveEntryList(&purb
->trasac_list
);
1615 lock_td_pool(&uhci
->td_pool
, TRUE
);
1616 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
1617 unlock_td_pool(&uhci
->td_pool
, TRUE
);
1618 //termination condition
1619 InitializeListHead(&purb
->trasac_list
);
1620 purb
->last_finished_td
= NULL
;
1624 if (endp_type(purb
->pendp
) == USB_ENDPOINT_XFER_ISOC
1625 || endp_type(purb
->pendp
) == USB_ENDPOINT_XFER_INT
)
1626 uhci_claim_bandwidth(uhci
, purb
, FALSE
); //release band-width
1628 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1630 uhci_set_error_code(purb
, urb_status
);
1634 //since the ref_count for the urb is not released, we can safely have one
1636 pdev
= dev_from_endp(purb
->pendp
);
1637 pendp
= purb
->pendp
;
1639 if (purb
->status
== USB_STATUS_BABBLE_DETECTED
)
1641 usb_dbg_print(DBGLVL_MEDIUM
,
1642 ("uhci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus\n"));
1644 uhci_start(&uhci
->hcd_interf
);
1647 //this will let the new request in uhci_generic_urb_completion to this endp
1648 //be processed rather than queued in the pending_endp_list
1649 lock_dev(pdev
, TRUE
);
1650 usb_endp_busy_count_dec(pendp
);
1651 unlock_dev(pdev
, TRUE
);
1653 if (usb_success(purb
->status
) == FALSE
)
1655 // set error code and complete the urb and purb is invalid from this point
1656 uhci_generic_urb_completion(purb
, purb
->context
);
1660 if ((purb
->pipe
& USB_ENDPOINT_XFERTYPE_MASK
) == USB_ENDPOINT_XFER_BULK
)
1662 purb
->rest_bytes
-= purb
->bytes_transfered
;
1663 if (purb
->rest_bytes
)
1669 uhci_generic_urb_completion(purb
, purb
->context
);
1674 uhci_generic_urb_completion(purb
, purb
->context
);
1675 //purb is now invalid
1679 KeAcquireSpinLockAtDpcLevel(&uhci
->pending_endp_list_lock
);
1680 lock_dev(pdev
, TRUE
);
1685 if (urb_status
& TD_CTRL_ANY_ERROR
&& endp_type(pendp
) != USB_ENDPOINT_XFER_CONTROL
)
1687 pendp
->flags
&= ~USB_ENDP_FLAG_STAT_MASK
;
1688 pendp
->flags
|= USB_ENDP_FLAG_STALL
;
1691 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
1693 unlock_dev(pdev
, TRUE
);
1694 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1695 if (finished
== FALSE
)
1698 purb
->status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1699 uhci_generic_urb_completion(purb
, purb
->context
);
1701 lock_dev(pdev
, TRUE
);
1703 unlock_dev(pdev
, TRUE
);
1708 if (finished
&& IsListEmpty(&pendp
->urb_list
) == TRUE
)
1710 unlock_dev(pdev
, TRUE
);
1711 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1714 else if (finished
== TRUE
)
1716 //has urb in the endp's urb-list
1717 if (usb_endp_busy_count(pendp
) > 0)
1719 //the urbs still have chance to be sheduled but not this time
1720 unlock_dev(pdev
, TRUE
);
1721 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1726 if (finished
== FALSE
)
1728 //a split bulk transfer
1729 purb
->bytes_transfered
= 0;
1730 purb
->bytes_to_transfer
=
1731 UHCI_MAX_TDS_PER_TRANSFER
* purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
1733 ? purb
->rest_bytes
: UHCI_MAX_TDS_PER_TRANSFER
* purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
;
1735 //the urb is not finished
1736 purb
->flags
&= ~URB_FLAG_STATE_MASK
;
1737 purb
->flags
|= URB_FLAG_STATE_PENDING
;
1739 InsertHeadList(&pendp
->urb_list
, &purb
->urb_link
);
1742 pending_endp
= alloc_pending_endp(&uhci
->pending_endp_pool
, 1);
1745 unlock_dev(pdev
, TRUE
);
1746 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1750 pending_endp
->pendp
= pendp
;
1751 InsertTailList(&uhci
->pending_endp_list
, &pending_endp
->endp_link
);
1753 unlock_dev(pdev
, TRUE
);
1754 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1757 //ah...exhausted, let's find some in the pending_endp_list to rock
1758 uhci_process_pending_endp(uhci
);
1763 uhci_add_device(PUHCI_DEV uhci
, PUSB_DEV dev
)
1765 if (dev
== NULL
|| uhci
== NULL
)
1772 uhci_sync_cancel_urbs_dev(PVOID context
)
1774 //cancel all the urbs on one dev
1776 PUSB_DEV pdev
, dest_dev
;
1777 PSYNC_PARAM sync_param
;
1778 PLIST_ENTRY pthis
, pnext
;
1781 sync_param
= (PSYNC_PARAM
) context
;
1782 dest_dev
= (PUSB_DEV
) sync_param
->context
;
1783 uhci
= sync_param
->uhci
;
1785 if (uhci
== NULL
|| dest_dev
== NULL
)
1787 return (UCHAR
) (sync_param
->ret
= FALSE
);
1790 ListFirst(&uhci
->urb_list
, pthis
);
1793 pdev
= dev_from_endp(((PURB
) pthis
)->pendp
);
1794 if (pdev
== dest_dev
)
1796 ((PURB
) pthis
)->flags
|= URB_FLAG_FORCE_CANCEL
;
1798 ListNext(&uhci
->urb_list
, pthis
, pnext
);
1803 uhci
->skel_term_td
->status
|= TD_CTRL_IOC
;
1805 return (UCHAR
) (sync_param
->ret
= TRUE
);
1809 uhci_remove_device(PUHCI_DEV uhci
, PUSB_DEV dev
)
1811 PUHCI_PENDING_ENDP ppending_endp
;
1812 PLIST_ENTRY pthis
, pnext
;
1814 LIST_HEAD temp_list
;
1816 SYNC_PARAM sync_param
;
1820 if (uhci
== NULL
|| dev
== NULL
)
1823 InitializeListHead(&temp_list
);
1825 //free pending endp that has urb queued from pending endp list
1826 lock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1828 ListFirst(&uhci
->pending_endp_list
, pthis
);
1832 ppending_endp
= (PUHCI_PENDING_ENDP
) pthis
;
1833 ListNext(&uhci
->pending_endp_list
, pthis
, pnext
);
1834 if (dev_from_endp(ppending_endp
->pendp
) == dev
)
1836 RemoveEntryList(pthis
);
1837 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1841 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1843 //cancel all the urbs in the urb-list
1844 sync_param
.uhci
= uhci
;
1845 sync_param
.context
= (PVOID
) dev
;
1847 KeSynchronizeExecution(uhci
->pdev_ext
->uhci_int
, uhci_sync_cancel_urbs_dev
, &sync_param
);
1849 //cancel all the urb in the endp's urb-list
1851 lock_dev(dev
, FALSE
);
1852 if (dev
->usb_config
)
1854 //only for configed dev
1855 for(i
= 0; i
< dev
->usb_config
->if_count
; i
++)
1857 for(j
= 0; j
< dev
->usb_config
->interf
[i
].endp_count
; j
++)
1859 ListFirst(&dev
->usb_config
->interf
[i
].endp
[j
].urb_list
, pthis
);
1862 ListNext(&dev
->usb_config
->interf
[i
].endp
[j
].urb_list
, pthis
, pnext
);
1864 RemoveEntryList(pthis
);
1865 InsertHeadList(&temp_list
, pthis
);
1873 ListFirst(&dev
->default_endp
.urb_list
, pthis
);
1877 ListNext(&dev
->default_endp
.urb_list
, pthis
, pnext
);
1879 RemoveEntryList(pthis
);
1880 InsertHeadList(&temp_list
, pthis
);
1884 unlock_dev(dev
, FALSE
);
1886 if (IsListEmpty(&temp_list
) == FALSE
)
1888 for(i
= 0; i
< k
; i
++)
1890 //complete those urbs with error
1891 pthis
= RemoveHeadList(&temp_list
);
1892 purb
= (PURB
) pthis
;
1893 purb
->status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1895 uhci_generic_urb_completion(purb
, purb
->context
);
1900 lock_dev(dev
, FALSE
) dev
->ref_count
-= k
;
1901 unlock_dev(dev
, FALSE
);
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.
1915 uhci_internal_submit_bulk(PUHCI_DEV uhci
, PURB urb
)
1918 LONG max_packet_size
, td_count
, offset
, bytes_to_transfer
, data_load
;
1922 LIST_ENTRY td_list
, *pthis
, *pnext
;
1923 BOOLEAN old_toggle
, toggle
, ret
;
1926 if (uhci
== NULL
|| urb
== NULL
)
1927 return STATUS_INVALID_PARAMETER
;
1929 max_packet_size
= endp_max_packet_size(urb
->pendp
);
1930 if (urb
->bytes_to_transfer
== 0)
1932 return STATUS_INVALID_PARAMETER
;
1935 td_count
= (urb
->bytes_to_transfer
+ max_packet_size
- 1) / max_packet_size
;
1937 lock_td_pool(&uhci
->td_pool
, TRUE
);
1938 if (can_transfer(&uhci
->td_pool
, td_count
) == FALSE
)
1940 unlock_td_pool(&uhci
->td_pool
, TRUE
);
1941 return STATUS_NO_MORE_ENTRIES
;
1944 ptd
= alloc_tds(&uhci
->td_pool
, td_count
);
1945 unlock_td_pool(&uhci
->td_pool
, TRUE
);
1949 return STATUS_UNSUCCESSFUL
;
1952 InitializeListHead(&td_list
);
1953 InsertTailList(&ptd
->ptde
->vert_link
, &td_list
);
1955 ListFirst(&td_list
, pthis
);
1956 ListNext(&td_list
, pthis
, pnext
);
1958 start_addr
= &urb
->data_buffer
[urb
->data_length
- urb
->rest_bytes
];
1961 old_toggle
= toggle
= urb
->pendp
->flags
& USB_ENDP_FLAG_DATATOGGLE
? TRUE
: FALSE
;
1962 bytes_to_transfer
= urb
->bytes_to_transfer
;
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
;
1969 pid
= (((ULONG
) urb
->pendp
->pusb_endp_desc
->bEndpointAddress
& USB_DIR_IN
) ? USB_PID_IN
: USB_PID_OUT
);
1972 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
1974 data_load
= max_packet_size
< bytes_to_transfer
? max_packet_size
: bytes_to_transfer
;
1977 (3 << TD_CTRL_C_ERR_SHIFT
)
1979 ((data_load
- 1) << 21)
1981 | ((ULONG
) endp_num(urb
->pendp
) << 15)
1982 | (dev_from_endp(urb
->pendp
)->dev_addr
<< 8)
1983 | pid
, MmGetPhysicalAddress(start_addr
+ offset
).LowPart
);
1985 bytes_to_transfer
-= data_load
;
1986 offset
+= data_load
;
1990 ptd
->link
= ((PTD_EXTENSION
) pnext
)->ptd
->phy_addr
;
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
))
1999 //ptd->status |= TD_CTRL_SPD;
2006 ListNext(&td_list
, pthis
, pnext
);
2010 ListFirst(&td_list
, pthis
);
2011 RemoveEntryList(&td_list
);
2013 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
2014 pqh
= alloc_qh(&uhci
->qh_pool
);
2015 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
2019 lock_td_pool(&uhci
->td_pool
, TRUE
);
2022 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2024 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2025 return STATUS_NO_MORE_ENTRIES
;
2029 urb
->td_count
= td_count
;
2031 uhci_insert_tds_qh(pqh
, ((PTD_EXTENSION
) pthis
)->ptd
);
2032 uhci_insert_qh_urb(urb
, pqh
);
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
);
2040 // undo all we have done
2041 RemoveEntryList(&pqh
->pqhe
->vert_link
); //remove qh from td_chain
2042 RemoveEntryList(&urb
->trasac_list
);
2044 lock_td_pool(&uhci
->td_pool
, TRUE
);
2046 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2047 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2049 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
2051 free_qh(&uhci
->qh_pool
, pqh
);
2052 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
2054 InitializeListHead(&urb
->trasac_list
);
2055 usb_endp_busy_count_dec(urb
->pendp
);
2057 (urb
->pendp
->flags
& ~USB_ENDP_FLAG_DATATOGGLE
) | (old_toggle
? USB_ENDP_FLAG_DATATOGGLE
: 0);
2058 return STATUS_UNSUCCESSFUL
;
2060 return STATUS_SUCCESS
;
2064 uhci_internal_submit_ctrl(PUHCI_DEV uhci
, PURB urb
)
2066 LIST_ENTRY td_list
, *pthis
, *pnext
;
2069 LONG max_packet_size
, bytes_to_transfer
, bytes_rest
, start_idx
;
2076 if (uhci
== NULL
|| urb
== NULL
)
2077 return STATUS_INVALID_PARAMETER
;
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
;
2086 lock_td_pool(&uhci
->td_pool
, TRUE
);
2088 if (can_transfer(&uhci
->td_pool
, td_count
) == FALSE
)
2090 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2091 return STATUS_NO_MORE_ENTRIES
;
2094 ptd
= alloc_tds(&uhci
->td_pool
, td_count
);
2095 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2099 return STATUS_UNSUCCESSFUL
;
2102 InsertTailList(&ptd
->ptde
->vert_link
, &td_list
);
2104 ListFirst(&td_list
, pthis
);
2105 ListNext(&td_list
, pthis
, pnext
);
2107 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2109 pdev
= dev_from_endp(urb
->pendp
);
2110 dev_addr
= pdev
->dev_addr
;
2112 if (dev_state(pdev
) <= USB_DEV_STATE_RESET
)
2115 usb_dbg_print(DBGLVL_MAXIMUM
, ("uhci_internal_submit_ctrl(): dev_addr =0x%x\n", dev_addr
));
2117 RtlCopyMemory(uhci
->io_buf
, urb
->setup_packet
, 8);
2119 if ((urb
->setup_packet
[0] & USB_DIR_IN
) == 0) //out
2120 RtlCopyMemory(&uhci
->io_buf
[8], urb
->data_buffer
, bytes_to_transfer
);
2122 RtlZeroMemory(&uhci
->io_buf
[8], bytes_to_transfer
);
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
);
2130 ptd
->link
= ((PTD_EXTENSION
) pnext
)->ptd
->phy_addr
;
2132 ListNext(&td_list
, pthis
, pnext
);
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
;
2138 for(i
= 0, toggle
= 1; ((i
< td_count
- 2) && pthis
); i
++, toggle
^= 1)
2140 //construct tds for DATA packets of data stage.
2141 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2143 (3 << TD_CTRL_C_ERR_SHIFT
)
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
);
2154 ptd
->link
= ((PTD_EXTENSION
) pnext
)->ptd
->phy_addr
;
2156 if (i
< td_count
- 3)
2158 bytes_to_transfer
-= max_packet_size
;
2162 if (bytes_to_transfer
> 0)
2164 if (bytes_to_transfer
< max_packet_size
&& (urb
->setup_packet
[0] & USB_DIR_IN
))
2165 ptd
->status
|= TD_CTRL_SPD
;
2171 ListNext(&td_list
, pthis
, pnext
);
2175 ptd
->link
= ((PTD_EXTENSION
) pnext
)->ptd
->phy_addr
;
2177 ListFirstPrev(&td_list
, pthis
);
2178 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2180 //the last is an IN transaction
2182 (3 << TD_CTRL_C_ERR_SHIFT
)
2183 | (TD_CTRL_ACTIVE
| TD_CTRL_IOC
),
2184 (UHCI_NULL_DATA_SIZE
<< 21)
2186 | (((ULONG
) endp_num(urb
->pendp
)) << 15)
2189 ? ((urb
->setup_packet
[0] & USB_DIR_IN
) ? USB_PID_OUT
: USB_PID_IN
) : USB_PID_IN
), 0);
2191 ptd
->link
= UHCI_PTR_TERM
;
2193 ListFirst(&td_list
, pthis
);
2194 RemoveEntryList(&td_list
);
2196 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
2197 pqh
= alloc_qh(&uhci
->qh_pool
);
2198 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
2202 lock_td_pool(&uhci
->td_pool
, TRUE
);
2204 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2205 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2207 return STATUS_NO_MORE_ENTRIES
;
2210 urb
->td_count
= td_count
;
2212 uhci_insert_tds_qh(pqh
, ((PTD_EXTENSION
) pthis
)->ptd
);
2213 uhci_insert_qh_urb(urb
, pqh
);
2215 usb_endp_busy_count_inc(urb
->pendp
);
2216 uhci_insert_urb_to_schedule(uhci
, urb
, ret
);
2219 RemoveEntryList(&pqh
->pqhe
->vert_link
);
2220 RemoveEntryList(&urb
->trasac_list
);
2222 lock_td_pool(&uhci
->td_pool
, TRUE
);
2224 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2225 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2227 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
2229 free_qh(&uhci
->qh_pool
, pqh
);
2230 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
2232 InitializeListHead(&urb
->trasac_list
);
2233 usb_endp_busy_count_dec(urb
->pendp
);
2234 return STATUS_UNSUCCESSFUL
;
2237 return STATUS_SUCCESS
;
2241 uhci_internal_submit_int(PUHCI_DEV uhci
, PURB urb
)
2245 LONG max_packet_size
;
2249 if (uhci
== NULL
|| urb
== NULL
)
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
;
2257 toggle
= (urb
->pendp
->flags
& USB_ENDP_FLAG_DATATOGGLE
) ? TRUE
: FALSE
;
2258 max_packet_size
= endp_max_packet_size(urb
->pendp
);
2260 if (max_packet_size
< urb
->data_length
|| max_packet_size
== 0 || max_packet_size
> 64)
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
;
2268 lock_td_pool(&uhci
->td_pool
, TRUE
);
2269 ptd
= alloc_td(&uhci
->td_pool
);
2270 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2273 return STATUS_NO_MORE_ENTRIES
;
2275 for(i
= 1; i
<= 7; i
++)
2277 if (((ULONG
) max_packet_size
) >> i
)
2286 urb
->pipe
= (((ULONG
) urb
->pendp
->pusb_endp_desc
->bInterval
) << 24)
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
;
2294 (3 << TD_CTRL_C_ERR_SHIFT
)
2296 | ((urb
->data_length
< max_packet_size
? TD_CTRL_SPD
: 0))
2298 (((ULONG
) max_packet_size
- 1) << 21)
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
);
2307 InitializeListHead(&urb
->trasac_list
);
2308 InsertTailList(&urb
->trasac_list
, &ptd
->ptde
->vert_link
);
2310 //indirectly guarded by pending_endp_list_lock
2311 if (uhci_claim_bandwidth(uhci
, urb
, TRUE
) == FALSE
)
2313 InitializeListHead(&urb
->trasac_list
);
2315 lock_td_pool(&uhci
->td_pool
, TRUE
);
2316 free_td(&uhci
->td_pool
, ptd
);
2317 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2319 return STATUS_NO_MORE_ENTRIES
;
2322 urb
->pendp
->flags
= (urb
->pendp
->flags
& ~USB_ENDP_FLAG_DATATOGGLE
) | (toggle
<< 31);
2323 usb_endp_busy_count_inc(urb
->pendp
);
2325 uhci_insert_urb_to_schedule(uhci
, urb
, ret
);
2329 lock_td_pool(&uhci
->td_pool
, TRUE
);
2331 free_td(&uhci
->td_pool
, ptd
);
2332 unlock_td_pool(&uhci
->td_pool
, TRUE
);
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
;
2341 return STATUS_SUCCESS
;
2346 uhci_internal_submit_iso(PUHCI_DEV uhci
, PURB urb
)
2349 LIST_ENTRY td_list
, *pthis
, *pnext
;
2351 BOOLEAN toggle
= FALSE
, ret
;
2353 if (uhci
== NULL
|| urb
== NULL
)
2354 return STATUS_INVALID_PARAMETER
;
2356 if (urb
->iso_frame_count
== 0)
2357 return STATUS_INVALID_PARAMETER
;
2359 lock_td_pool(&uhci
->td_pool
, TRUE
);
2361 if (can_transfer(&uhci
->td_pool
, urb
->iso_frame_count
) == FALSE
)
2363 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2364 return STATUS_NO_MORE_ENTRIES
;
2367 ptd
= alloc_tds(&uhci
->td_pool
, urb
->iso_frame_count
);
2368 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2372 return STATUS_UNSUCCESSFUL
;
2375 InsertTailList(&ptd
->ptde
->vert_link
, &td_list
);
2376 ListFirst(&td_list
, pthis
);
2378 urb
->td_count
= urb
->iso_frame_count
;
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
;
2386 for(i
= 0; i
< urb
->iso_frame_count
&& pthis
; i
++)
2388 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2390 (3 << TD_CTRL_C_ERR_SHIFT
)
2393 (((ULONG
) urb
->iso_packet_desc
[i
].length
- 1) << 21)
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
);
2402 ListNext(&td_list
, pthis
, pnext
);
2406 ptd
->status
|= TD_CTRL_IOC
; //need interrupt
2408 ListFirst(&td_list
, pthis
);
2409 RemoveEntryList(&td_list
);
2411 InsertTailList(pthis
, &urb
->trasac_list
);
2413 //indirectly guarded by pending_endp_list_lock
2414 if (uhci_claim_bandwidth(uhci
, urb
, TRUE
) == FALSE
)
2416 //bad news: we can not allocate the enough bandwidth for the urb
2417 RemoveEntryList(&urb
->trasac_list
);
2418 InitializeListHead(&urb
->trasac_list
);
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
;
2427 usb_endp_busy_count_inc(urb
->pendp
);
2428 uhci_insert_urb_to_schedule(uhci
, urb
, ret
);
2431 usb_endp_busy_count_dec(urb
->pendp
);
2432 RemoveEntryList(&urb
->trasac_list
);
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
;
2441 return STATUS_SUCCESS
;
2446 uhci_is_xfer_finished(PURB urb
)
2448 PLIST_ENTRY pthis
, pnext
;
2453 if (urb
->last_finished_td
== NULL
)
2455 urb
->last_finished_td
= &urb
->trasac_list
;
2458 if (&urb
->trasac_list
== urb
->last_finished_td
)
2459 ListFirst(&urb
->trasac_list
, pthis
)
2461 ListNext(&urb
->trasac_list
, urb
->last_finished_td
, pthis
);
2465 if ((((PTD_EXTENSION
) pthis
)->flags
& UHCI_ITEM_FLAG_TYPE
) != UHCI_ITEM_FLAG_TD
)
2467 ListNext(&urb
->trasac_list
, pthis
, pnext
);
2473 ptde
= (PTD_EXTENSION
) pthis
;
2475 ASSERT(ptd
!= NULL
);
2477 if (ptd
->status
& TD_CTRL_ACTIVE
)
2483 //let's see whether error occured
2484 if ((ptd
->status
& TD_CTRL_ANY_ERROR
) == 0)
2486 urb
->last_finished_td
= pthis
;
2487 ListNext(&urb
->trasac_list
, pthis
, pnext
);
2493 urb
->status
= ptd
->status
;
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
2512 uhci_remove_urb_from_schedule(PUHCI_DEV uhci
, PURB urb
)
2514 BOOLEAN ret
= FALSE
;
2516 switch (urb
->pipe
& USB_ENDPOINT_XFERTYPE_MASK
)
2518 case USB_ENDPOINT_XFER_BULK
:
2520 ret
= uhci_remove_bulk_from_schedule(uhci
, urb
);
2523 case USB_ENDPOINT_XFER_CONTROL
:
2525 ret
= uhci_remove_ctrl_from_schedule(uhci
, urb
);
2528 case USB_ENDPOINT_XFER_INT
:
2530 ret
= uhci_remove_int_from_schedule(uhci
, urb
);
2533 case USB_ENDPOINT_XFER_ISOC
:
2535 ret
= uhci_remove_iso_from_schedule(uhci
, urb
);
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
2548 uhci_remove_bulk_from_schedule(PUHCI_DEV uhci
, PURB urb
)
2551 PUHCI_QH pqh
, pnext_qh
, pprev_qh
;
2552 PLIST_ENTRY pthis
, pnext
, pprev
;
2555 if (uhci
== NULL
|| urb
== NULL
)
2558 ListFirst(&urb
->trasac_list
, pthis
);
2559 pqh
= ((PQH_EXTENSION
) pthis
)->pqh
;
2561 ListFirst(&pqh
->pqhe
->hori_link
, pnext
);
2562 ListFirstPrev(&pqh
->pqhe
->hori_link
, pprev
);
2564 if (pprev
== NULL
|| pnext
== NULL
)
2567 pnext_qh
= struct_ptr(pnext
, QH_EXTENSION
, hori_link
)->pqh
;
2568 pprev_qh
= struct_ptr(pprev
, QH_EXTENSION
, hori_link
)->pqh
;
2573 pprev_qh
->link
= pnext_qh
->phy_addr
;
2577 //only two qhs in the list
2578 for(i
= 0; i
< UHCI_MAX_SKELQHS
; i
++)
2580 if (pprev_qh
== uhci
->skel_qh
[i
])
2585 ASSERT(i
< UHCI_MAX_SKELQHS
- 1);
2586 pprev_qh
->link
= uhci
->skel_qh
[i
+ 1]->phy_addr
;
2588 RemoveEntryList(&pqh
->pqhe
->hori_link
);
2590 urb
->flags
&= ~URB_FLAG_IN_SCHEDULE
;
2592 if ((urb
->pipe
& USB_DEV_FLAG_LOW_SPEED
) == 0)
2593 uhci_drop_fsbr(uhci
);
2599 uhci_remove_iso_from_schedule(PUHCI_DEV uhci
, PURB urb
)
2601 PUHCI_TD ptd
, pprev_td
;
2602 PLIST_ENTRY pthis
, pnext
, pprev
;
2605 if (uhci
== NULL
|| urb
== NULL
)
2608 ListFirst(&urb
->trasac_list
, pthis
);
2610 for(i
= 0; i
< urb
->iso_frame_count
&& pthis
; i
++)
2612 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2613 idx
= (urb
->iso_start_frame
+ i
) & (UHCI_MAX_FRAMES
- 1);
2615 ListFirstPrev(&ptd
->ptde
->hori_link
, pprev
);
2620 if (pprev
== &uhci
->frame_list_cpu
[idx
].td_link
)
2622 uhci
->frame_list
[idx
] = ptd
->link
;
2626 pprev_td
= struct_ptr(pprev
, TD_EXTENSION
, hori_link
)->ptd
;
2627 pprev_td
->link
= ptd
->link
;
2630 RemoveEntryList(&ptd
->ptde
->hori_link
);
2631 ListNext(&urb
->trasac_list
, pthis
, pnext
);
2635 urb
->flags
&= ~URB_FLAG_IN_SCHEDULE
;
2640 uhci_remove_int_from_schedule(PUHCI_DEV uhci
, PURB urb
)
2642 PUHCI_TD ptd
, pnext_td
, pprev_td
;
2643 PLIST_ENTRY pthis
, pnext
, pprev
;
2646 if (uhci
== NULL
|| urb
== NULL
)
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
);
2654 if (pprev
== NULL
|| pnext
== NULL
)
2657 pnext_td
= struct_ptr(pnext
, TD_EXTENSION
, hori_link
)->ptd
;
2658 pprev_td
= struct_ptr(pprev
, TD_EXTENSION
, hori_link
)->ptd
;
2660 if (pprev_td
!= pnext_td
)
2661 pprev_td
->link
= pnext_td
->phy_addr
;
2665 for(i
= UHCI_MAX_SKELTDS
- 2; i
>= 0; i
--)
2667 //UHCI_MAX_SKELTDS -1 skel tds for int transfer
2668 if (pprev_td
== uhci
->skel_td
[i
])
2675 pprev_td
->link
= uhci
->skel_qh
[0]->phy_addr
;
2679 pprev_td
->link
= uhci
->skel_td
[i
- 1]->phy_addr
;
2682 RemoveEntryList(&ptd
->ptde
->hori_link
);
2684 urb
->flags
&= ~URB_FLAG_IN_SCHEDULE
;
2689 uhci_insert_tds_qh(PUHCI_QH pqh
, PUHCI_TD td_chain
)
2691 if (pqh
== NULL
|| td_chain
== NULL
)
2694 InsertTailList(&td_chain
->ptde
->vert_link
, &pqh
->pqhe
->vert_link
);
2695 pqh
->element
= td_chain
->phy_addr
;
2700 uhci_insert_qh_urb(PURB urb
, PUHCI_QH qh_chain
)
2702 if (urb
== NULL
|| qh_chain
== NULL
)
2705 InsertTailList(&qh_chain
->pqhe
->vert_link
, &urb
->trasac_list
);
2706 qh_chain
->pqhe
->purb
= urb
;
2710 // must have dev_lock and frame_list_lock acquired
2712 uhci_insert_urb_schedule(PUHCI_DEV uhci
, PURB urb
)
2714 PUHCI_QH pqh
, pskel_qh
, pnext_qh
;
2715 PUHCI_TD ptd
, plast_td
;
2716 PLIST_ENTRY pthis
, pnext
;
2719 if (uhci
== NULL
|| urb
== NULL
)
2722 ListFirst(&urb
->trasac_list
, pthis
);
2726 InsertTailList(&uhci
->urb_list
, &urb
->urb_link
);
2728 urb
->flags
&= ~URB_FLAG_STATE_MASK
;
2729 urb
->flags
|= URB_FLAG_STATE_IN_PROCESS
| URB_FLAG_IN_SCHEDULE
;
2732 switch (endp_type(urb
->pendp
))
2734 case USB_ENDPOINT_XFER_CONTROL
:
2736 pqh
= ((PQH_EXTENSION
) pthis
)->pqh
;
2738 if ((dev_from_endp(urb
->pendp
)->flags
& USB_DEV_FLAG_LOW_SPEED
) == 0)
2740 pskel_qh
= uhci
->skel_hs_control_qh
;
2741 pnext_qh
= uhci
->skel_bulk_qh
;
2745 pskel_qh
= uhci
->skel_ls_control_qh
;
2746 pnext_qh
= uhci
->skel_hs_control_qh
;
2749 ListFirstPrev(&pskel_qh
->pqhe
->hori_link
, pthis
);
2752 pthis
= &pskel_qh
->pqhe
->hori_link
;
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
;
2758 //full speed band reclaimation
2759 if ((urb
->pipe
& USB_DEV_FLAG_LOW_SPEED
) == 0)
2762 if (uhci
->fsbr_cnt
== 1)
2764 uhci
->skel_term_qh
->link
= uhci
->skel_hs_control_qh
->phy_addr
;
2769 case USB_ENDPOINT_XFER_BULK
:
2771 pqh
= ((PQH_EXTENSION
) pthis
)->pqh
;
2773 ListFirstPrev(&uhci
->skel_bulk_qh
->pqhe
->hori_link
, pthis
);
2776 pthis
= &uhci
->skel_bulk_qh
->pqhe
->hori_link
;
2778 InsertTailList(&uhci
->skel_bulk_qh
->pqhe
->hori_link
, &pqh
->pqhe
->hori_link
);
2780 pqh
->link
= uhci
->skel_term_qh
->phy_addr
;
2781 struct_ptr(pthis
, QH_EXTENSION
, hori_link
)->pqh
->link
= pqh
->phy_addr
;
2783 //full speed band reclaimation
2785 if (uhci
->fsbr_cnt
== 1)
2787 uhci
->skel_term_qh
->link
= uhci
->skel_hs_control_qh
->phy_addr
;
2792 case USB_ENDPOINT_XFER_INT
:
2794 //bandwidth claim is done outside
2795 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2797 get_int_idx(urb
, i
);
2799 ListFirstPrev(&uhci
->skel_td
[i
]->ptde
->hori_link
, pthis
);
2801 pthis
= &uhci
->skel_td
[i
]->ptde
->hori_link
;
2803 InsertTailList(&uhci
->skel_td
[i
]->ptde
->hori_link
, &ptd
->ptde
->hori_link
);
2807 ptd
->link
= uhci
->skel_td
[i
- 1]->phy_addr
;
2811 ptd
->link
= uhci
->skel_qh
[0]->phy_addr
;
2813 //finally link the previous td to this td
2814 struct_ptr(pthis
, TD_EXTENSION
, hori_link
)->ptd
->link
= ptd
->phy_addr
;
2817 case USB_ENDPOINT_XFER_ISOC
:
2820 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
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
);
2826 if (IsListEmpty(&uhci
->frame_list_cpu
[(urb
->iso_start_frame
+ i
) & 0x3ff].td_link
) == TRUE
)
2828 ptd
->link
= uhci
->frame_list
[(urb
->iso_start_frame
+ i
) & 0x3ff];
2829 uhci
->frame_list
[i
] = ptd
->phy_addr
;
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
;
2839 ListNext(&urb
->trasac_list
, pthis
, pnext
);
2849 //this function used as the KeSynchronizeExecution param to delegate control to uhci_insert_urb_schedule
2851 uhci_sync_insert_urb_schedule(PVOID context
)
2853 PSYNC_PARAM sync_param
;
2857 sync_param
= (PSYNC_PARAM
) context
;
2858 if (sync_param
== NULL
)
2861 uhci
= sync_param
->uhci
;
2862 purb
= (PURB
) sync_param
->context
;
2864 if (uhci
== NULL
|| purb
== NULL
)
2865 return (UCHAR
) (sync_param
->ret
= FALSE
);
2867 return (UCHAR
) (sync_param
->ret
= uhci_insert_urb_schedule(uhci
, purb
));
2870 // be sure pending_endp_list_lock acquired
2872 uhci_claim_bandwidth(PUHCI_DEV uhci
,
2874 BOOLEAN claim_bw
//true to claim bandwidth, false to free bandwidth
2879 BOOLEAN ls
, can_alloc
;
2881 LONG i
, idx
, j
, start_frame
, interval
;
2888 type
= (UCHAR
) (urb
->pipe
& USB_ENDPOINT_XFERTYPE_MASK
);
2889 if (type
== USB_ENDPOINT_XFER_BULK
|| type
== USB_ENDPOINT_XFER_CONTROL
)
2894 ls
= (urb
->pipe
& USB_DEV_FLAG_LOW_SPEED
) ? TRUE
: FALSE
;
2896 if (type
== USB_ENDPOINT_XFER_INT
)
2899 i
= urb
->data_length
;
2900 bus_time
= usb_calc_bus_time(ls
, FALSE
, FALSE
, i
);
2901 us
= ns_to_us(bus_time
);
2903 i
= (urb
->pipe
>> 24); //polling interval
2905 for(interval
= 0, j
= 0; j
< 8; j
++)
2913 interval
= 1 << interval
;
2914 start_frame
= interval
- 1;
2919 for(idx
= 0; idx
< UHCI_MAX_FRAMES
; idx
+= interval
)
2921 if (uhci
->frame_bw
[idx
] < us
)
2933 for(idx
= start_frame
; idx
< UHCI_MAX_FRAMES
; idx
+= interval
)
2935 uhci
->frame_bw
[idx
] -= us
;
2940 for(idx
= start_frame
; idx
< UHCI_MAX_FRAMES
; idx
+= interval
)
2942 uhci
->frame_bw
[idx
] += us
;
2947 else if (type
== USB_ENDPOINT_XFER_ISOC
)
2951 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
2953 bus_time
= usb_calc_bus_time(FALSE
,
2954 (urb
->pipe
& USB_DIR_IN
)
2955 ? TRUE
: FALSE
, TRUE
, urb
->iso_packet_desc
[i
].length
);
2957 urb
->iso_packet_desc
[i
].bus_time
= ns_to_us(bus_time
);
2960 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
2962 if (uhci
->frame_bw
[(urb
->iso_start_frame
+ i
) & 0x3ff] < urb
->iso_packet_desc
[i
].bus_time
)
2974 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
2976 uhci
->frame_bw
[(urb
->iso_start_frame
+ i
) & 0x3ff] -= urb
->iso_packet_desc
[i
].bus_time
;
2981 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
2983 uhci
->frame_bw
[(urb
->iso_start_frame
+ i
) & 0x3ff] += urb
->iso_packet_desc
[i
].bus_time
;
2993 //cancel a single urb
2995 uhci_sync_cancel_urb(PVOID context
)
2998 PSYNC_PARAM sync_param
;
2999 PURB purb2
, dest_urb
;
3000 PLIST_ENTRY pthis
, pnext
;
3001 BOOLEAN found
= FALSE
;
3003 if (context
== NULL
)
3006 sync_param
= (PSYNC_PARAM
) context
;
3007 uhci
= sync_param
->uhci
;
3008 dest_urb
= (PURB
) sync_param
->context
;
3010 if (uhci
== NULL
|| dest_urb
== NULL
)
3011 return (UCHAR
) (sync_param
->ret
= FALSE
);
3013 ListFirst(&uhci
->urb_list
, pthis
);
3016 purb2
= (PURB
) pthis
;
3017 if (purb2
== dest_urb
)
3020 purb2
->flags
|= URB_FLAG_FORCE_CANCEL
;
3023 ListNext(&uhci
->urb_list
, pthis
, pnext
);
3027 uhci
->skel_term_td
->status
|= TD_CTRL_IOC
;
3029 return (UCHAR
) (sync_param
->ret
= found
);
3032 //note any fields of the purb can not be referenced unless it is found in some queue
3034 uhci_cancel_urb(PUHCI_DEV uhci
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
3036 PLIST_ENTRY pthis
, pnext
;
3040 SYNC_PARAM sync_param
;
3042 USE_BASIC_NON_PENDING_IRQL
;
3044 if (uhci
== NULL
|| purb
== NULL
|| pdev
== NULL
|| pendp
== NULL
)
3045 return STATUS_INVALID_PARAMETER
;
3047 lock_dev(pdev
, FALSE
);
3049 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
3051 unlock_dev(pdev
, FALSE
);
3052 //delegate to remove device for this job
3053 return STATUS_DEVICE_DOES_NOT_EXIST
;
3056 if (dev_from_endp(pendp
) != pdev
)
3058 unlock_dev(pdev
, FALSE
);
3059 return STATUS_INVALID_PARAMETER
;
3062 if (endp_state(pendp
) == USB_ENDP_FLAG_STALL
)
3064 //it will be canceled in uhci_process_pending_endp
3065 unlock_dev(pdev
, FALSE
);
3066 return USB_STATUS_ENDPOINT_HALTED
;
3070 ListFirst(&pendp
->urb_list
, pthis
);
3073 purb2
= (PURB
) pthis
;
3077 RemoveEntryList(pthis
);
3078 InitializeListHead(pthis
);
3081 ListNext(&pendp
->urb_list
, pthis
, pnext
);
3084 unlock_dev(pdev
, FALSE
);
3088 purb
->status
= STATUS_CANCELLED
;
3090 uhci_generic_urb_completion(purb
, purb
->context
);
3092 lock_dev(pdev
, FALSE
);
3094 unlock_dev(pdev
, FALSE
);
3095 return STATUS_SUCCESS
;
3098 // search the urb in the urb-list and try to cancel
3099 sync_param
.uhci
= uhci
;
3100 sync_param
.context
= purb
;
3102 KeSynchronizeExecution(uhci
->pdev_ext
->uhci_int
, uhci_sync_cancel_urb
, &sync_param
);
3104 found
= (BOOLEAN
) sync_param
.ret
;
3107 return USB_STATUS_CANCELING
;
3109 return STATUS_INVALID_PARAMETER
;
3113 uhci_generic_urb_completion(PURB purb
, PVOID context
)
3116 USE_NON_PENDING_IRQL
;
3118 old_irql
= KeGetCurrentIrql();
3119 if (old_irql
> DISPATCH_LEVEL
)
3122 if (old_irql
< DISPATCH_LEVEL
)
3123 KeRaiseIrql(DISPATCH_LEVEL
, &old_irql
);
3133 lock_dev(pdev
, TRUE
);
3135 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
3137 unlock_dev(pdev
, TRUE
);
3138 goto LBL_CLIENT_PROCESS
;
3140 if (usb_error(purb
->status
))
3142 pdev
->error_count
++;
3145 if (purb
->pendp
== &pdev
->default_endp
)
3147 if (usb_halted(purb
->status
))
3149 pdev
->time_out_count
++;
3150 if (pdev
->time_out_count
> 3)
3152 dev_set_state(pdev
, USB_DEV_STATE_ZOMB
);
3153 uhci_dbg_print(DBGLVL_MAXIMUM
,
3154 ("uhci_generic_urb_completion(): contiguous error 3 times, dev 0x%x is deactivated\n",
3159 pdev
->time_out_count
= 0;
3162 unlock_dev(pdev
, TRUE
);
3165 if (purb
->completion
)
3166 purb
->completion(purb
, context
);
3168 if (old_irql
< DISPATCH_LEVEL
)
3169 KeLowerIrql(old_irql
);
3176 uhci_rh_submit_urb(PUSB_DEV pdev
, PURB purb
)
3178 PUSB_DEV_MANAGER dev_mgr
;
3180 PUSB_CTRL_SETUP_PACKET psetup
;
3184 #ifndef INCLUDE_EHCI
3185 PHUB_EXTENSION hub_ext
;
3187 PHUB2_EXTENSION hub_ext
;
3189 PUSB_PORT_STATUS ps
, psret
;
3191 USE_NON_PENDING_IRQL
;
3193 if (pdev
== NULL
|| purb
== NULL
)
3194 return STATUS_INVALID_PARAMETER
;
3196 dev_mgr
= dev_mgr_from_dev(pdev
);
3198 KeAcquireSpinLock(&dev_mgr
->timer_svc_list_lock
, &old_irql
);
3199 lock_dev(pdev
, FALSE
);
3200 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
3202 unlock_dev(pdev
, FALSE
);
3203 KeReleaseSpinLock(&dev_mgr
->timer_svc_list_lock
, old_irql
);
3204 return STATUS_DEVICE_DOES_NOT_EXIST
;
3207 uhci
= uhci_from_hcd(pdev
->hcd
);
3208 psetup
= (PUSB_CTRL_SETUP_PACKET
) purb
->setup_packet
;
3210 #ifndef INCLUDE_EHCI
3211 hub_ext
= ((PHUB_EXTENSION
) pdev
->dev_ext
);
3213 hub_ext
= ((PHUB2_EXTENSION
) pdev
->dev_ext
);
3216 switch (endp_type(purb
->pendp
))
3218 case USB_ENDPOINT_XFER_CONTROL
:
3220 if (psetup
->bmRequestType
== 0xa3 && psetup
->bRequest
== USB_REQ_GET_STATUS
)
3223 if (psetup
->wIndex
== 0 || psetup
->wIndex
> 2 || psetup
->wLength
< 4)
3225 purb
->status
= STATUS_INVALID_PARAMETER
;
3228 if (psetup
->wIndex
== 1)
3230 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC1
));
3231 ps
= &hub_ext
->rh_port1_status
;
3235 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC2
));
3236 ps
= &hub_ext
->rh_port2_status
;
3239 psret
= (PUSB_PORT_STATUS
) purb
->data_buffer
;
3240 ps
->wPortStatus
= 0;
3242 if (status
& USBPORTSC_CCS
)
3244 ps
->wPortStatus
|= USB_PORT_STAT_CONNECTION
;
3246 if (status
& USBPORTSC_PE
)
3248 ps
->wPortStatus
|= USB_PORT_STAT_ENABLE
;
3250 if (status
& USBPORTSC_PR
)
3252 ps
->wPortStatus
|= USB_PORT_STAT_RESET
;
3254 if (status
& USBPORTSC_SUSP
)
3256 ps
->wPortStatus
|= USB_PORT_STAT_SUSPEND
;
3258 if (status
& USBPORTSC_LSDA
)
3260 ps
->wPortStatus
|= USB_PORT_STAT_LOW_SPEED
;
3264 ps
->wPortStatus
|= USB_PORT_STAT_POWER
;
3266 //now set change field
3267 if (status
& USBPORTSC_CSC
)
3269 ps
->wPortChange
|= USB_PORT_STAT_C_CONNECTION
;
3271 if (status
& USBPORTSC_PEC
)
3273 ps
->wPortChange
|= USB_PORT_STAT_C_ENABLE
;
3276 //don't touch other fields, will be filled by
3279 usb_dbg_print(DBGLVL_MAXIMUM
,
3280 ("uhci_rh_submit_urb(): get port status, wPortStatus=0x%x, wPortChange=0x%x, address=0x%x\n",
3281 ps
->wPortStatus
, ps
->wPortChange
, ps
));
3283 psret
->wPortChange
= ps
->wPortChange
;
3284 psret
->wPortStatus
= ps
->wPortStatus
;
3286 purb
->status
= STATUS_SUCCESS
;
3290 else if (psetup
->bmRequestType
== 0x23 && psetup
->bRequest
== USB_REQ_CLEAR_FEATURE
)
3292 //clear-port-feature
3293 if (psetup
->wIndex
== 0 || psetup
->wIndex
> 2)
3295 purb
->status
= STATUS_INVALID_PARAMETER
;
3298 if (psetup
->wIndex
== 1)
3301 ps
= &hub_ext
->rh_port1_status
;
3306 ps
= &hub_ext
->rh_port2_status
;
3309 purb
->status
= STATUS_SUCCESS
;
3310 switch (psetup
->wValue
)
3312 case USB_PORT_FEAT_C_CONNECTION
:
3314 ps
->wPortChange
&= ~USB_PORT_STAT_C_CONNECTION
;
3315 SET_RH_PORTSTAT(i
, USBPORTSC_CSC
);
3316 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3317 usb_dbg_print(DBGLVL_MAXIMUM
,
3318 ("uhci_rh_submit_urb(): clear csc, port%d=0x%x\n", psetup
->wIndex
,
3322 case USB_PORT_FEAT_C_ENABLE
:
3324 ps
->wPortChange
&= ~USB_PORT_STAT_C_ENABLE
;
3325 SET_RH_PORTSTAT(i
, USBPORTSC_PEC
);
3326 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3327 usb_dbg_print(DBGLVL_MAXIMUM
,
3328 ("uhci_rh_submit_urb(): clear pec, port%d=0x%x\n", psetup
->wIndex
,
3332 case USB_PORT_FEAT_C_RESET
:
3334 ps
->wPortChange
&= ~USB_PORT_STAT_C_RESET
;
3335 //the reset signal is down in rh_timer_svc_reset_port_completion
3336 //so enable the port here
3337 status
= READ_PORT_USHORT((PUSHORT
)(uhci
->port_base
+ i
));
3338 usb_dbg_print(DBGLVL_MAXIMUM
,
3339 ("uhci_rh_submit_urb(): clear pr, enable pe, port%d=0x%x\n",
3340 psetup
->wIndex
, status
));
3343 case USB_PORT_FEAT_ENABLE
:
3345 ps
->wPortStatus
&= ~USB_PORT_STAT_ENABLE
;
3346 CLR_RH_PORTSTAT(i
, USBPORTSC_PE
);
3347 status
= READ_PORT_USHORT((PUSHORT
)(uhci
->port_base
+ i
));
3348 usb_dbg_print(DBGLVL_MAXIMUM
,
3349 ("uhci_rh_submit_urb(): clear pe, port%d=0x%x\n", psetup
->wIndex
,
3354 purb
->status
= STATUS_UNSUCCESSFUL
;
3358 else if (psetup
->bmRequestType
== 0xd3 && psetup
->bRequest
== HUB_REQ_GET_STATE
)
3361 if (psetup
->wIndex
== 0 || psetup
->wIndex
> 2 || psetup
->wLength
== 0)
3363 purb
->status
= STATUS_INVALID_PARAMETER
;
3367 if (psetup
->wIndex
== 1)
3375 port_status
= READ_PORT_USHORT((PUSHORT
)(uhci
->port_base
+ i
));
3376 purb
->data_buffer
[0] = (port_status
& USBPORTSC_LS
);
3378 // reverse the order
3379 purb
->data_buffer
[0] ^= 0x3;
3380 purb
->status
= STATUS_SUCCESS
;
3383 else if (psetup
->bmRequestType
== 0x23 && psetup
->bRequest
== USB_REQ_SET_FEATURE
)
3386 if (psetup
->wValue
!= USB_PORT_FEAT_RESET
)
3388 purb
->status
= STATUS_INVALID_PARAMETER
;
3389 uhci_dbg_print(DBGLVL_MAXIMUM
,
3390 ("uhci_rh_submit_urb(): set feature with wValue=0x%x\n", psetup
->wValue
));
3393 if (psetup
->wIndex
== 1)
3402 ptimer
= alloc_timer_svc(&dev_mgr
->timer_svc_pool
, 1);
3405 purb
->status
= STATUS_NO_MEMORY
;
3409 ptimer
->threshold
= 0; // within [ 50ms, 60ms ], one tick is 10 ms
3410 ptimer
->context
= (ULONG
) purb
;
3411 ptimer
->pdev
= pdev
;
3412 ptimer
->func
= rh_timer_svc_reset_port_completion
;
3415 pdev
->ref_count
+= 2; //one for timer and one for urb
3417 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3418 usb_dbg_print(DBGLVL_MAXIMUM
,
3419 ("uhci_rh_submit_urb(): reset port, port%d=0x%x\n", psetup
->wIndex
, status
));
3420 InsertTailList(&dev_mgr
->timer_svc_list
, &ptimer
->timer_svc_link
);
3421 purb
->status
= STATUS_PENDING
;
3425 purb
->status
= STATUS_INVALID_PARAMETER
;
3429 case USB_ENDPOINT_XFER_INT
:
3431 ptimer
= alloc_timer_svc(&dev_mgr
->timer_svc_pool
, 1);
3434 purb
->status
= STATUS_NO_MEMORY
;
3438 ptimer
->threshold
= RH_INTERVAL
;
3439 ptimer
->context
= (ULONG
) purb
;
3440 ptimer
->pdev
= pdev
;
3441 ptimer
->func
= rh_timer_svc_int_completion
;
3444 InsertTailList(&dev_mgr
->timer_svc_list
, &ptimer
->timer_svc_link
);
3446 usb_dbg_print(DBGLVL_ULTRA
,
3447 ("uhci_rh_submit_urb(): current rh's ref_count=0x%x\n", pdev
->ref_count
));
3448 pdev
->ref_count
+= 2; //one for timer and one for urb
3450 purb
->status
= STATUS_PENDING
;
3453 case USB_ENDPOINT_XFER_BULK
:
3454 case USB_ENDPOINT_XFER_ISOC
:
3457 purb
->status
= STATUS_INVALID_PARAMETER
;
3461 unlock_dev(pdev
, FALSE
);
3462 KeReleaseSpinLock(&dev_mgr
->timer_svc_list_lock
, old_irql
);
3463 return purb
->status
;
3466 //must have rh dev_lock acquired
3468 uhci_rh_reset_port(PHCD hcd
, UCHAR port_idx
)
3474 if (port_idx
!= 1 && port_idx
!= 2)
3489 uhci
= uhci_from_hcd(hcd
);
3490 //assert the reset signal,(implicitly disable the port)
3491 SET_RH_PORTSTAT(i
, USBPORTSC_PR
);
3492 usb_wait_ms_dpc(50);
3493 //clear the reset signal, delay port enable till clearing port feature
3494 CLR_RH_PORTSTAT(i
, USBPORTSC_PR
);
3495 usb_wait_us_dpc(10);
3496 SET_RH_PORTSTAT(i
, USBPORTSC_PE
);
3497 //recovery time 10ms
3498 usb_wait_ms_dpc(10);
3499 SET_RH_PORTSTAT(i
, 0x0a);
3501 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3502 usb_dbg_print(DBGLVL_MAXIMUM
, ("uhci_rh_reset_port(): status after written=0x%x\n", status
));
3508 uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject
, IN PIRP irp
)
3510 PDEVICE_EXTENSION pdev_ext
;
3511 PUSB_DEV_MANAGER dev_mgr
;
3514 pdev_ext
= DeviceObject
->DeviceExtension
;
3515 uhci
= pdev_ext
->uhci
;
3517 dev_mgr
= uhci
->hcd_interf
.hcd_get_dev_mgr(&uhci
->hcd_interf
);
3518 return dev_mgr_dispatch(dev_mgr
, irp
);
3522 uhci_unload(IN PDRIVER_OBJECT DriverObject
)
3524 PDEVICE_OBJECT pdev
;
3525 PDEVICE_EXTENSION pdev_ext
;
3526 PUSB_DEV_MANAGER dev_mgr
;
3528 pdev
= DriverObject
->DeviceObject
;
3533 pdev_ext
= pdev
->DeviceExtension
;
3534 if (pdev_ext
== NULL
)
3537 dev_mgr
= &g_dev_mgr
;
3538 if (dev_mgr
== NULL
)
3541 // set the termination flag
3543 dev_mgr
->term_flag
= TRUE
;
3546 // wake up the thread if it is
3548 KeSetEvent(&dev_mgr
->wake_up_event
, 0, FALSE
);
3549 KeWaitForSingleObject(dev_mgr
->pthread
, Executive
, KernelMode
, TRUE
, NULL
);
3550 ObDereferenceObject(dev_mgr
->pthread
);
3551 dev_mgr
->pthread
= NULL
;
3552 // for( i = 0; i < dev_mgr->hcd_count; i++ )
3553 // dev_mgr->hcd_array[ i ]->hcd_release( dev_mgr->hcd_array[ i ]);
3554 dev_mgr_release_hcd(dev_mgr
);
3559 //the following are for hcd interface methods
3561 uhci_set_dev_mgr(struct _HCD
* hcd
, PUSB_DEV_MANAGER dev_mgr
)
3563 hcd
->dev_mgr
= dev_mgr
;
3567 uhci_get_dev_mgr(struct _HCD
*hcd
)
3569 return hcd
->dev_mgr
;
3573 uhci_get_type(struct _HCD
* hcd
)
3575 return (hcd
->flags
& HCD_TYPE_MASK
);
3579 uhci_set_id(struct _HCD
* hcd
, UCHAR id
)
3581 hcd
->flags
&= ~HCD_ID_MASK
;
3582 hcd
->flags
|= (HCD_ID_MASK
& id
);
3586 uhci_get_id(struct _HCD
*hcd
)
3588 return (UCHAR
) (hcd
->flags
& HCD_ID_MASK
);
3593 uhci_alloc_addr(struct _HCD
* hcd
)
3599 for(i
= 1; i
< MAX_DEVS
; i
++)
3601 if (hcd
->dev_addr_map
[i
>> 3] & (1 << (i
& 7)))
3614 hcd
->dev_addr_map
[i
>> 3] |= (1 << (i
& 7));
3620 uhci_free_addr(struct _HCD
* hcd
, UCHAR addr
)
3628 hcd
->dev_addr_map
[addr
>> 3] &= ~(1 << (addr
& 7));
3634 uhci_submit_urb2(struct _HCD
* hcd
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
3636 return uhci_submit_urb(uhci_from_hcd(hcd
), pdev
, pendp
, purb
);
3640 uhci_get_root_hub(struct _HCD
* hcd
)
3642 return uhci_from_hcd(hcd
)->root_hub
;
3646 uhci_set_root_hub(struct _HCD
* hcd
, PUSB_DEV root_hub
)
3648 if (hcd
== NULL
|| root_hub
== NULL
)
3650 uhci_from_hcd(hcd
)->root_hub
= root_hub
;
3655 uhci_remove_device2(struct _HCD
* hcd
, PUSB_DEV pdev
)
3657 if (hcd
== NULL
|| pdev
== NULL
)
3660 return uhci_remove_device(uhci_from_hcd(hcd
), pdev
);
3664 uhci_hcd_release(struct _HCD
* hcd
)
3667 PDEVICE_EXTENSION pdev_ext
;
3673 uhci
= uhci_from_hcd(hcd
);
3674 pdev_ext
= uhci
->pdev_ext
;
3676 return uhci_release(pdev_ext
->pdev_obj
);
3680 uhci_cancel_urb2(struct _HCD
* hcd
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
3684 return STATUS_INVALID_PARAMETER
;
3686 uhci
= uhci_from_hcd(hcd
);
3687 return uhci_cancel_urb(uhci
, pdev
, pendp
, purb
);
3691 uhci_rh_get_dev_change(PHCD hcd
, PBYTE buf
)
3696 if (hcd
== NULL
|| buf
== NULL
)
3699 uhci
= uhci_from_hcd(hcd
);
3700 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC1
));
3701 usb_dbg_print(DBGLVL_ULTRA
, ("uhci_rh_get_dev_change(): rh port1 status=0x%x\n", status
));
3703 if ((status
& USBPORTSC_PEC
) || (status
& USBPORTSC_CSC
))
3708 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC2
));
3709 usb_dbg_print(DBGLVL_ULTRA
, ("uhci_rh_get_dev_change(): rh port2 status=0x%x\n", status
));
3711 if ((status
& USBPORTSC_PEC
) || (status
& USBPORTSC_CSC
))
3719 uhci_dispatch(PHCD hcd
, LONG disp_code
, PVOID param
) // locking depends on type of code
3726 case HCD_DISP_READ_PORT_COUNT
:
3729 return STATUS_INVALID_PARAMETER
;
3730 *((PUCHAR
) param
) = 2;
3731 return STATUS_SUCCESS
;
3733 case HCD_DISP_READ_RH_DEV_CHANGE
:
3735 if (uhci_rh_get_dev_change(hcd
, param
) == FALSE
)
3736 return STATUS_INVALID_PARAMETER
;
3737 return STATUS_SUCCESS
;
3741 return STATUS_NOT_IMPLEMENTED
;
3745 uhci_init_hcd_interface(PUHCI_DEV uhci
)
3747 uhci
->hcd_interf
.hcd_set_dev_mgr
= uhci_set_dev_mgr
;
3748 uhci
->hcd_interf
.hcd_get_dev_mgr
= uhci_get_dev_mgr
;
3749 uhci
->hcd_interf
.hcd_get_type
= uhci_get_type
;
3750 uhci
->hcd_interf
.hcd_set_id
= uhci_set_id
;
3751 uhci
->hcd_interf
.hcd_get_id
= uhci_get_id
;
3752 uhci
->hcd_interf
.hcd_alloc_addr
= uhci_alloc_addr
;
3753 uhci
->hcd_interf
.hcd_free_addr
= uhci_free_addr
;
3754 uhci
->hcd_interf
.hcd_submit_urb
= uhci_submit_urb2
;
3755 uhci
->hcd_interf
.hcd_generic_urb_completion
= uhci_generic_urb_completion
;
3756 uhci
->hcd_interf
.hcd_get_root_hub
= uhci_get_root_hub
;
3757 uhci
->hcd_interf
.hcd_set_root_hub
= uhci_set_root_hub
;
3758 uhci
->hcd_interf
.hcd_remove_device
= uhci_remove_device2
;
3759 uhci
->hcd_interf
.hcd_rh_reset_port
= uhci_rh_reset_port
;
3760 uhci
->hcd_interf
.hcd_release
= uhci_hcd_release
;
3761 uhci
->hcd_interf
.hcd_cancel_urb
= uhci_cancel_urb2
;
3762 uhci
->hcd_interf
.hcd_start
= uhci_start
;
3763 uhci
->hcd_interf
.hcd_dispatch
= uhci_dispatch
;
3765 uhci
->hcd_interf
.flags
= HCD_TYPE_UHCI
; //hcd types | hcd id
3769 generic_dispatch_irp(IN PDEVICE_OBJECT dev_obj
, IN PIRP irp
)
3771 PDEVEXT_HEADER dev_ext
;
3773 dev_ext
= (PDEVEXT_HEADER
) dev_obj
->DeviceExtension
;
3775 if (dev_ext
&& dev_ext
->dispatch
)
3776 return dev_ext
->dispatch(dev_obj
, irp
);
3778 irp
->IoStatus
.Information
= 0;
3780 EXIT_DISPATCH(STATUS_UNSUCCESSFUL
, irp
);
3785 generic_start_io(IN PDEVICE_OBJECT dev_obj
, IN PIRP irp
)
3787 PDEVEXT_HEADER dev_ext
;
3791 IoAcquireCancelSpinLock(&old_irql
);
3792 if (irp
!= dev_obj
->CurrentIrp
|| irp
->Cancel
)
3794 IoReleaseCancelSpinLock(old_irql
);
3799 (void)IoSetCancelRoutine(irp
, NULL
);
3800 IoReleaseCancelSpinLock(old_irql
);
3803 dev_ext
= (PDEVEXT_HEADER
) dev_obj
->DeviceExtension
;
3805 if (dev_ext
&& dev_ext
->start_io
)
3807 dev_ext
->start_io(dev_obj
, irp
);
3811 irp
->IoStatus
.Information
= 0;
3812 irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3814 IoStartNextPacket(dev_obj
, FALSE
);
3815 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
3820 DriverEntry(IN PDRIVER_OBJECT DriverObject
, IN PUNICODE_STRING RegistryPath
)
3822 NTSTATUS ntStatus
= STATUS_SUCCESS
;
3825 // should be done before any debug output is done.
3826 // read our debug verbosity level from the registry
3827 //NetacOD_GetRegistryDword( NetacOD_REGISTRY_PARAMETERS_PATH, //absolute registry path
3828 // L"DebugLevel", // REG_DWORD ValueName
3829 // &gDebugLevel ); // Value receiver
3831 // debug_level = DBGLVL_MAXIMUM;
3834 uhci_dbg_print_cond(DBGLVL_MINIMUM
, DEBUG_UHCI
,
3835 ("Entering DriverEntry(), RegistryPath=\n %ws\n", RegistryPath
->Buffer
));
3837 // Remember our driver object, for when we create our child PDO
3838 usb_driver_obj
= DriverObject
;
3841 // Create dispatch points for create, close, unload
3842 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = generic_dispatch_irp
;
3843 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = generic_dispatch_irp
;
3844 DriverObject
->DriverUnload
= uhci_unload
;
3846 // User mode DeviceIoControl() calls will be routed here
3847 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = generic_dispatch_irp
;
3848 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = generic_dispatch_irp
;
3850 // User mode ReadFile()/WriteFile() calls will be routed here
3851 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = generic_dispatch_irp
;
3852 DriverObject
->MajorFunction
[IRP_MJ_READ
] = generic_dispatch_irp
;
3854 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = generic_dispatch_irp
;
3855 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = generic_dispatch_irp
;
3856 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = generic_dispatch_irp
;
3858 DriverObject
->DriverStartIo
= generic_start_io
;
3859 // routines for handling system PNP and power management requests
3860 //DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = generic_dispatch_irp;
3862 // The Functional Device Object (FDO) will not be created for PNP devices until
3863 // this routine is called upon device plug-in.
3864 RtlZeroMemory(&g_dev_mgr
, sizeof(USB_DEV_MANAGER
));
3865 g_dev_mgr
.usb_driver_obj
= DriverObject
;
3868 ehci_probe(DriverObject
, RegistryPath
, &g_dev_mgr
);
3871 uhci_probe(DriverObject
, RegistryPath
, &g_dev_mgr
);
3873 if (dev_mgr_strobe(&g_dev_mgr
) == FALSE
)
3876 dev_mgr_release_hcd(&g_dev_mgr
);
3877 return STATUS_UNSUCCESSFUL
;
3880 dev_mgr_start_hcd(&g_dev_mgr
);
3882 /* Wait till all drivers are initialized */
3883 ntStatus
= KeWaitForSingleObject(&g_dev_mgr
.drivers_inited
, Executive
, KernelMode
, TRUE
, NULL
);
3885 uhci_dbg_print_cond(DBGLVL_DEFAULT
, DEBUG_UHCI
, ("DriverEntry(): exiting... (%x)\n", ntStatus
));
3886 return STATUS_SUCCESS
;
3889 //note: the initialization will be in the following order
3894 // to kill dev_mgr_thread:
3895 // dev_mgr->term_flag = TRUE;
3896 // KeSetEvent( &dev_mgr->wake_up_event );
3897 // this piece of code must run at passive-level