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 )
70 #define release_adapter( padapTER ) \
75 #define release_adapter( padapTER ) (void)(padapTER)
78 #define get_int_idx( _urb, _idx ) \
81 interVAL = ( UCHAR )( ( _urb )->pipe >> 24 );\
82 for( _idx = 1; _idx < 9; _idx++ )\
91 #define uhci_insert_urb_to_schedule( uHCI, pURB, rET ) \
93 SYNC_PARAM sync_param;\
94 sync_param.uhci = uHCI;\
95 sync_param.context = pURB;\
97 rET = KeSynchronizeExecution( uHCI->pdev_ext->uhci_int, uhci_sync_insert_urb_schedule, &sync_param );\
106 } SYNC_PARAM
, *PSYNC_PARAM
;
109 uhci_alloc(PDRIVER_OBJECT drvr_obj
, PUNICODE_STRING reg_path
, ULONG bus_addr
, PUSB_DEV_MANAGER dev_mgr
);
111 BOOLEAN
uhci_init_schedule(PUHCI_DEV uhci
, PADAPTER_OBJECT padapter
);
113 BOOLEAN
uhci_release(PDEVICE_OBJECT pdev
);
115 static VOID
uhci_stop(PUHCI_DEV uhci
);
117 BOOLEAN
uhci_destroy_schedule(PUHCI_DEV uhci
);
119 BOOLEAN NTAPI
uhci_sync_insert_urb_schedule(PVOID context
);
121 VOID
uhci_init_hcd_interface(PUHCI_DEV uhci
);
123 NTSTATUS
uhci_rh_submit_urb(PUSB_DEV rh
, PURB purb
);
125 NTSTATUS
uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject
, IN PIRP irp
);
127 extern VOID
rh_timer_svc_reset_port_completion(PUSB_DEV dev
, PVOID context
);
129 extern VOID
rh_timer_svc_int_completion(PUSB_DEV dev
, PVOID context
);
131 ULONG debug_level
= DBGLVL_MINIMUM
;//DBGLVL_MAXIMUM;
132 PDRIVER_OBJECT usb_driver_obj
= NULL
;
133 extern USB_DEV_MANAGER g_dev_mgr
;
135 //pending endpoint pool funcs
137 uhci_wait_ms(PUHCI_DEV uhci
, LONG ms
)
143 lms
.QuadPart
= -10 * ms
;
144 KeSetTimer(&uhci
->reset_timer
, lms
, NULL
);
146 KeWaitForSingleObject(&uhci
->reset_timer
, Executive
, KernelMode
, FALSE
, NULL
);
152 init_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool
)
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
);
165 for(i
= 0; i
< MAX_TIMER_SVCS
; i
++)
167 free_pending_endp(pool
, &pool
->pending_endp_array
[i
]);
175 free_pending_endp(PUHCI_PENDING_ENDP_POOL pool
, PUHCI_PENDING_ENDP pending_endp
)
177 if (pool
== NULL
|| pending_endp
== NULL
)
182 RtlZeroMemory(pending_endp
, sizeof(UHCI_PENDING_ENDP
));
183 InsertTailList(&pool
->free_que
, &pending_endp
->endp_link
);
190 alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool
, LONG count
)
192 PUHCI_PENDING_ENDP new_endp
;
193 if (pool
== NULL
|| count
!= 1)
196 if (pool
->free_count
<= 0)
199 new_endp
= (PUHCI_PENDING_ENDP
) RemoveHeadList(&pool
->free_que
);
205 destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool
)
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
;
220 //end of pending endpoint pool funcs
223 uhci_fill_td(PUHCI_TD td
, ULONG status
, ULONG info
, ULONG buffer
)
231 uhci_insert_td_fl(PUHCI_TD prev_td
, PUHCI_TD ptd
)
233 PLIST_ENTRY temp_entry
;
235 if (prev_td
== NULL
|| ptd
== NULL
)
238 temp_entry
= &prev_td
->ptde
->hori_link
;
240 ptd
->link
= (struct_ptr(temp_entry
, TD_EXTENSION
, hori_link
))->ptd
->phy_addr
;
241 prev_td
->link
= ptd
->phy_addr
;
243 InsertHeadList(&prev_td
->ptde
->hori_link
, &ptd
->ptde
->hori_link
);
248 uhci_remove_td_fl(PUHCI_TD ptd
)
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
;
259 RemoveEntryList(&ptd
->ptde
->hori_link
);
265 uhci_insert_qh_fl(PVOID prev_item
, PUHCI_QH pqh
)
267 //only horizontal link allowed
270 PLIST_ENTRY temp_entry
;
272 if (prev_item
== NULL
|| pqh
== NULL
)
275 if ((((PUHCI_TD
) prev_item
)->ptde
->flags
& UHCI_ITEM_FLAG_TYPE
) == UHCI_ITEM_FLAG_QH
)
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
;
282 InsertHeadList(&pprev_qh
->pqhe
->hori_link
, &pqh
->pqhe
->hori_link
);
286 pprev_td
= ((PUHCI_TD
) prev_item
);
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
;
292 InsertHeadList(&pprev_td
->ptde
->hori_link
, &pqh
->pqhe
->hori_link
);
299 uhci_remove_qh_fl(PUHCI_QH pqh
)
308 prev_item
= (struct_ptr(pqh
->pqhe
->hori_link
.Blink
, TD_EXTENSION
, hori_link
))->ptd
;
310 if ((((PUHCI_TD
) prev_item
)->ptde
->flags
& UHCI_ITEM_FLAG_TYPE
) == UHCI_ITEM_FLAG_QH
)
312 pprevqh
= (PUHCI_QH
) prev_item
;
313 pprevqh
->link
= pqh
->link
;
317 pprevtd
= ((PUHCI_TD
) prev_item
);
318 pprevtd
->link
= pqh
->link
;
321 RemoveEntryList(&pqh
->pqhe
->hori_link
);
323 pqh
->link
= UHCI_PTR_TERM
;
324 pqh
->pqhe
->hori_link
.Flink
= pqh
->pqhe
->hori_link
.Blink
= NULL
;
330 uhci_init_frame_list(PUHCI_DEV uhci
, PADAPTER_OBJECT padapter
)
333 if (uhci
== NULL
|| padapter
== NULL
)
336 //note: frame_list_lock will be connected to interrupt
337 KeInitializeSpinLock(&uhci
->frame_list_lock
);
339 uhci
->io_buf
= HalAllocateCommonBuffer(padapter
, 4096, &uhci
->io_buf_logic_addr
, FALSE
);
341 if (uhci
->io_buf
== NULL
)
345 HalAllocateCommonBuffer(padapter
,
346 sizeof(ULONG
) * UHCI_MAX_FRAMES
, &uhci
->frame_list_logic_addr
, FALSE
);
348 if (uhci
->frame_list
== NULL
)
351 RtlZeroMemory(uhci
->frame_list
, sizeof(ULONG
) * UHCI_MAX_FRAMES
);
353 uhci
->frame_list_cpu
= usb_alloc_mem(NonPagedPool
, sizeof(FRAME_LIST_CPU_ENTRY
) * UHCI_MAX_FRAMES
);
355 if (uhci
->frame_list_cpu
== NULL
)
358 for(i
= 0; i
< UHCI_MAX_FRAMES
; i
++)
359 InitializeListHead(&uhci
->frame_list_cpu
[i
].td_link
);
361 uhci
->frame_bw
= usb_alloc_mem(NonPagedPool
, sizeof(LONG
) * UHCI_MAX_FRAMES
);
363 if (uhci
->frame_bw
== NULL
)
366 for(i
= 0; i
< UHCI_MAX_FRAMES
; i
++)
368 uhci
->frame_bw
[i
] = FRAME_TIME_MAX_USECS_ALLOC
;
377 uhci_destroy_frame_list(PUHCI_DEV uhci
)
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
);
387 uhci
->frame_list
= NULL
;
388 uhci
->frame_list_logic_addr
.LowPart
= 0;
389 uhci
->frame_list_logic_addr
.HighPart
= 0;
391 if (uhci
->frame_list_cpu
)
392 usb_free_mem(uhci
->frame_list_cpu
);
394 uhci
->frame_list_cpu
= NULL
;
397 usb_free_mem(uhci
->frame_bw
);
399 uhci
->frame_bw
= NULL
;
405 uhci_create_device(PDRIVER_OBJECT drvr_obj
, PUSB_DEV_MANAGER dev_mgr
)
409 PDEVICE_EXTENSION pdev_ext
;
411 UNICODE_STRING dev_name
;
412 UNICODE_STRING symb_name
;
414 STRING string
, another_string
;
415 CHAR str_dev_name
[64], str_symb_name
[64];
418 if (drvr_obj
== NULL
)
421 ASSERT(dev_mgr
!= NULL
);
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
);
427 RtlInitString(&string
, str_dev_name
);
428 RtlAnsiStringToUnicodeString(&dev_name
, &string
, TRUE
);
431 status
= IoCreateDevice(drvr_obj
,
432 sizeof(DEVICE_EXTENSION
) + sizeof(UHCI_DEV
),
433 &dev_name
, FILE_UHCI_DEV_TYPE
, 0, FALSE
, &pdev
);
435 if (status
!= STATUS_SUCCESS
|| pdev
== NULL
)
437 RtlFreeUnicodeString(&dev_name
);
441 pdev_ext
= pdev
->DeviceExtension
;
442 RtlZeroMemory(pdev_ext
, sizeof(DEVICE_EXTENSION
) + sizeof(UHCI_DEV
));
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
;
449 pdev_ext
->pdev_obj
= pdev
;
450 pdev_ext
->pdrvr_obj
= drvr_obj
;
452 pdev_ext
->uhci
= (PUHCI_DEV
) & (pdev_ext
[1]);
454 RtlInitString(&another_string
, str_symb_name
);
455 RtlAnsiStringToUnicodeString(&symb_name
, &another_string
, TRUE
);
457 IoCreateSymbolicLink(&symb_name
, &dev_name
);
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
));
463 RtlFreeUnicodeString(&dev_name
);
464 RtlFreeUnicodeString(&symb_name
);
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
);
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
);
476 uhci_delete_device(PDEVICE_OBJECT pdev
)
479 UNICODE_STRING symb_name
;
480 PDEVICE_EXTENSION pdev_ext
;
481 CHAR str_symb_name
[64];
487 pdev_ext
= pdev
->DeviceExtension
;
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
);
496 if (pdev_ext
->res_list
)
497 ExFreePool(pdev_ext
->res_list
); // not allocated by usb_alloc_mem
499 IoDeleteDevice(pdev
);
500 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_delete_device(): device deleted\n"));
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.
508 uhci_isr(PKINTERRUPT interrupt
, PVOID context
)
512 PLIST_ENTRY pthis
, pnext
;
515 UNREFERENCED_PARAMETER(interrupt
);
516 UNREFERENCED_PARAMETER(context
);
518 uhci_dbg_print(DBGLVL_ULTRA
, ("uhci_isr(): context=0x%x\n", context
));
521 * Read the interrupt status, and write it back to clear the
524 uhci
= (PUHCI_DEV
) context
;
528 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBSTS
));
529 if (!status
) /* shared interrupt, not mine */
534 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_isr(): current uhci status=0x%x\n", status
));
538 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_isr(): congratulations, no error occurs\n"));
542 WRITE_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBSTS
), status
);
544 if (status
& ~(USBSTS_USBINT
| USBSTS_ERROR
| USBSTS_RD
))
546 if (status
& USBSTS_HSE
)
548 DbgPrint("uhci_isr(): host system error, PCI problems?\n");
551 if (status
& USBSTS_HCPE
)
553 DbgPrint("uhci_isr(): host controller process error. something bad happened\n");
557 if ((status
& USBSTS_HCH
)) //&& !uhci->is_suspended
559 DbgPrint("uhci_isr(): host controller halted. very bad\n");
560 /* FIXME: Reset the controller, fix the offending TD */
564 // don't no how to handle it yet
565 //if (status & USBSTS_RD)
570 //let's remove those force-cancel urbs from the schedule first
571 ListFirst(&uhci
->urb_list
, pthis
);
575 if (purb
->flags
& URB_FLAG_FORCE_CANCEL
)
577 uhci_remove_urb_from_schedule(uhci
, purb
);
579 ListNext(&uhci
->urb_list
, pthis
, pnext
);
583 //clear the interrupt if the urb is force canceled
584 uhci
->skel_term_td
->status
&= ~TD_CTRL_IOC
;
586 //next we need to find if anything fininshed
587 ListFirst(&uhci
->urb_list
, pthis
);
591 if (purb
->flags
& URB_FLAG_IN_SCHEDULE
)
593 if (uhci_is_xfer_finished(purb
))
594 uhci_remove_urb_from_schedule(uhci
, purb
);
596 ListNext(&uhci
->urb_list
, pthis
, pnext
);
600 KeInsertQueueDpc(&uhci
->pdev_ext
->uhci_dpc
, uhci
, 0);
605 uhci_cal_cpu_freq(PVOID context
)
607 UNREFERENCED_PARAMETER(context
);
614 uhci_probe(PDRIVER_OBJECT drvr_obj
, PUNICODE_STRING reg_path
, PUSB_DEV_MANAGER dev_mgr
)
616 LONG bus
, i
, j
, ret
= 0;
617 PCI_SLOT_NUMBER slot_num
;
618 PPCI_COMMON_CONFIG pci_config
;
620 BYTE buffer
[sizeof(PCI_COMMON_CONFIG
)];
622 PDEVICE_EXTENSION pdev_ext
;
624 slot_num
.u
.AsULONG
= 0;
625 pci_config
= (PPCI_COMMON_CONFIG
) buffer
;
629 //scan the PCI buses to find uhci controller
630 for (bus
= 0; bus
<= PCI_MAX_BRIDGE_NUMBER
; bus
++)
632 for(i
= 0; i
<= PCI_MAX_DEVICES
; i
++)
634 slot_num
.u
.bits
.DeviceNumber
= i
;
635 for(j
= 0; j
<= PCI_MAX_FUNCTION
; j
++)
637 slot_num
.u
.bits
.FunctionNumber
= j
;
639 ret
= HalGetBusData(PCIConfiguration
,
640 bus
, slot_num
.u
.AsULONG
, pci_config
, PCI_COMMON_HDR_LENGTH
);
642 if (ret
== 0) /*no this bus */
645 if (ret
== 2) /*no device on the slot */
648 if (pci_config
->BaseClass
== 0x0c && pci_config
->SubClass
== 0x03 &&
649 pci_config
->ProgIf
== 0x00)
651 // well, we find our usb host controller, create device
652 pdev
= uhci_alloc(drvr_obj
, reg_path
, ((bus
<< 8) | (i
<< 3) | j
), dev_mgr
);
669 DbgPrint("Found %d UHCI controllers\n", count
);
673 pdev_ext
= pdev
->DeviceExtension
;
676 // acquire higher irql to eliminate pre-empty
677 KeSynchronizeExecution(pdev_ext
->uhci_int
, uhci_cal_cpu_freq
, NULL
);
684 uhci_alloc(PDRIVER_OBJECT drvr_obj
, PUNICODE_STRING reg_path
, ULONG bus_addr
, PUSB_DEV_MANAGER dev_mgr
)
686 LONG frd_num
, prd_num
;
688 PDEVICE_EXTENSION pdev_ext
;
689 ULONG vector
, addr_space
;
694 DEVICE_DESCRIPTION dev_desc
;
695 CM_PARTIAL_RESOURCE_DESCRIPTOR
*pprd
;
696 PCI_SLOT_NUMBER slot_num
;
700 pdev
= uhci_create_device(drvr_obj
, dev_mgr
);
703 pdev_ext
= pdev
->DeviceExtension
;
705 pdev_ext
->pci_addr
= bus_addr
;
706 bus
= (bus_addr
>> 8);
708 slot_num
.u
.AsULONG
= 0;
709 slot_num
.u
.bits
.DeviceNumber
= ((bus_addr
& 0xff) >> 3);
710 slot_num
.u
.bits
.FunctionNumber
= (bus_addr
& 0x07);
712 //now create adapter object
713 RtlZeroMemory(&dev_desc
, sizeof(dev_desc
));
715 dev_desc
.Version
= DEVICE_DESCRIPTION_VERSION
;
716 dev_desc
.Master
= TRUE
;
717 dev_desc
.ScatterGather
= TRUE
;
718 dev_desc
.Dma32BitAddresses
= TRUE
;
719 dev_desc
.BusNumber
= bus
;
720 dev_desc
.InterfaceType
= PCIBus
;
721 dev_desc
.MaximumLength
=
722 UHCI_MAX_POOL_TDS
* sizeof(UHCI_TD
) * UHCI_MAX_TD_POOLS
723 + sizeof(UHCI_QH
) * UHCI_MAX_POOL_QHS
+ sizeof(ULONG
) * UHCI_MAX_FRAMES
;
725 pdev_ext
->map_regs
= 2; // UHCI_MAX_TD_POOLS +
726 //+ BYTES_TO_PAGES( ( UHCI_MAX_POOL_TDS * 64 ) * UHCI_MAX_TD_POOLS ) ;
728 pdev_ext
->padapter
= HalGetAdapter(&dev_desc
, &pdev_ext
->map_regs
);
730 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_alloc(): padapter=0x%x\n", pdev_ext
->padapter
));
731 if (pdev_ext
->padapter
== NULL
)
734 uhci_delete_device(pdev
);
738 DbgPrint("uhci_alloc(): reg_path=%p, \n \
739 uhci_alloc(): PCIBus=0x%x, bus=0x%x, bus_addr=0x%x \n \
740 uhci_alloc(): slot_num=0x%x, &res_list=%p \n", reg_path
, (DWORD
) PCIBus
, (DWORD
) bus
,
741 (DWORD
) bus_addr
, (DWORD
) slot_num
.u
.AsULONG
, & pdev_ext
->res_list
);
743 //let's allocate resources for this device
744 DbgPrint("uhci_alloc(): about to assign slot res\n");
745 if ((status
= HalAssignSlotResources(reg_path
, NULL
, //no class name yet
746 drvr_obj
, NULL
, //no support of another uhci controller
748 bus
, slot_num
.u
.AsULONG
, &pdev_ext
->res_list
)) != STATUS_SUCCESS
)
750 DbgPrint("uhci_alloc(): error assign slot res, 0x%x\n", status
);
751 release_adapter(pdev_ext
->padapter
);
752 pdev_ext
->padapter
= NULL
;
753 uhci_delete_device(pdev
);
757 //parse the resource list
758 for(frd_num
= 0; frd_num
< (LONG
) pdev_ext
->res_list
->Count
; frd_num
++)
760 for(prd_num
= 0; prd_num
< (LONG
) pdev_ext
->res_list
->List
[frd_num
].PartialResourceList
.Count
;
763 pprd
= &pdev_ext
->res_list
->List
[frd_num
].PartialResourceList
.PartialDescriptors
[prd_num
];
764 if (pprd
->Type
== CmResourceTypePort
)
766 RtlCopyMemory(&pdev_ext
->res_port
, &pprd
->u
.Port
, sizeof(pprd
->u
.Port
));
768 else if (pprd
->Type
== CmResourceTypeInterrupt
)
770 RtlCopyMemory(&pdev_ext
->res_interrupt
, &pprd
->u
.Interrupt
, sizeof(pprd
->u
.Interrupt
));
775 //for port, translate them to system address
777 if (HalTranslateBusAddress(PCIBus
, bus
, pdev_ext
->res_port
.Start
, &addr_space
, //io space
778 &pdev_ext
->uhci
->uhci_reg_base
) != (BOOLEAN
) TRUE
)
780 DbgPrint("uhci_alloc(): error, can not translate bus address\n");
781 release_adapter(pdev_ext
->padapter
);
782 pdev_ext
->padapter
= NULL
;
783 uhci_delete_device(pdev
);
787 DbgPrint("uhci_alloc(): address space=0x%x\n, reg_base=0x%x\n",
788 addr_space
, pdev_ext
->uhci
->uhci_reg_base
.u
.LowPart
);
792 //port has been mapped to memory space
793 pdev_ext
->uhci
->port_mapped
= TRUE
;
794 pdev_ext
->uhci
->port_base
= (PBYTE
) MmMapIoSpace(pdev_ext
->uhci
->uhci_reg_base
,
795 pdev_ext
->res_port
.Length
, FALSE
);
797 //fatal error can not map the registers
798 if (pdev_ext
->uhci
->port_base
== NULL
)
800 release_adapter(pdev_ext
->padapter
);
801 pdev_ext
->padapter
= NULL
;
802 uhci_delete_device(pdev
);
809 pdev_ext
->uhci
->port_mapped
= FALSE
;
810 pdev_ext
->uhci
->port_base
= (PBYTE
) pdev_ext
->uhci
->uhci_reg_base
.LowPart
;
813 //before we connect the interrupt, we have to init uhci
814 pdev_ext
->uhci
->fsbr_cnt
= 0;
815 pdev_ext
->uhci
->pdev_ext
= pdev_ext
;
817 if (uhci_init_schedule(pdev_ext
->uhci
, pdev_ext
->padapter
) == FALSE
)
819 release_adapter(pdev_ext
->padapter
);
820 pdev_ext
->padapter
= NULL
;
821 uhci_delete_device(pdev
);
825 InitializeListHead(&pdev_ext
->uhci
->urb_list
);
826 KeInitializeSpinLock(&pdev_ext
->uhci
->pending_endp_list_lock
);
827 InitializeListHead(&pdev_ext
->uhci
->pending_endp_list
);
829 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_alloc(): pending_endp_list=0x%x\n",
830 &pdev_ext
->uhci
->pending_endp_list
));
832 init_pending_endp_pool(&pdev_ext
->uhci
->pending_endp_pool
);
833 KeInitializeTimer(&pdev_ext
->uhci
->reset_timer
);
835 vector
= HalGetInterruptVector(PCIBus
,
837 pdev_ext
->res_interrupt
.level
,
838 pdev_ext
->res_interrupt
.vector
,
842 KeInitializeDpc(&pdev_ext
->uhci_dpc
, uhci_dpc_callback
, (PVOID
) pdev_ext
->uhci
);
844 //connect the interrupt
845 DbgPrint("uhci_alloc(): the int=0x%x\n", vector
);
846 if (IoConnectInterrupt(&pdev_ext
->uhci_int
,
849 NULL
, //&pdev_ext->uhci->frame_list_lock,
854 TRUE
, //share the vector
856 FALSE
) //No float save
867 uhci_release(PDEVICE_OBJECT pdev
)
869 PDEVICE_EXTENSION pdev_ext
;
875 pdev_ext
= pdev
->DeviceExtension
;
877 if (pdev_ext
== NULL
)
880 uhci
= pdev_ext
->uhci
;
885 //pdev_ext->uhci->conn_count = 0;
886 pdev_ext
->uhci
->fsbr_cnt
= 0;
888 if (pdev_ext
->uhci_int
)
890 IoDisconnectInterrupt(pdev_ext
->uhci_int
);
891 pdev_ext
->uhci_int
= NULL
;
895 destroy_pending_endp_pool(&pdev_ext
->uhci
->pending_endp_pool
);
896 //pdev_ext->uhci->pending_endp_pool = NULL;
898 uhci_destroy_schedule(uhci
);
900 release_adapter(pdev_ext
->padapter
);
901 pdev_ext
->padapter
= NULL
;
903 uhci_delete_device(pdev
);
909 // send cmds to start the uhc
910 // shamelessly copied from linux's uhci.c (reset_hc(), configure_hc() routines)
917 PCI_SLOT_NUMBER SlotNum
;
920 uhci
= uhci_from_hcd(hcd
);
921 io_addr
= uhci
->port_base
;
924 * Reset the HC - this will force us to get a
925 * new notification of any already connected
926 * ports due to the virtual disconnect that it
929 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_HCRESET
);
930 while (READ_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
)) & USBCMD_HCRESET
)
938 /* Turn on all interrupts */
939 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBINTR
),
940 USBINTR_TIMEOUT
| USBINTR_RESUME
| USBINTR_IOC
| USBINTR_SP
);
942 /* Start at frame 0 */
943 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBFRNUM
), 0);
944 WRITE_PORT_ULONG((PULONG
) (io_addr
+ USBFLBASEADD
), uhci
->frame_list_logic_addr
.LowPart
);
946 /* Run and mark it configured with a 64-byte max packet */
947 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_RS
| USBCMD_CF
| USBCMD_MAXP
);
949 DbgPrint("uhci_start(): current uhci status=0x%x\n", uhci_status(uhci
));
952 pirq
= USBLEGSUP_DEFAULT
;
953 SlotNum
.u
.AsULONG
= 0;
954 SlotNum
.u
.bits
.DeviceNumber
= ((uhci
->pdev_ext
->pci_addr
& 0xff) >> 3);
955 SlotNum
.u
.bits
.FunctionNumber
= (uhci
->pdev_ext
->pci_addr
& 0x07);
957 DbgPrint("uhci_start(): set bus %d data at slot 0x%x\n", (uhci
->pdev_ext
->pci_addr
>> 8),
960 HalSetBusDataByOffset(PCIConfiguration
, (uhci
->pdev_ext
->pci_addr
>> 8), SlotNum
.u
.AsULONG
,
961 &pirq
, USBLEGSUP
, sizeof(pirq
));
967 uhci_stop(PUHCI_DEV uhci
)
969 PBYTE io_addr
= uhci
->port_base
;
970 // turn off all the interrupt
971 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBINTR
), 0);
972 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), 0);
976 uhci_reset(PUHCI_DEV uhci
)
978 PBYTE io_addr
= uhci
->port_base
;
981 /* Global reset for 50ms */
982 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_GRESET
);
983 //uhci_wait_ms( uhci, 50 );
986 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), 0);
987 //uhci_wait_ms( uhci, 10 );
992 uhci_suspend(PUHCI_DEV uhci
)
994 PBYTE io_addr
= uhci
->port_base
;
996 //uhci->is_suspended = 1;
997 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_EGSM
);
1002 uhci_wakeup(PUHCI_DEV uhci
)
1005 unsigned int status
;
1007 io_addr
= uhci
->port_base
;
1009 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), 0);
1011 /* wait for EOP to be sent */
1012 status
= READ_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
));
1013 while (status
& USBCMD_FGR
)
1014 status
= READ_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
));
1016 //uhci->is_suspended = 0;
1018 /* Run and mark it configured with a 64-byte max packet */
1019 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_RS
| USBCMD_CF
| USBCMD_MAXP
);
1024 uhci_init_schedule(PUHCI_DEV uhci
, PADAPTER_OBJECT padapter
)
1028 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_init_schedule(): entering..., uhci=0x%x\n", uhci
));
1029 if (uhci
== NULL
|| padapter
== NULL
)
1032 if (init_td_pool_list(&uhci
->td_pool
, padapter
) == FALSE
)
1036 if (init_qh_pool(&uhci
->qh_pool
, padapter
) == FALSE
)
1041 //since uhci is not started we can freely access all resources.
1042 for(i
= 0; i
< UHCI_MAX_SKELTDS
; i
++)
1044 uhci
->skel_td
[i
] = alloc_td(&uhci
->td_pool
);
1045 uhci_fill_td(uhci
->skel_td
[i
], 0, (UHCI_NULL_DATA_SIZE
<< 21) | (0x7f << 8) | USB_PID_IN
, 0);
1049 uhci
->skel_td
[i
]->link
= uhci
->skel_td
[i
- 1]->phy_addr
;
1053 /*for( i = UHCI_MAX_SKELTDS - 3; i >= 0; i-- )
1055 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1056 &uhci->skel_td[ i ]->ptde->hori_link );
1059 for(i
= 0; i
< UHCI_MAX_SKELQHS
; i
++)
1061 uhci
->skel_qh
[i
] = alloc_qh(&uhci
->qh_pool
);
1064 uhci
->skel_qh
[i
- 1]->link
= uhci
->skel_qh
[i
]->phy_addr
;
1067 uhci
->skel_qh
[i
]->element
= UHCI_PTR_TERM
;
1070 uhci
->skel_int1_td
->link
= uhci
->skel_ls_control_qh
->phy_addr
;
1073 uhci_fill_td(uhci
->skel_term_td
, 0, (UHCI_NULL_DATA_SIZE
<< 21) | (0x7f << 8) | USB_PID_IN
, 0);
1074 uhci
->skel_term_td
->link
= uhci
->skel_term_td
->phy_addr
;
1076 uhci
->skel_term_qh
->link
= UHCI_PTR_TERM
;
1077 uhci
->skel_term_qh
->element
= uhci
->skel_term_td
->phy_addr
;
1079 InsertTailList(&uhci
->skel_term_qh
->pqhe
->vert_link
, &uhci
->skel_term_td
->ptde
->vert_link
);
1081 /*for( i = 0; i < UHCI_MAX_SKELQHS; i++ )
1083 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1084 &uhci->skel_qh[ i ]->pqhe->hori_link );
1087 if (uhci_init_frame_list(uhci
, uhci
->pdev_ext
->padapter
) == FALSE
)
1088 uhci_destroy_frame_list(uhci
);
1090 //well all have been chained, now scatter the int tds to frame-list
1091 //shamelessly pasted from linux's uhci.c :-)
1092 for(i
= 0; i
< UHCI_MAX_FRAMES
; i
++)
1122 /* Only place we don't use the frame list routines */
1123 uhci
->frame_list
[i
] = uhci
->skel_td
[irq
]->phy_addr
;
1129 uhci_destroy_schedule(PUHCI_DEV uhci
)
1133 ret
= uhci_destroy_frame_list(uhci
);
1134 ret
= destroy_qh_pool(&uhci
->qh_pool
);
1135 ret
= destroy_td_pool_list(&uhci
->td_pool
);
1142 uhci_cancel_pending_endp_urb(IN PVOID Parameter
)
1144 PLIST_ENTRY abort_list
;
1147 USE_BASIC_NON_PENDING_IRQL
;
1149 abort_list
= (PLIST_ENTRY
) Parameter
;
1151 if (abort_list
== NULL
)
1154 while (IsListEmpty(abort_list
) == FALSE
)
1156 //these devs are protected by urb's ref-count
1157 purb
= (PURB
) RemoveHeadList(abort_list
);
1159 // purb->status is set when they are added to abort_list
1161 uhci_generic_urb_completion(purb
, purb
->context
);
1163 lock_dev(pdev
, FALSE
);
1165 unlock_dev(pdev
, FALSE
);
1167 usb_free_mem(abort_list
);
1172 uhci_process_pending_endp(PUHCI_DEV uhci
)
1175 LIST_ENTRY temp_list
, abort_list
;
1178 PUSB_ENDPOINT pendp
;
1179 NTSTATUS can_submit
= STATUS_UNSUCCESSFUL
;
1180 PWORK_QUEUE_ITEM pwork_item
;
1181 PLIST_ENTRY cancel_list
;
1187 InitializeListHead(&temp_list
);
1188 InitializeListHead(&abort_list
);
1191 uhci_dbg_print(DBGLVL_MEDIUM
, ("uhci_process_pending_endp(): entering..., uhci=0x%x\n", uhci
));
1193 lock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1194 while (IsListEmpty(&uhci
->pending_endp_list
) == FALSE
)
1197 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_process_pending_endp(): pending_endp_list=0x%x\n",
1198 &uhci
->pending_endp_list
));
1200 pthis
= RemoveHeadList(&uhci
->pending_endp_list
);
1201 pendp
= ((PUHCI_PENDING_ENDP
) pthis
)->pendp
;
1202 pdev
= dev_from_endp(pendp
);
1204 lock_dev(pdev
, TRUE
);
1206 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
1208 unlock_dev(pdev
, TRUE
);
1209 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1210 //delegate to uhci_remove_device for removing the urb queue on the endpoint
1214 if (endp_state(pendp
) == USB_ENDP_FLAG_STALL
)
1216 while (IsListEmpty(&pendp
->urb_list
) == FALSE
)
1218 purb
= (PURB
) RemoveHeadList(&pendp
->urb_list
);
1219 purb
->status
= USB_STATUS_ENDPOINT_HALTED
;
1220 InsertTailList(&abort_list
, (LIST_ENTRY
*) purb
);
1222 InitializeListHead(&pendp
->urb_list
);
1223 unlock_dev(pdev
, TRUE
);
1224 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1229 if (IsListEmpty(&pendp
->urb_list
) == FALSE
)
1231 purb
= (PURB
) RemoveHeadList(&pendp
->urb_list
);
1236 InitializeListHead(&pendp
->urb_list
);
1237 unlock_dev(pdev
, TRUE
);
1238 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1242 // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
1243 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_process_pending_endp(): endp_type=0x%x\n",
1245 switch (endp_type(pendp
))
1247 case USB_ENDPOINT_XFER_BULK
:
1250 can_submit
= STATUS_UNSUCCESSFUL
;
1252 can_submit
= uhci_internal_submit_bulk(uhci
, purb
);
1256 case USB_ENDPOINT_XFER_CONTROL
:
1258 can_submit
= uhci_internal_submit_ctrl(uhci
, purb
);
1261 case USB_ENDPOINT_XFER_INT
:
1263 can_submit
= uhci_internal_submit_int(uhci
, purb
);
1266 case USB_ENDPOINT_XFER_ISOC
:
1268 can_submit
= uhci_internal_submit_iso(uhci
, purb
);
1273 if (can_submit
== STATUS_NO_MORE_ENTRIES
)
1275 //no enough bandwidth or tds
1276 InsertHeadList(&pendp
->urb_list
, &purb
->urb_link
);
1277 InsertTailList(&temp_list
, pthis
);
1281 // other error or success
1282 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1284 if (can_submit
!= STATUS_SUCCESS
)
1287 InsertTailList(&abort_list
, (LIST_ENTRY
*) purb
);
1288 uhci_dbg_print(DBGLVL_MEDIUM
, ("uhci_process_pending_endp(): unable to submit urb 0x%x, "
1289 "with status=0x%x\n", purb
, can_submit
));
1290 purb
->status
= can_submit
;
1294 unlock_dev(pdev
, TRUE
);
1297 if (IsListEmpty(&temp_list
) == FALSE
)
1299 //re-append them to the pending_endp_list
1300 ListFirst(&temp_list
, pthis
);
1301 RemoveEntryList(&temp_list
);
1302 MergeList(&uhci
->pending_endp_list
, pthis
);
1304 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1306 if (IsListEmpty(&abort_list
) == FALSE
)
1309 cancel_list
= (PLIST_ENTRY
) usb_alloc_mem(NonPagedPool
, sizeof(WORK_QUEUE_ITEM
) + sizeof(LIST_ENTRY
));
1310 ASSERT(cancel_list
);
1312 ListFirst(&abort_list
, pthis
);
1313 RemoveEntryList(&abort_list
);
1314 InsertTailList(pthis
, cancel_list
);
1316 pwork_item
= (PWORK_QUEUE_ITEM
) (cancel_list
+ 1);
1318 // we do not need to worry the uhci_cancel_pending_endp_urb running when the
1319 // driver is unloading since it will prevent the dev_mgr to quit till all the
1320 // reference count to the dev drop to zero.
1321 ExInitializeWorkItem(pwork_item
, uhci_cancel_pending_endp_urb
, (PVOID
) cancel_list
);
1322 ExQueueWorkItem(pwork_item
, DelayedWorkQueue
);
1328 uhci_submit_urb(PUHCI_DEV uhci
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
1331 PUHCI_PENDING_ENDP pending_endp
;
1335 if (uhci
== NULL
|| pdev
== NULL
|| pendp
== NULL
|| purb
== NULL
)
1337 uhci_dbg_print(DBGLVL_MEDIUM
,
1338 ("uhci_submit_urb(): uhci=0x%x, pdev=0x%x, pendp=0x%x, purb=0x%x "
1339 "called with invalid param!\n", uhci
, pdev
, pendp
, purb
));
1340 return STATUS_INVALID_PARAMETER
;
1343 lock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1344 lock_dev(pdev
, TRUE
);
1346 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
1348 status
= purb
->status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1352 if (dev_class(pdev
) == USB_DEV_CLASS_ROOT_HUB
)
1354 unlock_dev(pdev
, TRUE
);
1355 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1356 status
= uhci_rh_submit_urb(pdev
, purb
);
1361 purb
->pendp
= pendp
;
1363 purb
->pendp
= &pdev
->default_endp
;
1365 if (dev_from_endp(purb
->pendp
) != pdev
)
1367 uhci_dbg_print(DBGLVL_MEDIUM
,
1368 ("uhci_submit_urb(): dev_from_endp=0x%x\n, pdev=0x%x, pendp=0x%x "
1369 "devices mismatch!\n", dev_from_endp(purb
->pendp
), pdev
, pendp
));
1371 status
= purb
->status
= STATUS_INVALID_PARAMETER
;
1375 if (endp_state(purb
->pendp
) == USB_ENDP_FLAG_STALL
)
1377 status
= purb
->status
= USB_STATUS_ENDPOINT_HALTED
;
1382 purb
->rest_bytes
= purb
->data_length
;
1384 if (endp_type(purb
->pendp
) == USB_ENDPOINT_XFER_BULK
)
1385 purb
->bytes_to_transfer
= (purb
->data_length
> purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
* UHCI_MAX_TDS_PER_TRANSFER
? purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
* UHCI_MAX_TDS_PER_TRANSFER
: purb
->data_length
); //multiple transfer for large data block
1387 purb
->bytes_to_transfer
= purb
->data_length
;
1389 uhci_dbg_print(DBGLVL_MEDIUM
, ("uhci_submit_urb(): bytes_to_transfer=0x%x\n", purb
->bytes_to_transfer
));
1391 purb
->bytes_transfered
= 0;
1392 InitializeListHead(&purb
->trasac_list
);
1393 purb
->last_finished_td
= &purb
->trasac_list
;
1394 purb
->flags
&= ~(URB_FLAG_STATE_MASK
| URB_FLAG_IN_SCHEDULE
| URB_FLAG_FORCE_CANCEL
);
1395 purb
->flags
|= URB_FLAG_STATE_PENDING
;
1398 i
= IsListEmpty(&pendp
->urb_list
);
1399 InsertTailList(&pendp
->urb_list
, &purb
->urb_link
);
1401 pdev
->ref_count
++; //for urb reference
1405 //there is urb pending, simply queue it and return
1406 status
= purb
->status
= STATUS_PENDING
;
1409 else if (usb_endp_busy_count(purb
->pendp
) && endp_type(purb
->pendp
) != USB_ENDPOINT_XFER_ISOC
)
1412 //No urb waiting but urb overlap not allowed,
1413 //so leave it in queue and return, will be scheduled
1416 status
= purb
->status
= STATUS_PENDING
;
1420 pending_endp
= alloc_pending_endp(&uhci
->pending_endp_pool
, 1);
1421 if (pending_endp
== NULL
)
1424 status
= purb
->status
= STATUS_UNSUCCESSFUL
;
1428 pending_endp
->pendp
= purb
->pendp
;
1429 InsertTailList(&uhci
->pending_endp_list
, &pending_endp
->endp_link
);
1431 unlock_dev(pdev
, TRUE
);
1432 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1434 uhci_process_pending_endp(uhci
);
1435 return STATUS_PENDING
;
1439 RemoveEntryList(&purb
->urb_link
);
1442 unlock_dev(pdev
, TRUE
);
1443 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1448 uhci_set_error_code(PURB urb
, ULONG raw_status
)
1450 if ((raw_status
& TD_CTRL_ANY_ERROR
) == 0)
1452 //test if the urb is canceled
1453 if (urb
->flags
& URB_FLAG_FORCE_CANCEL
)
1454 urb
->status
= STATUS_CANCELLED
;
1456 urb
->status
= STATUS_SUCCESS
;
1459 else if (raw_status
& TD_CTRL_BABBLE
)
1460 urb
->status
= USB_STATUS_DATA_OVERRUN
;
1462 else if (raw_status
& TD_CTRL_STALLED
)
1463 urb
->status
= USB_STATUS_STALL_PID
;
1465 else if (raw_status
& TD_CTRL_DBUFERR
)
1466 urb
->status
= USB_STATUS_BUFFER_OVERRUN
;
1468 else if (raw_status
& TD_CTRL_CRCTIMEO
)
1469 urb
->status
= USB_STATUS_CRC
;
1471 else if (raw_status
& TD_CTRL_BITSTUFF
)
1472 urb
->status
= USB_STATUS_BTSTUFF
;
1475 urb
->status
= STATUS_UNSUCCESSFUL
;
1481 uhci_sync_remove_urb_finished(PVOID context
)
1484 PLIST_ENTRY pthis
, pnext
, ptemp
;
1488 pparam
= (PSYNC_PARAM
) context
;
1489 uhci
= pparam
->uhci
;
1490 ptemp
= (PLIST_ENTRY
) pparam
->context
;
1494 return (UCHAR
) (pparam
->ret
= FALSE
);
1497 ListFirst(&uhci
->urb_list
, pthis
);
1500 //remove urbs not in the schedule
1501 ListNext(&uhci
->urb_list
, pthis
, pnext
);
1502 purb
= (PURB
) pthis
;
1504 if ((purb
->flags
& URB_FLAG_IN_SCHEDULE
) == 0)
1506 //finished or canceled( not apply for split bulk ).
1507 purb
->flags
&= ~URB_FLAG_STATE_MASK
;
1508 purb
->flags
|= URB_FLAG_STATE_FINISHED
;
1509 RemoveEntryList(pthis
);
1510 InsertTailList(ptemp
, pthis
);
1515 return (UCHAR
) TRUE
;
1519 uhci_drop_fsbr(PUHCI_DEV uhci
)
1522 return (UCHAR
) FALSE
;
1526 if (uhci
->fsbr_cnt
<= 0)
1528 uhci
->skel_term_qh
->link
= UHCI_PTR_TERM
;
1532 return (UCHAR
) TRUE
;
1536 uhci_dpc_callback(PKDPC dpc
, PVOID context
, PVOID sysarg1
, PVOID sysarg2
)
1540 LIST_HEAD temp_list
;
1541 PLIST_ENTRY pthis
, pnext
;
1544 PUHCI_PENDING_ENDP pending_endp
;
1546 PUSB_ENDPOINT pendp
;
1550 ULONG uhci_status
, urb_status
, toggle
= 0;
1552 SYNC_PARAM sync_param
;
1553 USE_BASIC_NON_PENDING_IRQL
;
1555 UNREFERENCED_PARAMETER(dpc
);
1556 UNREFERENCED_PARAMETER(sysarg2
);
1558 uhci
= (PUHCI_DEV
) context
;
1562 uhci_status
= (ULONG
) sysarg1
;
1564 InitializeListHead(&temp_list
);
1566 sync_param
.uhci
= uhci
;
1567 sync_param
.context
= (PVOID
) & temp_list
;
1569 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_dpc_callback(): entering..., uhci=0x%x\n", uhci
));
1570 //remove finished urb from uhci's urb-list
1571 KeSynchronizeExecution(uhci
->pdev_ext
->uhci_int
, uhci_sync_remove_urb_finished
, &sync_param
);
1573 //release resources( tds, and qhs ) the urb occupied
1574 while (IsListEmpty(&temp_list
) == FALSE
)
1576 //not in any public queue, if do not access into dev, no race
1577 //condition will occur
1578 purb
= (PURB
) RemoveHeadList(&temp_list
);
1579 urb_status
= purb
->status
;
1581 //the only place we do not use this lock on non-pending-endp-list data ops
1582 KeAcquireSpinLockAtDpcLevel(&uhci
->pending_endp_list_lock
);
1583 while (IsListEmpty(&purb
->trasac_list
) == FALSE
)
1585 pthis
= RemoveHeadList(&purb
->trasac_list
);
1587 if ((((PTD_EXTENSION
) pthis
)->flags
& UHCI_ITEM_FLAG_TYPE
) == UHCI_ITEM_FLAG_QH
)
1589 pqhe
= (PQH_EXTENSION
) pthis
;
1590 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
1591 free_qh(&uhci
->qh_pool
, pqhe
->pqh
);
1592 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
1596 //must be a td chain
1597 InsertHeadList(&purb
->trasac_list
, pthis
);
1598 for(i
= 0, purb
->bytes_transfered
= 0; i
< purb
->td_count
; i
++)
1601 // accumulate data transfered in tds
1602 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
1603 if ((ptd
->status
& TD_CTRL_ACTIVE
) == 0 && (ptd
->status
& TD_CTRL_ANY_ERROR
) == 0)
1605 j
= ptd
->status
& 0x7ff;
1606 purb
->bytes_transfered
+= ((j
== 0x7ff) ? 0 : (j
+ 1));
1609 ListNext(&purb
->trasac_list
, pthis
, pnext
);
1613 if (urb_status
& TD_CTRL_ANY_ERROR
)
1615 if (purb
->last_finished_td
!= NULL
&& purb
->last_finished_td
!= &purb
->trasac_list
)
1616 toggle
= (((PTD_EXTENSION
) purb
->last_finished_td
)->ptd
->info
& (1 << 19));
1618 //trick, remove trasac_list
1619 ListFirst(&purb
->trasac_list
, pthis
);
1620 RemoveEntryList(&purb
->trasac_list
);
1621 lock_td_pool(&uhci
->td_pool
, TRUE
);
1622 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
1623 unlock_td_pool(&uhci
->td_pool
, TRUE
);
1624 //termination condition
1625 InitializeListHead(&purb
->trasac_list
);
1626 purb
->last_finished_td
= NULL
;
1630 if (endp_type(purb
->pendp
) == USB_ENDPOINT_XFER_ISOC
1631 || endp_type(purb
->pendp
) == USB_ENDPOINT_XFER_INT
)
1632 uhci_claim_bandwidth(uhci
, purb
, FALSE
); //release band-width
1634 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1636 uhci_set_error_code(purb
, urb_status
);
1640 //since the ref_count for the urb is not released, we can safely have one
1642 pdev
= dev_from_endp(purb
->pendp
);
1643 pendp
= purb
->pendp
;
1645 if (purb
->status
== USB_STATUS_BABBLE_DETECTED
)
1647 usb_dbg_print(DBGLVL_MEDIUM
,
1648 ("uhci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus\n"));
1650 uhci_start(&uhci
->hcd_interf
);
1653 //this will let the new request in uhci_generic_urb_completion to this endp
1654 //be processed rather than queued in the pending_endp_list
1655 lock_dev(pdev
, TRUE
);
1656 usb_endp_busy_count_dec(pendp
);
1657 unlock_dev(pdev
, TRUE
);
1659 if (usb_success(purb
->status
) == FALSE
)
1661 // set error code and complete the urb and purb is invalid from this point
1662 uhci_generic_urb_completion(purb
, purb
->context
);
1666 if ((purb
->pipe
& USB_ENDPOINT_XFERTYPE_MASK
) == USB_ENDPOINT_XFER_BULK
)
1668 purb
->rest_bytes
-= purb
->bytes_transfered
;
1669 if (purb
->rest_bytes
)
1675 uhci_generic_urb_completion(purb
, purb
->context
);
1680 uhci_generic_urb_completion(purb
, purb
->context
);
1681 //purb is now invalid
1685 KeAcquireSpinLockAtDpcLevel(&uhci
->pending_endp_list_lock
);
1686 lock_dev(pdev
, TRUE
);
1691 if (urb_status
& TD_CTRL_ANY_ERROR
&& endp_type(pendp
) != USB_ENDPOINT_XFER_CONTROL
)
1693 pendp
->flags
&= ~USB_ENDP_FLAG_STAT_MASK
;
1694 pendp
->flags
|= USB_ENDP_FLAG_STALL
;
1697 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
1699 unlock_dev(pdev
, TRUE
);
1700 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1701 if (finished
== FALSE
)
1704 purb
->status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1705 uhci_generic_urb_completion(purb
, purb
->context
);
1707 lock_dev(pdev
, TRUE
);
1709 unlock_dev(pdev
, TRUE
);
1714 if (finished
&& IsListEmpty(&pendp
->urb_list
) == TRUE
)
1716 unlock_dev(pdev
, TRUE
);
1717 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1720 else if (finished
== TRUE
)
1722 //has urb in the endp's urb-list
1723 if (usb_endp_busy_count(pendp
) > 0)
1725 //the urbs still have chance to be sheduled but not this time
1726 unlock_dev(pdev
, TRUE
);
1727 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1732 if (finished
== FALSE
)
1734 //a split bulk transfer
1735 purb
->bytes_transfered
= 0;
1736 purb
->bytes_to_transfer
=
1737 UHCI_MAX_TDS_PER_TRANSFER
* purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
1739 ? purb
->rest_bytes
: UHCI_MAX_TDS_PER_TRANSFER
* purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
;
1741 //the urb is not finished
1742 purb
->flags
&= ~URB_FLAG_STATE_MASK
;
1743 purb
->flags
|= URB_FLAG_STATE_PENDING
;
1745 InsertHeadList(&pendp
->urb_list
, &purb
->urb_link
);
1748 pending_endp
= alloc_pending_endp(&uhci
->pending_endp_pool
, 1);
1751 unlock_dev(pdev
, TRUE
);
1752 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1756 pending_endp
->pendp
= pendp
;
1757 InsertTailList(&uhci
->pending_endp_list
, &pending_endp
->endp_link
);
1759 unlock_dev(pdev
, TRUE
);
1760 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1763 //ah...exhausted, let's find some in the pending_endp_list to rock
1764 uhci_process_pending_endp(uhci
);
1769 uhci_add_device(PUHCI_DEV uhci
, PUSB_DEV dev
)
1771 if (dev
== NULL
|| uhci
== NULL
)
1778 uhci_sync_cancel_urbs_dev(PVOID context
)
1780 //cancel all the urbs on one dev
1782 PUSB_DEV pdev
, dest_dev
;
1783 PSYNC_PARAM sync_param
;
1784 PLIST_ENTRY pthis
, pnext
;
1787 sync_param
= (PSYNC_PARAM
) context
;
1788 dest_dev
= (PUSB_DEV
) sync_param
->context
;
1789 uhci
= sync_param
->uhci
;
1791 if (uhci
== NULL
|| dest_dev
== NULL
)
1793 return (UCHAR
) (sync_param
->ret
= FALSE
);
1796 ListFirst(&uhci
->urb_list
, pthis
);
1799 pdev
= dev_from_endp(((PURB
) pthis
)->pendp
);
1800 if (pdev
== dest_dev
)
1802 ((PURB
) pthis
)->flags
|= URB_FLAG_FORCE_CANCEL
;
1804 ListNext(&uhci
->urb_list
, pthis
, pnext
);
1809 uhci
->skel_term_td
->status
|= TD_CTRL_IOC
;
1811 return (UCHAR
) (sync_param
->ret
= TRUE
);
1815 uhci_remove_device(PUHCI_DEV uhci
, PUSB_DEV dev
)
1817 PUHCI_PENDING_ENDP ppending_endp
;
1818 PLIST_ENTRY pthis
, pnext
;
1820 LIST_HEAD temp_list
;
1822 SYNC_PARAM sync_param
;
1826 if (uhci
== NULL
|| dev
== NULL
)
1829 InitializeListHead(&temp_list
);
1831 //free pending endp that has urb queued from pending endp list
1832 lock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1834 ListFirst(&uhci
->pending_endp_list
, pthis
);
1838 ppending_endp
= (PUHCI_PENDING_ENDP
) pthis
;
1839 ListNext(&uhci
->pending_endp_list
, pthis
, pnext
);
1840 if (dev_from_endp(ppending_endp
->pendp
) == dev
)
1842 RemoveEntryList(pthis
);
1843 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1847 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1849 //cancel all the urbs in the urb-list
1850 sync_param
.uhci
= uhci
;
1851 sync_param
.context
= (PVOID
) dev
;
1853 KeSynchronizeExecution(uhci
->pdev_ext
->uhci_int
, uhci_sync_cancel_urbs_dev
, &sync_param
);
1855 //cancel all the urb in the endp's urb-list
1857 lock_dev(dev
, FALSE
);
1858 if (dev
->usb_config
)
1860 //only for configed dev
1861 for(i
= 0; i
< dev
->usb_config
->if_count
; i
++)
1863 for(j
= 0; j
< dev
->usb_config
->interf
[i
].endp_count
; j
++)
1865 ListFirst(&dev
->usb_config
->interf
[i
].endp
[j
].urb_list
, pthis
);
1868 ListNext(&dev
->usb_config
->interf
[i
].endp
[j
].urb_list
, pthis
, pnext
);
1870 RemoveEntryList(pthis
);
1871 InsertHeadList(&temp_list
, pthis
);
1879 ListFirst(&dev
->default_endp
.urb_list
, pthis
);
1883 ListNext(&dev
->default_endp
.urb_list
, pthis
, pnext
);
1885 RemoveEntryList(pthis
);
1886 InsertHeadList(&temp_list
, pthis
);
1890 unlock_dev(dev
, FALSE
);
1892 if (IsListEmpty(&temp_list
) == FALSE
)
1894 for(i
= 0; i
< k
; i
++)
1896 //complete those urbs with error
1897 pthis
= RemoveHeadList(&temp_list
);
1898 purb
= (PURB
) pthis
;
1899 purb
->status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1901 uhci_generic_urb_completion(purb
, purb
->context
);
1906 lock_dev(dev
, FALSE
) dev
->ref_count
-= k
;
1907 unlock_dev(dev
, FALSE
);
1914 // assume that the urb has its rest_bytes and bytes_to_transfer set
1915 // and bytes_transfered is zeroed.
1916 // dev_lock must be acquired outside
1917 // urb comes from dev's endpoint urb-list. it is already removed from
1918 // the endpoint urb-list.
1921 uhci_internal_submit_bulk(PUHCI_DEV uhci
, PURB urb
)
1924 LONG max_packet_size
, td_count
, offset
, bytes_to_transfer
, data_load
;
1928 LIST_ENTRY td_list
, *pthis
, *pnext
;
1929 BOOLEAN old_toggle
, toggle
, ret
;
1932 if (uhci
== NULL
|| urb
== NULL
)
1933 return STATUS_INVALID_PARAMETER
;
1935 max_packet_size
= endp_max_packet_size(urb
->pendp
);
1936 if (urb
->bytes_to_transfer
== 0)
1938 return STATUS_INVALID_PARAMETER
;
1941 td_count
= (urb
->bytes_to_transfer
+ max_packet_size
- 1) / max_packet_size
;
1943 lock_td_pool(&uhci
->td_pool
, TRUE
);
1944 if (can_transfer(&uhci
->td_pool
, td_count
) == FALSE
)
1946 unlock_td_pool(&uhci
->td_pool
, TRUE
);
1947 return STATUS_NO_MORE_ENTRIES
;
1950 ptd
= alloc_tds(&uhci
->td_pool
, td_count
);
1951 unlock_td_pool(&uhci
->td_pool
, TRUE
);
1955 return STATUS_UNSUCCESSFUL
;
1958 InitializeListHead(&td_list
);
1959 InsertTailList(&ptd
->ptde
->vert_link
, &td_list
);
1961 ListFirst(&td_list
, pthis
);
1962 ListNext(&td_list
, pthis
, pnext
);
1964 start_addr
= &urb
->data_buffer
[urb
->data_length
- urb
->rest_bytes
];
1967 old_toggle
= toggle
= urb
->pendp
->flags
& USB_ENDP_FLAG_DATATOGGLE
? TRUE
: FALSE
;
1968 bytes_to_transfer
= urb
->bytes_to_transfer
;
1970 urb
->pipe
= ((max_packet_size
- 1) << 21)
1971 | ((ULONG
) endp_num(urb
->pendp
) << 15)
1972 | (dev_from_endp(urb
->pendp
)->dev_addr
<< 8)
1973 | ((ULONG
) endp_dir(urb
->pendp
)) | USB_ENDPOINT_XFER_BULK
;
1975 pid
= (((ULONG
) urb
->pendp
->pusb_endp_desc
->bEndpointAddress
& USB_DIR_IN
) ? USB_PID_IN
: USB_PID_OUT
);
1978 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
1980 data_load
= max_packet_size
< bytes_to_transfer
? max_packet_size
: bytes_to_transfer
;
1983 (3 << TD_CTRL_C_ERR_SHIFT
)
1985 ((data_load
- 1) << 21)
1987 | ((ULONG
) endp_num(urb
->pendp
) << 15)
1988 | (dev_from_endp(urb
->pendp
)->dev_addr
<< 8)
1989 | pid
, MmGetPhysicalAddress(start_addr
+ offset
).LowPart
);
1991 bytes_to_transfer
-= data_load
;
1992 offset
+= data_load
;
1996 ptd
->link
= ((PTD_EXTENSION
) pnext
)->ptd
->phy_addr
;
2000 //Last one, enable ioc and short packet detect if necessary
2001 ptd
->link
= UHCI_PTR_TERM
;
2002 ptd
->status
|= TD_CTRL_IOC
;
2003 if (bytes_to_transfer
< max_packet_size
&& (pid
== USB_PID_IN
))
2005 //ptd->status |= TD_CTRL_SPD;
2012 ListNext(&td_list
, pthis
, pnext
);
2016 ListFirst(&td_list
, pthis
);
2017 RemoveEntryList(&td_list
);
2019 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
2020 pqh
= alloc_qh(&uhci
->qh_pool
);
2021 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
2025 lock_td_pool(&uhci
->td_pool
, TRUE
);
2028 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2030 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2031 return STATUS_NO_MORE_ENTRIES
;
2035 urb
->td_count
= td_count
;
2037 uhci_insert_tds_qh(pqh
, ((PTD_EXTENSION
) pthis
)->ptd
);
2038 uhci_insert_qh_urb(urb
, pqh
);
2040 (urb
->pendp
->flags
& ~USB_ENDP_FLAG_DATATOGGLE
) | (toggle
? USB_ENDP_FLAG_DATATOGGLE
: 0);
2041 usb_endp_busy_count_inc(urb
->pendp
);
2042 uhci_insert_urb_to_schedule(uhci
, urb
, ret
);
2046 // undo all we have done
2047 RemoveEntryList(&pqh
->pqhe
->vert_link
); //remove qh from td_chain
2048 RemoveEntryList(&urb
->trasac_list
);
2050 lock_td_pool(&uhci
->td_pool
, TRUE
);
2052 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2053 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2055 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
2057 free_qh(&uhci
->qh_pool
, pqh
);
2058 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
2060 InitializeListHead(&urb
->trasac_list
);
2061 usb_endp_busy_count_dec(urb
->pendp
);
2063 (urb
->pendp
->flags
& ~USB_ENDP_FLAG_DATATOGGLE
) | (old_toggle
? USB_ENDP_FLAG_DATATOGGLE
: 0);
2064 return STATUS_UNSUCCESSFUL
;
2066 return STATUS_SUCCESS
;
2070 uhci_internal_submit_ctrl(PUHCI_DEV uhci
, PURB urb
)
2072 LIST_ENTRY td_list
, *pthis
, *pnext
;
2075 LONG max_packet_size
, bytes_to_transfer
, bytes_rest
, start_idx
;
2082 if (uhci
== NULL
|| urb
== NULL
)
2083 return STATUS_INVALID_PARAMETER
;
2086 bytes_rest
= urb
->rest_bytes
;
2087 bytes_to_transfer
= urb
->bytes_to_transfer
;
2088 max_packet_size
= endp_max_packet_size(urb
->pendp
);
2089 start_idx
= urb
->data_length
- urb
->rest_bytes
;
2090 td_count
= 2 + (urb
->bytes_to_transfer
+ max_packet_size
- 1) / max_packet_size
;
2092 lock_td_pool(&uhci
->td_pool
, TRUE
);
2094 if (can_transfer(&uhci
->td_pool
, td_count
) == FALSE
)
2096 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2097 return STATUS_NO_MORE_ENTRIES
;
2100 ptd
= alloc_tds(&uhci
->td_pool
, td_count
);
2101 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2105 return STATUS_UNSUCCESSFUL
;
2108 InsertTailList(&ptd
->ptde
->vert_link
, &td_list
);
2110 ListFirst(&td_list
, pthis
);
2111 ListNext(&td_list
, pthis
, pnext
);
2113 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2115 pdev
= dev_from_endp(urb
->pendp
);
2116 dev_addr
= pdev
->dev_addr
;
2118 if (dev_state(pdev
) <= USB_DEV_STATE_RESET
)
2121 usb_dbg_print(DBGLVL_MAXIMUM
, ("uhci_internal_submit_ctrl(): dev_addr =0x%x\n", dev_addr
));
2123 RtlCopyMemory(uhci
->io_buf
, urb
->setup_packet
, 8);
2125 if ((urb
->setup_packet
[0] & USB_DIR_IN
) == 0) //out
2126 RtlCopyMemory(&uhci
->io_buf
[8], urb
->data_buffer
, bytes_to_transfer
);
2128 RtlZeroMemory(&uhci
->io_buf
[8], bytes_to_transfer
);
2131 (3 << TD_CTRL_C_ERR_SHIFT
) | (TD_CTRL_ACTIVE
),
2132 (7 << 21) | (((ULONG
) endp_num(urb
->pendp
)) << 15) | (dev_addr
<< 8) | (USB_PID_SETUP
),
2133 //uhci->io_buf_logic_addr.LowPart);
2134 MmGetPhysicalAddress(urb
->setup_packet
).LowPart
);
2136 ptd
->link
= ((PTD_EXTENSION
) pnext
)->ptd
->phy_addr
;
2138 ListNext(&td_list
, pthis
, pnext
);
2140 urb
->pipe
= ((max_packet_size
- 1) << 21)
2141 | ((ULONG
) endp_num(urb
->pendp
) << 15)
2142 | (dev_addr
<< 8) | (pdev
->flags
& USB_DEV_FLAG_LOW_SPEED
) | USB_ENDPOINT_XFER_CONTROL
;
2144 for(i
= 0, toggle
= 1; ((i
< td_count
- 2) && pthis
); i
++, toggle
^= 1)
2146 //construct tds for DATA packets of data stage.
2147 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2149 (3 << TD_CTRL_C_ERR_SHIFT
)
2151 ((bytes_to_transfer
>
2152 max_packet_size
? max_packet_size
- 1 : bytes_to_transfer
-
2153 1) << 21) | (toggle
<< 19) | (((ULONG
) endp_num(urb
->
2154 pendp
)) << 15) | (dev_addr
<< 8) |
2155 ((urb
->setup_packet
[0] & USB_DIR_IN
) ? USB_PID_IN
: USB_PID_OUT
),
2156 //uhci->io_buf_logic_addr.LowPart + 8 + i * max_packet_size );
2157 MmGetPhysicalAddress(&urb
->data_buffer
[start_idx
+ i
* max_packet_size
]).LowPart
);
2160 ptd
->link
= ((PTD_EXTENSION
) pnext
)->ptd
->phy_addr
;
2162 if (i
< td_count
- 3)
2164 bytes_to_transfer
-= max_packet_size
;
2168 if (bytes_to_transfer
> 0)
2170 if (bytes_to_transfer
< max_packet_size
&& (urb
->setup_packet
[0] & USB_DIR_IN
))
2171 ptd
->status
|= TD_CTRL_SPD
;
2177 ListNext(&td_list
, pthis
, pnext
);
2181 ptd
->link
= ((PTD_EXTENSION
) pnext
)->ptd
->phy_addr
;
2183 ListFirstPrev(&td_list
, pthis
);
2184 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2186 //the last is an IN transaction
2188 (3 << TD_CTRL_C_ERR_SHIFT
)
2189 | (TD_CTRL_ACTIVE
| TD_CTRL_IOC
),
2190 (UHCI_NULL_DATA_SIZE
<< 21)
2192 | (((ULONG
) endp_num(urb
->pendp
)) << 15)
2195 ? ((urb
->setup_packet
[0] & USB_DIR_IN
) ? USB_PID_OUT
: USB_PID_IN
) : USB_PID_IN
), 0);
2197 ptd
->link
= UHCI_PTR_TERM
;
2199 ListFirst(&td_list
, pthis
);
2200 RemoveEntryList(&td_list
);
2202 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
2203 pqh
= alloc_qh(&uhci
->qh_pool
);
2204 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
2208 lock_td_pool(&uhci
->td_pool
, TRUE
);
2210 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2211 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2213 return STATUS_NO_MORE_ENTRIES
;
2216 urb
->td_count
= td_count
;
2218 uhci_insert_tds_qh(pqh
, ((PTD_EXTENSION
) pthis
)->ptd
);
2219 uhci_insert_qh_urb(urb
, pqh
);
2221 usb_endp_busy_count_inc(urb
->pendp
);
2222 uhci_insert_urb_to_schedule(uhci
, urb
, ret
);
2225 RemoveEntryList(&pqh
->pqhe
->vert_link
);
2226 RemoveEntryList(&urb
->trasac_list
);
2228 lock_td_pool(&uhci
->td_pool
, TRUE
);
2230 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2231 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2233 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
2235 free_qh(&uhci
->qh_pool
, pqh
);
2236 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
2238 InitializeListHead(&urb
->trasac_list
);
2239 usb_endp_busy_count_dec(urb
->pendp
);
2240 return STATUS_UNSUCCESSFUL
;
2243 return STATUS_SUCCESS
;
2247 uhci_internal_submit_int(PUHCI_DEV uhci
, PURB urb
)
2251 LONG max_packet_size
;
2255 if (uhci
== NULL
|| urb
== NULL
)
2257 uhci_dbg_print(DBGLVL_MEDIUM
,
2258 ("uhci_internal_submit_int(): uhci=0x%x, urb=0x%x "
2259 "returning STATUS_INVALID_PARAMETER!\n", uhci
, urb
));
2260 return STATUS_INVALID_PARAMETER
;
2263 toggle
= (urb
->pendp
->flags
& USB_ENDP_FLAG_DATATOGGLE
) ? TRUE
: FALSE
;
2264 max_packet_size
= endp_max_packet_size(urb
->pendp
);
2266 if (max_packet_size
< urb
->data_length
|| max_packet_size
== 0 || max_packet_size
> 64)
2268 uhci_dbg_print(DBGLVL_MEDIUM
,
2269 ("uhci_internal_submit_int(): max_packet_size=%d, urb->data_length=%d "
2270 "returning STATUS_INVALID_PARAMETER!\n", max_packet_size
, urb
->data_length
));
2271 return STATUS_INVALID_PARAMETER
;
2274 lock_td_pool(&uhci
->td_pool
, TRUE
);
2275 ptd
= alloc_td(&uhci
->td_pool
);
2276 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2279 return STATUS_NO_MORE_ENTRIES
;
2281 for(i
= 1; i
<= 7; i
++)
2283 if (((ULONG
) max_packet_size
) >> i
)
2292 urb
->pipe
= (((ULONG
) urb
->pendp
->pusb_endp_desc
->bInterval
) << 24)
2295 | ((ULONG
) endp_num(urb
->pendp
) << 15)
2296 | (((ULONG
) dev_from_endp(urb
->pendp
)->dev_addr
) << 8)
2297 | USB_DIR_IN
| (dev_from_endp(urb
->pendp
)->flags
& USB_DEV_FLAG_LOW_SPEED
) | USB_ENDPOINT_XFER_INT
;
2300 (3 << TD_CTRL_C_ERR_SHIFT
)
2302 | ((urb
->data_length
< max_packet_size
? TD_CTRL_SPD
: 0))
2304 (((ULONG
) max_packet_size
- 1) << 21)
2306 | ((ULONG
) endp_num(urb
->pendp
) << 15)
2307 | (((ULONG
) dev_from_endp(urb
->pendp
)->dev_addr
& 0x7f) << 8)
2308 | USB_PID_IN
, MmGetPhysicalAddress(urb
->data_buffer
).LowPart
);
2313 InitializeListHead(&urb
->trasac_list
);
2314 InsertTailList(&urb
->trasac_list
, &ptd
->ptde
->vert_link
);
2316 //indirectly guarded by pending_endp_list_lock
2317 if (uhci_claim_bandwidth(uhci
, urb
, TRUE
) == FALSE
)
2319 InitializeListHead(&urb
->trasac_list
);
2321 lock_td_pool(&uhci
->td_pool
, TRUE
);
2322 free_td(&uhci
->td_pool
, ptd
);
2323 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2325 return STATUS_NO_MORE_ENTRIES
;
2328 urb
->pendp
->flags
= (urb
->pendp
->flags
& ~USB_ENDP_FLAG_DATATOGGLE
) | (toggle
<< 31);
2329 usb_endp_busy_count_inc(urb
->pendp
);
2331 uhci_insert_urb_to_schedule(uhci
, urb
, ret
);
2335 lock_td_pool(&uhci
->td_pool
, TRUE
);
2337 free_td(&uhci
->td_pool
, ptd
);
2338 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2340 InitializeListHead(&urb
->trasac_list
);
2341 usb_endp_busy_count_dec(urb
->pendp
);
2342 urb
->pendp
->flags
= (urb
->pendp
->flags
& ~USB_ENDP_FLAG_DATATOGGLE
) | ((toggle
^ 1) << 31);
2343 uhci_claim_bandwidth(uhci
, urb
, FALSE
);
2344 return STATUS_UNSUCCESSFUL
;
2347 return STATUS_SUCCESS
;
2352 uhci_internal_submit_iso(PUHCI_DEV uhci
, PURB urb
)
2355 LIST_ENTRY td_list
, *pthis
, *pnext
;
2357 BOOLEAN toggle
= FALSE
, ret
;
2359 if (uhci
== NULL
|| urb
== NULL
)
2360 return STATUS_INVALID_PARAMETER
;
2362 if (urb
->iso_frame_count
== 0)
2363 return STATUS_INVALID_PARAMETER
;
2365 lock_td_pool(&uhci
->td_pool
, TRUE
);
2367 if (can_transfer(&uhci
->td_pool
, urb
->iso_frame_count
) == FALSE
)
2369 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2370 return STATUS_NO_MORE_ENTRIES
;
2373 ptd
= alloc_tds(&uhci
->td_pool
, urb
->iso_frame_count
);
2374 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2378 return STATUS_UNSUCCESSFUL
;
2381 InsertTailList(&ptd
->ptde
->vert_link
, &td_list
);
2382 ListFirst(&td_list
, pthis
);
2384 urb
->td_count
= urb
->iso_frame_count
;
2386 urb
->pipe
= (((ULONG
) urb
->iso_packet_desc
[0].length
) << 21)
2387 | ((ULONG
) endp_num(urb
->pendp
) << 15)
2388 | (((ULONG
) dev_from_endp(urb
->pendp
)->dev_addr
) << 8)
2389 | ((ULONG
) endp_dir(urb
->pendp
)) | USB_ENDPOINT_XFER_ISOC
;
2392 for(i
= 0; i
< urb
->iso_frame_count
&& pthis
; i
++)
2394 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2396 (3 << TD_CTRL_C_ERR_SHIFT
)
2399 (((ULONG
) urb
->iso_packet_desc
[i
].length
- 1) << 21)
2401 | ((ULONG
) endp_num(urb
->pendp
) << 15)
2402 | (((ULONG
) dev_from_endp(urb
->pendp
)->dev_addr
) << 8)
2403 | ((urb
->pendp
->pusb_endp_desc
->bEndpointAddress
& USB_DIR_IN
)
2404 ? USB_PID_OUT
: USB_PID_IN
),
2405 MmGetPhysicalAddress(&urb
->data_buffer
[urb
->iso_packet_desc
[i
].offset
]).LowPart
);
2408 ListNext(&td_list
, pthis
, pnext
);
2412 ptd
->status
|= TD_CTRL_IOC
; //need interrupt
2414 ListFirst(&td_list
, pthis
);
2415 RemoveEntryList(&td_list
);
2417 InsertTailList(pthis
, &urb
->trasac_list
);
2419 //indirectly guarded by pending_endp_list_lock
2420 if (uhci_claim_bandwidth(uhci
, urb
, TRUE
) == FALSE
)
2422 //bad news: we can not allocate the enough bandwidth for the urb
2423 RemoveEntryList(&urb
->trasac_list
);
2424 InitializeListHead(&urb
->trasac_list
);
2426 lock_td_pool(&uhci
->td_pool
, TRUE
);
2427 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2428 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2429 return STATUS_NO_MORE_ENTRIES
;
2433 usb_endp_busy_count_inc(urb
->pendp
);
2434 uhci_insert_urb_to_schedule(uhci
, urb
, ret
);
2437 usb_endp_busy_count_dec(urb
->pendp
);
2438 RemoveEntryList(&urb
->trasac_list
);
2440 lock_td_pool(&uhci
->td_pool
, TRUE
);
2441 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
2442 unlock_td_pool(&uhci
->td_pool
, TRUE
);
2443 uhci_claim_bandwidth(uhci
, urb
, FALSE
);
2444 return STATUS_UNSUCCESSFUL
;
2447 return STATUS_SUCCESS
;
2452 uhci_is_xfer_finished(PURB urb
)
2454 PLIST_ENTRY pthis
, pnext
;
2459 if (urb
->last_finished_td
== NULL
)
2461 urb
->last_finished_td
= &urb
->trasac_list
;
2464 if (&urb
->trasac_list
== urb
->last_finished_td
)
2465 ListFirst(&urb
->trasac_list
, pthis
)
2467 ListNext(&urb
->trasac_list
, urb
->last_finished_td
, pthis
);
2471 if ((((PTD_EXTENSION
) pthis
)->flags
& UHCI_ITEM_FLAG_TYPE
) != UHCI_ITEM_FLAG_TD
)
2473 ListNext(&urb
->trasac_list
, pthis
, pnext
);
2479 ptde
= (PTD_EXTENSION
) pthis
;
2481 ASSERT(ptd
!= NULL
);
2483 if (ptd
->status
& TD_CTRL_ACTIVE
)
2489 //let's see whether error occured
2490 if ((ptd
->status
& TD_CTRL_ANY_ERROR
) == 0)
2492 urb
->last_finished_td
= pthis
;
2493 ListNext(&urb
->trasac_list
, pthis
, pnext
);
2499 urb
->status
= ptd
->status
;
2513 // executed in isr, and have frame_list_lock acquired, so
2514 // never try to acquire any spin-lock
2515 // remove the bulk urb from schedule, and mark it not in
2518 uhci_remove_urb_from_schedule(PUHCI_DEV uhci
, PURB urb
)
2520 BOOLEAN ret
= FALSE
;
2522 switch (urb
->pipe
& USB_ENDPOINT_XFERTYPE_MASK
)
2524 case USB_ENDPOINT_XFER_BULK
:
2526 ret
= uhci_remove_bulk_from_schedule(uhci
, urb
);
2529 case USB_ENDPOINT_XFER_CONTROL
:
2531 ret
= uhci_remove_ctrl_from_schedule(uhci
, urb
);
2534 case USB_ENDPOINT_XFER_INT
:
2536 ret
= uhci_remove_int_from_schedule(uhci
, urb
);
2539 case USB_ENDPOINT_XFER_ISOC
:
2541 ret
= uhci_remove_iso_from_schedule(uhci
, urb
);
2549 // executed in isr, and have frame_list_lock acquired, so
2550 // never try to acquire any spin-lock
2551 // remove the bulk urb from schedule, and mark it not in
2554 uhci_remove_bulk_from_schedule(PUHCI_DEV uhci
, PURB urb
)
2557 PUHCI_QH pqh
, pnext_qh
, pprev_qh
;
2558 PLIST_ENTRY pthis
, pnext
, pprev
;
2561 if (uhci
== NULL
|| urb
== NULL
)
2564 ListFirst(&urb
->trasac_list
, pthis
);
2565 pqh
= ((PQH_EXTENSION
) pthis
)->pqh
;
2567 ListFirst(&pqh
->pqhe
->hori_link
, pnext
);
2568 ListFirstPrev(&pqh
->pqhe
->hori_link
, pprev
);
2570 if (pprev
== NULL
|| pnext
== NULL
)
2573 pnext_qh
= struct_ptr(pnext
, QH_EXTENSION
, hori_link
)->pqh
;
2574 pprev_qh
= struct_ptr(pprev
, QH_EXTENSION
, hori_link
)->pqh
;
2579 pprev_qh
->link
= pnext_qh
->phy_addr
;
2583 //only two qhs in the list
2584 for(i
= 0; i
< UHCI_MAX_SKELQHS
; i
++)
2586 if (pprev_qh
== uhci
->skel_qh
[i
])
2591 ASSERT(i
< UHCI_MAX_SKELQHS
- 1);
2592 pprev_qh
->link
= uhci
->skel_qh
[i
+ 1]->phy_addr
;
2594 RemoveEntryList(&pqh
->pqhe
->hori_link
);
2596 urb
->flags
&= ~URB_FLAG_IN_SCHEDULE
;
2598 if ((urb
->pipe
& USB_DEV_FLAG_LOW_SPEED
) == 0)
2599 uhci_drop_fsbr(uhci
);
2605 uhci_remove_iso_from_schedule(PUHCI_DEV uhci
, PURB urb
)
2607 PUHCI_TD ptd
, pprev_td
;
2608 PLIST_ENTRY pthis
, pnext
, pprev
;
2611 if (uhci
== NULL
|| urb
== NULL
)
2614 ListFirst(&urb
->trasac_list
, pthis
);
2616 for(i
= 0; i
< urb
->iso_frame_count
&& pthis
; i
++)
2618 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2619 idx
= (urb
->iso_start_frame
+ i
) & (UHCI_MAX_FRAMES
- 1);
2621 ListFirstPrev(&ptd
->ptde
->hori_link
, pprev
);
2626 if (pprev
== &uhci
->frame_list_cpu
[idx
].td_link
)
2628 uhci
->frame_list
[idx
] = ptd
->link
;
2632 pprev_td
= struct_ptr(pprev
, TD_EXTENSION
, hori_link
)->ptd
;
2633 pprev_td
->link
= ptd
->link
;
2636 RemoveEntryList(&ptd
->ptde
->hori_link
);
2637 ListNext(&urb
->trasac_list
, pthis
, pnext
);
2641 urb
->flags
&= ~URB_FLAG_IN_SCHEDULE
;
2646 uhci_remove_int_from_schedule(PUHCI_DEV uhci
, PURB urb
)
2648 PUHCI_TD ptd
, pnext_td
, pprev_td
;
2649 PLIST_ENTRY pthis
, pnext
, pprev
;
2652 if (uhci
== NULL
|| urb
== NULL
)
2655 ListFirst(&urb
->trasac_list
, pthis
);
2656 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2657 ListFirst(&ptd
->ptde
->hori_link
, pnext
);
2658 ListFirstPrev(&ptd
->ptde
->hori_link
, pprev
);
2660 if (pprev
== NULL
|| pnext
== NULL
)
2663 pnext_td
= struct_ptr(pnext
, TD_EXTENSION
, hori_link
)->ptd
;
2664 pprev_td
= struct_ptr(pprev
, TD_EXTENSION
, hori_link
)->ptd
;
2666 if (pprev_td
!= pnext_td
)
2667 pprev_td
->link
= pnext_td
->phy_addr
;
2671 for(i
= UHCI_MAX_SKELTDS
- 2; i
>= 0; i
--)
2673 //UHCI_MAX_SKELTDS -1 skel tds for int transfer
2674 if (pprev_td
== uhci
->skel_td
[i
])
2681 pprev_td
->link
= uhci
->skel_qh
[0]->phy_addr
;
2685 pprev_td
->link
= uhci
->skel_td
[i
- 1]->phy_addr
;
2688 RemoveEntryList(&ptd
->ptde
->hori_link
);
2690 urb
->flags
&= ~URB_FLAG_IN_SCHEDULE
;
2695 uhci_insert_tds_qh(PUHCI_QH pqh
, PUHCI_TD td_chain
)
2697 if (pqh
== NULL
|| td_chain
== NULL
)
2700 InsertTailList(&td_chain
->ptde
->vert_link
, &pqh
->pqhe
->vert_link
);
2701 pqh
->element
= td_chain
->phy_addr
;
2706 uhci_insert_qh_urb(PURB urb
, PUHCI_QH qh_chain
)
2708 if (urb
== NULL
|| qh_chain
== NULL
)
2711 InsertTailList(&qh_chain
->pqhe
->vert_link
, &urb
->trasac_list
);
2712 qh_chain
->pqhe
->purb
= urb
;
2716 // must have dev_lock and frame_list_lock acquired
2718 uhci_insert_urb_schedule(PUHCI_DEV uhci
, PURB urb
)
2720 PUHCI_QH pqh
, pskel_qh
, pnext_qh
;
2721 PUHCI_TD ptd
, plast_td
;
2722 PLIST_ENTRY pthis
, pnext
;
2725 if (uhci
== NULL
|| urb
== NULL
)
2728 ListFirst(&urb
->trasac_list
, pthis
);
2732 InsertTailList(&uhci
->urb_list
, &urb
->urb_link
);
2734 urb
->flags
&= ~URB_FLAG_STATE_MASK
;
2735 urb
->flags
|= URB_FLAG_STATE_IN_PROCESS
| URB_FLAG_IN_SCHEDULE
;
2738 switch (endp_type(urb
->pendp
))
2740 case USB_ENDPOINT_XFER_CONTROL
:
2742 pqh
= ((PQH_EXTENSION
) pthis
)->pqh
;
2744 if ((dev_from_endp(urb
->pendp
)->flags
& USB_DEV_FLAG_LOW_SPEED
) == 0)
2746 pskel_qh
= uhci
->skel_hs_control_qh
;
2747 pnext_qh
= uhci
->skel_bulk_qh
;
2751 pskel_qh
= uhci
->skel_ls_control_qh
;
2752 pnext_qh
= uhci
->skel_hs_control_qh
;
2755 ListFirstPrev(&pskel_qh
->pqhe
->hori_link
, pthis
);
2758 pthis
= &pskel_qh
->pqhe
->hori_link
;
2760 InsertTailList(&pskel_qh
->pqhe
->hori_link
, &pqh
->pqhe
->hori_link
);
2761 pqh
->link
= pnext_qh
->phy_addr
;
2762 struct_ptr(pthis
, QH_EXTENSION
, hori_link
)->pqh
->link
= pqh
->phy_addr
;
2764 //full speed band reclaimation
2765 if ((urb
->pipe
& USB_DEV_FLAG_LOW_SPEED
) == 0)
2768 if (uhci
->fsbr_cnt
== 1)
2770 uhci
->skel_term_qh
->link
= uhci
->skel_hs_control_qh
->phy_addr
;
2775 case USB_ENDPOINT_XFER_BULK
:
2777 pqh
= ((PQH_EXTENSION
) pthis
)->pqh
;
2779 ListFirstPrev(&uhci
->skel_bulk_qh
->pqhe
->hori_link
, pthis
);
2782 pthis
= &uhci
->skel_bulk_qh
->pqhe
->hori_link
;
2784 InsertTailList(&uhci
->skel_bulk_qh
->pqhe
->hori_link
, &pqh
->pqhe
->hori_link
);
2786 pqh
->link
= uhci
->skel_term_qh
->phy_addr
;
2787 struct_ptr(pthis
, QH_EXTENSION
, hori_link
)->pqh
->link
= pqh
->phy_addr
;
2789 //full speed band reclaimation
2791 if (uhci
->fsbr_cnt
== 1)
2793 uhci
->skel_term_qh
->link
= uhci
->skel_hs_control_qh
->phy_addr
;
2798 case USB_ENDPOINT_XFER_INT
:
2800 //bandwidth claim is done outside
2801 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2803 get_int_idx(urb
, i
);
2805 ListFirstPrev(&uhci
->skel_td
[i
]->ptde
->hori_link
, pthis
);
2807 pthis
= &uhci
->skel_td
[i
]->ptde
->hori_link
;
2809 InsertTailList(&uhci
->skel_td
[i
]->ptde
->hori_link
, &ptd
->ptde
->hori_link
);
2813 ptd
->link
= uhci
->skel_td
[i
- 1]->phy_addr
;
2817 ptd
->link
= uhci
->skel_qh
[0]->phy_addr
;
2819 //finally link the previous td to this td
2820 struct_ptr(pthis
, TD_EXTENSION
, hori_link
)->ptd
->link
= ptd
->phy_addr
;
2823 case USB_ENDPOINT_XFER_ISOC
:
2826 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
2828 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
2829 InsertTailList(&uhci
->frame_list_cpu
[(urb
->iso_start_frame
+ i
) & 0x3ff].td_link
,
2830 &ptd
->ptde
->hori_link
);
2832 if (IsListEmpty(&uhci
->frame_list_cpu
[(urb
->iso_start_frame
+ i
) & 0x3ff].td_link
) == TRUE
)
2834 ptd
->link
= uhci
->frame_list
[(urb
->iso_start_frame
+ i
) & 0x3ff];
2835 uhci
->frame_list
[i
] = ptd
->phy_addr
;
2839 ListFirstPrev(&uhci
->frame_list_cpu
[(urb
->iso_start_frame
+ i
) & 0x3ff].td_link
, pnext
);
2840 plast_td
= struct_ptr(pnext
, TD_EXTENSION
, hori_link
)->ptd
;
2841 ptd
->link
= plast_td
->link
;
2842 plast_td
->link
= ptd
->phy_addr
;
2845 ListNext(&urb
->trasac_list
, pthis
, pnext
);
2855 //this function used as the KeSynchronizeExecution param to delegate control to uhci_insert_urb_schedule
2857 uhci_sync_insert_urb_schedule(PVOID context
)
2859 PSYNC_PARAM sync_param
;
2863 sync_param
= (PSYNC_PARAM
) context
;
2864 if (sync_param
== NULL
)
2867 uhci
= sync_param
->uhci
;
2868 purb
= (PURB
) sync_param
->context
;
2870 if (uhci
== NULL
|| purb
== NULL
)
2871 return (UCHAR
) (sync_param
->ret
= FALSE
);
2873 return (UCHAR
) (sync_param
->ret
= uhci_insert_urb_schedule(uhci
, purb
));
2876 // be sure pending_endp_list_lock acquired
2878 uhci_claim_bandwidth(PUHCI_DEV uhci
,
2880 BOOLEAN claim_bw
//true to claim bandwidth, false to free bandwidth
2885 BOOLEAN ls
, can_alloc
;
2887 LONG i
, idx
, j
, start_frame
, interval
;
2894 type
= (UCHAR
) (urb
->pipe
& USB_ENDPOINT_XFERTYPE_MASK
);
2895 if (type
== USB_ENDPOINT_XFER_BULK
|| type
== USB_ENDPOINT_XFER_CONTROL
)
2900 ls
= (urb
->pipe
& USB_DEV_FLAG_LOW_SPEED
) ? TRUE
: FALSE
;
2902 if (type
== USB_ENDPOINT_XFER_INT
)
2905 i
= urb
->data_length
;
2906 bus_time
= usb_calc_bus_time(ls
, FALSE
, FALSE
, i
);
2907 us
= ns_to_us(bus_time
);
2909 i
= (urb
->pipe
>> 24); //polling interval
2911 for(interval
= 0, j
= 0; j
< 8; j
++)
2919 interval
= 1 << interval
;
2920 start_frame
= interval
- 1;
2925 for(idx
= 0; idx
< UHCI_MAX_FRAMES
; idx
+= interval
)
2927 if (uhci
->frame_bw
[idx
] < us
)
2939 for(idx
= start_frame
; idx
< UHCI_MAX_FRAMES
; idx
+= interval
)
2941 uhci
->frame_bw
[idx
] -= us
;
2946 for(idx
= start_frame
; idx
< UHCI_MAX_FRAMES
; idx
+= interval
)
2948 uhci
->frame_bw
[idx
] += us
;
2953 else if (type
== USB_ENDPOINT_XFER_ISOC
)
2957 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
2959 bus_time
= usb_calc_bus_time(FALSE
,
2960 (urb
->pipe
& USB_DIR_IN
)
2961 ? TRUE
: FALSE
, TRUE
, urb
->iso_packet_desc
[i
].length
);
2963 urb
->iso_packet_desc
[i
].bus_time
= ns_to_us(bus_time
);
2966 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
2968 if (uhci
->frame_bw
[(urb
->iso_start_frame
+ i
) & 0x3ff] < urb
->iso_packet_desc
[i
].bus_time
)
2980 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
2982 uhci
->frame_bw
[(urb
->iso_start_frame
+ i
) & 0x3ff] -= urb
->iso_packet_desc
[i
].bus_time
;
2987 for(i
= 0; i
< urb
->iso_frame_count
; i
++)
2989 uhci
->frame_bw
[(urb
->iso_start_frame
+ i
) & 0x3ff] += urb
->iso_packet_desc
[i
].bus_time
;
2999 //cancel a single urb
3001 uhci_sync_cancel_urb(PVOID context
)
3004 PSYNC_PARAM sync_param
;
3005 PURB purb2
, dest_urb
;
3006 PLIST_ENTRY pthis
, pnext
;
3007 BOOLEAN found
= FALSE
;
3009 if (context
== NULL
)
3012 sync_param
= (PSYNC_PARAM
) context
;
3013 uhci
= sync_param
->uhci
;
3014 dest_urb
= (PURB
) sync_param
->context
;
3016 if (uhci
== NULL
|| dest_urb
== NULL
)
3017 return (UCHAR
) (sync_param
->ret
= FALSE
);
3019 ListFirst(&uhci
->urb_list
, pthis
);
3022 purb2
= (PURB
) pthis
;
3023 if (purb2
== dest_urb
)
3026 purb2
->flags
|= URB_FLAG_FORCE_CANCEL
;
3029 ListNext(&uhci
->urb_list
, pthis
, pnext
);
3033 uhci
->skel_term_td
->status
|= TD_CTRL_IOC
;
3035 return (UCHAR
) (sync_param
->ret
= found
);
3038 //note any fields of the purb can not be referenced unless it is found in some queue
3040 uhci_cancel_urb(PUHCI_DEV uhci
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
3042 PLIST_ENTRY pthis
, pnext
;
3046 SYNC_PARAM sync_param
;
3048 USE_BASIC_NON_PENDING_IRQL
;
3050 if (uhci
== NULL
|| purb
== NULL
|| pdev
== NULL
|| pendp
== NULL
)
3051 return STATUS_INVALID_PARAMETER
;
3053 lock_dev(pdev
, FALSE
);
3055 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
3057 unlock_dev(pdev
, FALSE
);
3058 //delegate to remove device for this job
3059 return STATUS_DEVICE_DOES_NOT_EXIST
;
3062 if (dev_from_endp(pendp
) != pdev
)
3064 unlock_dev(pdev
, FALSE
);
3065 return STATUS_INVALID_PARAMETER
;
3068 if (endp_state(pendp
) == USB_ENDP_FLAG_STALL
)
3070 //it will be canceled in uhci_process_pending_endp
3071 unlock_dev(pdev
, FALSE
);
3072 return USB_STATUS_ENDPOINT_HALTED
;
3076 ListFirst(&pendp
->urb_list
, pthis
);
3079 purb2
= (PURB
) pthis
;
3083 RemoveEntryList(pthis
);
3084 InitializeListHead(pthis
);
3087 ListNext(&pendp
->urb_list
, pthis
, pnext
);
3090 unlock_dev(pdev
, FALSE
);
3094 purb
->status
= STATUS_CANCELLED
;
3096 uhci_generic_urb_completion(purb
, purb
->context
);
3098 lock_dev(pdev
, FALSE
);
3100 unlock_dev(pdev
, FALSE
);
3101 return STATUS_SUCCESS
;
3104 // search the urb in the urb-list and try to cancel
3105 sync_param
.uhci
= uhci
;
3106 sync_param
.context
= purb
;
3108 KeSynchronizeExecution(uhci
->pdev_ext
->uhci_int
, uhci_sync_cancel_urb
, &sync_param
);
3110 found
= (BOOLEAN
) sync_param
.ret
;
3113 return USB_STATUS_CANCELING
;
3115 return STATUS_INVALID_PARAMETER
;
3119 uhci_generic_urb_completion(PURB purb
, PVOID context
)
3122 USE_NON_PENDING_IRQL
;
3124 old_irql
= KeGetCurrentIrql();
3125 if (old_irql
> DISPATCH_LEVEL
)
3128 if (old_irql
< DISPATCH_LEVEL
)
3129 KeRaiseIrql(DISPATCH_LEVEL
, &old_irql
);
3139 lock_dev(pdev
, TRUE
);
3141 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
3143 unlock_dev(pdev
, TRUE
);
3144 goto LBL_CLIENT_PROCESS
;
3146 if (usb_error(purb
->status
))
3148 pdev
->error_count
++;
3151 if (purb
->pendp
== &pdev
->default_endp
)
3153 if (usb_halted(purb
->status
))
3155 pdev
->time_out_count
++;
3156 if (pdev
->time_out_count
> 3)
3158 dev_set_state(pdev
, USB_DEV_STATE_ZOMB
);
3159 uhci_dbg_print(DBGLVL_MAXIMUM
,
3160 ("uhci_generic_urb_completion(): contiguous error 3 times, dev 0x%x is deactivated\n",
3165 pdev
->time_out_count
= 0;
3168 unlock_dev(pdev
, TRUE
);
3171 if (purb
->completion
)
3172 purb
->completion(purb
, context
);
3174 if (old_irql
< DISPATCH_LEVEL
)
3175 KeLowerIrql(old_irql
);
3182 uhci_rh_submit_urb(PUSB_DEV pdev
, PURB purb
)
3184 PUSB_DEV_MANAGER dev_mgr
;
3186 PUSB_CTRL_SETUP_PACKET psetup
;
3190 #ifndef INCLUDE_EHCI
3191 PHUB_EXTENSION hub_ext
;
3193 PHUB2_EXTENSION hub_ext
;
3195 PUSB_PORT_STATUS ps
, psret
;
3197 USE_NON_PENDING_IRQL
;
3199 if (pdev
== NULL
|| purb
== NULL
)
3200 return STATUS_INVALID_PARAMETER
;
3202 dev_mgr
= dev_mgr_from_dev(pdev
);
3204 KeAcquireSpinLock(&dev_mgr
->timer_svc_list_lock
, &old_irql
);
3205 lock_dev(pdev
, FALSE
);
3206 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
3208 unlock_dev(pdev
, FALSE
);
3209 KeReleaseSpinLock(&dev_mgr
->timer_svc_list_lock
, old_irql
);
3210 return STATUS_DEVICE_DOES_NOT_EXIST
;
3213 uhci
= uhci_from_hcd(pdev
->hcd
);
3214 psetup
= (PUSB_CTRL_SETUP_PACKET
) purb
->setup_packet
;
3216 #ifndef INCLUDE_EHCI
3217 hub_ext
= ((PHUB_EXTENSION
) pdev
->dev_ext
);
3219 hub_ext
= ((PHUB2_EXTENSION
) pdev
->dev_ext
);
3222 switch (endp_type(purb
->pendp
))
3224 case USB_ENDPOINT_XFER_CONTROL
:
3226 if (psetup
->bmRequestType
== 0xa3 && psetup
->bRequest
== USB_REQ_GET_STATUS
)
3229 if (psetup
->wIndex
== 0 || psetup
->wIndex
> 2 || psetup
->wLength
< 4)
3231 purb
->status
= STATUS_INVALID_PARAMETER
;
3234 if (psetup
->wIndex
== 1)
3236 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC1
));
3237 ps
= &hub_ext
->rh_port1_status
;
3241 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC2
));
3242 ps
= &hub_ext
->rh_port2_status
;
3245 psret
= (PUSB_PORT_STATUS
) purb
->data_buffer
;
3246 ps
->wPortStatus
= 0;
3248 if (status
& USBPORTSC_CCS
)
3250 ps
->wPortStatus
|= USB_PORT_STAT_CONNECTION
;
3252 if (status
& USBPORTSC_PE
)
3254 ps
->wPortStatus
|= USB_PORT_STAT_ENABLE
;
3256 if (status
& USBPORTSC_PR
)
3258 ps
->wPortStatus
|= USB_PORT_STAT_RESET
;
3260 if (status
& USBPORTSC_SUSP
)
3262 ps
->wPortStatus
|= USB_PORT_STAT_SUSPEND
;
3264 if (status
& USBPORTSC_LSDA
)
3266 ps
->wPortStatus
|= USB_PORT_STAT_LOW_SPEED
;
3270 ps
->wPortStatus
|= USB_PORT_STAT_POWER
;
3272 //now set change field
3273 if (status
& USBPORTSC_CSC
)
3275 ps
->wPortChange
|= USB_PORT_STAT_C_CONNECTION
;
3277 if (status
& USBPORTSC_PEC
)
3279 ps
->wPortChange
|= USB_PORT_STAT_C_ENABLE
;
3282 //don't touch other fields, will be filled by
3285 usb_dbg_print(DBGLVL_MAXIMUM
,
3286 ("uhci_rh_submit_urb(): get port status, wPortStatus=0x%x, wPortChange=0x%x, address=0x%x\n",
3287 ps
->wPortStatus
, ps
->wPortChange
, ps
));
3289 psret
->wPortChange
= ps
->wPortChange
;
3290 psret
->wPortStatus
= ps
->wPortStatus
;
3292 purb
->status
= STATUS_SUCCESS
;
3296 else if (psetup
->bmRequestType
== 0x23 && psetup
->bRequest
== USB_REQ_CLEAR_FEATURE
)
3298 //clear-port-feature
3299 if (psetup
->wIndex
== 0 || psetup
->wIndex
> 2)
3301 purb
->status
= STATUS_INVALID_PARAMETER
;
3304 if (psetup
->wIndex
== 1)
3307 ps
= &hub_ext
->rh_port1_status
;
3312 ps
= &hub_ext
->rh_port2_status
;
3315 purb
->status
= STATUS_SUCCESS
;
3316 switch (psetup
->wValue
)
3318 case USB_PORT_FEAT_C_CONNECTION
:
3320 ps
->wPortChange
&= ~USB_PORT_STAT_C_CONNECTION
;
3321 SET_RH_PORTSTAT(i
, USBPORTSC_CSC
);
3322 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3323 usb_dbg_print(DBGLVL_MAXIMUM
,
3324 ("uhci_rh_submit_urb(): clear csc, port%d=0x%x\n", psetup
->wIndex
,
3328 case USB_PORT_FEAT_C_ENABLE
:
3330 ps
->wPortChange
&= ~USB_PORT_STAT_C_ENABLE
;
3331 SET_RH_PORTSTAT(i
, USBPORTSC_PEC
);
3332 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3333 usb_dbg_print(DBGLVL_MAXIMUM
,
3334 ("uhci_rh_submit_urb(): clear pec, port%d=0x%x\n", psetup
->wIndex
,
3338 case USB_PORT_FEAT_C_RESET
:
3340 ps
->wPortChange
&= ~USB_PORT_STAT_C_RESET
;
3341 //the reset signal is down in rh_timer_svc_reset_port_completion
3342 //so enable the port here
3343 status
= READ_PORT_USHORT((PUSHORT
)(uhci
->port_base
+ i
));
3344 usb_dbg_print(DBGLVL_MAXIMUM
,
3345 ("uhci_rh_submit_urb(): clear pr, enable pe, port%d=0x%x\n",
3346 psetup
->wIndex
, status
));
3349 case USB_PORT_FEAT_ENABLE
:
3351 ps
->wPortStatus
&= ~USB_PORT_STAT_ENABLE
;
3352 CLR_RH_PORTSTAT(i
, USBPORTSC_PE
);
3353 status
= READ_PORT_USHORT((PUSHORT
)(uhci
->port_base
+ i
));
3354 usb_dbg_print(DBGLVL_MAXIMUM
,
3355 ("uhci_rh_submit_urb(): clear pe, port%d=0x%x\n", psetup
->wIndex
,
3360 purb
->status
= STATUS_UNSUCCESSFUL
;
3364 else if (psetup
->bmRequestType
== 0xd3 && psetup
->bRequest
== HUB_REQ_GET_STATE
)
3367 if (psetup
->wIndex
== 0 || psetup
->wIndex
> 2 || psetup
->wLength
== 0)
3369 purb
->status
= STATUS_INVALID_PARAMETER
;
3373 if (psetup
->wIndex
== 1)
3381 port_status
= READ_PORT_USHORT((PUSHORT
)(uhci
->port_base
+ i
));
3382 purb
->data_buffer
[0] = (port_status
& USBPORTSC_LS
);
3384 // reverse the order
3385 purb
->data_buffer
[0] ^= 0x3;
3386 purb
->status
= STATUS_SUCCESS
;
3389 else if (psetup
->bmRequestType
== 0x23 && psetup
->bRequest
== USB_REQ_SET_FEATURE
)
3392 if (psetup
->wValue
!= USB_PORT_FEAT_RESET
)
3394 purb
->status
= STATUS_INVALID_PARAMETER
;
3395 uhci_dbg_print(DBGLVL_MAXIMUM
,
3396 ("uhci_rh_submit_urb(): set feature with wValue=0x%x\n", psetup
->wValue
));
3399 if (psetup
->wIndex
== 1)
3408 ptimer
= alloc_timer_svc(&dev_mgr
->timer_svc_pool
, 1);
3411 purb
->status
= STATUS_NO_MEMORY
;
3415 ptimer
->threshold
= 0; // within [ 50ms, 60ms ], one tick is 10 ms
3416 ptimer
->context
= (ULONG
) purb
;
3417 ptimer
->pdev
= pdev
;
3418 ptimer
->func
= rh_timer_svc_reset_port_completion
;
3421 pdev
->ref_count
+= 2; //one for timer and one for urb
3423 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3424 usb_dbg_print(DBGLVL_MAXIMUM
,
3425 ("uhci_rh_submit_urb(): reset port, port%d=0x%x\n", psetup
->wIndex
, status
));
3426 InsertTailList(&dev_mgr
->timer_svc_list
, &ptimer
->timer_svc_link
);
3427 purb
->status
= STATUS_PENDING
;
3431 purb
->status
= STATUS_INVALID_PARAMETER
;
3435 case USB_ENDPOINT_XFER_INT
:
3437 ptimer
= alloc_timer_svc(&dev_mgr
->timer_svc_pool
, 1);
3440 purb
->status
= STATUS_NO_MEMORY
;
3444 ptimer
->threshold
= RH_INTERVAL
;
3445 ptimer
->context
= (ULONG
) purb
;
3446 ptimer
->pdev
= pdev
;
3447 ptimer
->func
= rh_timer_svc_int_completion
;
3450 InsertTailList(&dev_mgr
->timer_svc_list
, &ptimer
->timer_svc_link
);
3452 usb_dbg_print(DBGLVL_ULTRA
,
3453 ("uhci_rh_submit_urb(): current rh's ref_count=0x%x\n", pdev
->ref_count
));
3454 pdev
->ref_count
+= 2; //one for timer and one for urb
3456 purb
->status
= STATUS_PENDING
;
3459 case USB_ENDPOINT_XFER_BULK
:
3460 case USB_ENDPOINT_XFER_ISOC
:
3463 purb
->status
= STATUS_INVALID_PARAMETER
;
3467 unlock_dev(pdev
, FALSE
);
3468 KeReleaseSpinLock(&dev_mgr
->timer_svc_list_lock
, old_irql
);
3469 return purb
->status
;
3472 //must have rh dev_lock acquired
3474 uhci_rh_reset_port(PHCD hcd
, UCHAR port_idx
)
3480 if (port_idx
!= 1 && port_idx
!= 2)
3495 uhci
= uhci_from_hcd(hcd
);
3496 //assert the reset signal,(implicitly disable the port)
3497 SET_RH_PORTSTAT(i
, USBPORTSC_PR
);
3498 usb_wait_ms_dpc(50);
3499 //clear the reset signal, delay port enable till clearing port feature
3500 CLR_RH_PORTSTAT(i
, USBPORTSC_PR
);
3501 usb_wait_us_dpc(10);
3502 SET_RH_PORTSTAT(i
, USBPORTSC_PE
);
3503 //recovery time 10ms
3504 usb_wait_ms_dpc(10);
3505 SET_RH_PORTSTAT(i
, 0x0a);
3507 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3508 usb_dbg_print(DBGLVL_MAXIMUM
, ("uhci_rh_reset_port(): status after written=0x%x\n", status
));
3514 uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject
, IN PIRP irp
)
3516 PDEVICE_EXTENSION pdev_ext
;
3517 PUSB_DEV_MANAGER dev_mgr
;
3520 pdev_ext
= DeviceObject
->DeviceExtension
;
3521 uhci
= pdev_ext
->uhci
;
3523 dev_mgr
= uhci
->hcd_interf
.hcd_get_dev_mgr(&uhci
->hcd_interf
);
3524 return dev_mgr_dispatch(dev_mgr
, irp
);
3528 uhci_unload(IN PDRIVER_OBJECT DriverObject
)
3530 PDEVICE_OBJECT pdev
;
3531 PDEVICE_EXTENSION pdev_ext
;
3532 PUSB_DEV_MANAGER dev_mgr
;
3534 pdev
= DriverObject
->DeviceObject
;
3539 pdev_ext
= pdev
->DeviceExtension
;
3540 if (pdev_ext
== NULL
)
3543 dev_mgr
= &g_dev_mgr
;
3544 if (dev_mgr
== NULL
)
3547 // set the termination flag
3549 dev_mgr
->term_flag
= TRUE
;
3552 // wake up the thread if it is
3554 KeSetEvent(&dev_mgr
->wake_up_event
, 0, FALSE
);
3555 KeWaitForSingleObject(dev_mgr
->pthread
, Executive
, KernelMode
, TRUE
, NULL
);
3556 ObDereferenceObject(dev_mgr
->pthread
);
3557 dev_mgr
->pthread
= NULL
;
3558 // for( i = 0; i < dev_mgr->hcd_count; i++ )
3559 // dev_mgr->hcd_array[ i ]->hcd_release( dev_mgr->hcd_array[ i ]);
3560 dev_mgr_release_hcd(dev_mgr
);
3565 //the following are for hcd interface methods
3567 uhci_set_dev_mgr(struct _HCD
* hcd
, PUSB_DEV_MANAGER dev_mgr
)
3569 hcd
->dev_mgr
= dev_mgr
;
3573 uhci_get_dev_mgr(struct _HCD
*hcd
)
3575 return hcd
->dev_mgr
;
3579 uhci_get_type(struct _HCD
* hcd
)
3581 return (hcd
->flags
& HCD_TYPE_MASK
);
3585 uhci_set_id(struct _HCD
* hcd
, UCHAR id
)
3587 hcd
->flags
&= ~HCD_ID_MASK
;
3588 hcd
->flags
|= (HCD_ID_MASK
& id
);
3592 uhci_get_id(struct _HCD
*hcd
)
3594 return (UCHAR
) (hcd
->flags
& HCD_ID_MASK
);
3599 uhci_alloc_addr(struct _HCD
* hcd
)
3605 for(i
= 1; i
< MAX_DEVS
; i
++)
3607 if (hcd
->dev_addr_map
[i
>> 3] & (1 << (i
& 7)))
3620 hcd
->dev_addr_map
[i
>> 3] |= (1 << (i
& 7));
3626 uhci_free_addr(struct _HCD
* hcd
, UCHAR addr
)
3634 hcd
->dev_addr_map
[addr
>> 3] &= ~(1 << (addr
& 7));
3640 uhci_submit_urb2(struct _HCD
* hcd
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
3642 return uhci_submit_urb(uhci_from_hcd(hcd
), pdev
, pendp
, purb
);
3646 uhci_get_root_hub(struct _HCD
* hcd
)
3648 return uhci_from_hcd(hcd
)->root_hub
;
3652 uhci_set_root_hub(struct _HCD
* hcd
, PUSB_DEV root_hub
)
3654 if (hcd
== NULL
|| root_hub
== NULL
)
3656 uhci_from_hcd(hcd
)->root_hub
= root_hub
;
3661 uhci_remove_device2(struct _HCD
* hcd
, PUSB_DEV pdev
)
3663 if (hcd
== NULL
|| pdev
== NULL
)
3666 return uhci_remove_device(uhci_from_hcd(hcd
), pdev
);
3670 uhci_hcd_release(struct _HCD
* hcd
)
3673 PDEVICE_EXTENSION pdev_ext
;
3679 uhci
= uhci_from_hcd(hcd
);
3680 pdev_ext
= uhci
->pdev_ext
;
3682 return uhci_release(pdev_ext
->pdev_obj
);
3686 uhci_cancel_urb2(struct _HCD
* hcd
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
3690 return STATUS_INVALID_PARAMETER
;
3692 uhci
= uhci_from_hcd(hcd
);
3693 return uhci_cancel_urb(uhci
, pdev
, pendp
, purb
);
3697 uhci_rh_get_dev_change(PHCD hcd
, PBYTE buf
)
3702 if (hcd
== NULL
|| buf
== NULL
)
3705 uhci
= uhci_from_hcd(hcd
);
3706 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC1
));
3707 usb_dbg_print(DBGLVL_ULTRA
, ("uhci_rh_get_dev_change(): rh port1 status=0x%x\n", status
));
3709 if ((status
& USBPORTSC_PEC
) || (status
& USBPORTSC_CSC
))
3714 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC2
));
3715 usb_dbg_print(DBGLVL_ULTRA
, ("uhci_rh_get_dev_change(): rh port2 status=0x%x\n", status
));
3717 if ((status
& USBPORTSC_PEC
) || (status
& USBPORTSC_CSC
))
3725 uhci_dispatch(PHCD hcd
, LONG disp_code
, PVOID param
) // locking depends on type of code
3732 case HCD_DISP_READ_PORT_COUNT
:
3735 return STATUS_INVALID_PARAMETER
;
3736 *((PUCHAR
) param
) = 2;
3737 return STATUS_SUCCESS
;
3739 case HCD_DISP_READ_RH_DEV_CHANGE
:
3741 if (uhci_rh_get_dev_change(hcd
, param
) == FALSE
)
3742 return STATUS_INVALID_PARAMETER
;
3743 return STATUS_SUCCESS
;
3747 return STATUS_NOT_IMPLEMENTED
;
3751 uhci_init_hcd_interface(PUHCI_DEV uhci
)
3753 uhci
->hcd_interf
.hcd_set_dev_mgr
= uhci_set_dev_mgr
;
3754 uhci
->hcd_interf
.hcd_get_dev_mgr
= uhci_get_dev_mgr
;
3755 uhci
->hcd_interf
.hcd_get_type
= uhci_get_type
;
3756 uhci
->hcd_interf
.hcd_set_id
= uhci_set_id
;
3757 uhci
->hcd_interf
.hcd_get_id
= uhci_get_id
;
3758 uhci
->hcd_interf
.hcd_alloc_addr
= uhci_alloc_addr
;
3759 uhci
->hcd_interf
.hcd_free_addr
= uhci_free_addr
;
3760 uhci
->hcd_interf
.hcd_submit_urb
= uhci_submit_urb2
;
3761 uhci
->hcd_interf
.hcd_generic_urb_completion
= uhci_generic_urb_completion
;
3762 uhci
->hcd_interf
.hcd_get_root_hub
= uhci_get_root_hub
;
3763 uhci
->hcd_interf
.hcd_set_root_hub
= uhci_set_root_hub
;
3764 uhci
->hcd_interf
.hcd_remove_device
= uhci_remove_device2
;
3765 uhci
->hcd_interf
.hcd_rh_reset_port
= uhci_rh_reset_port
;
3766 uhci
->hcd_interf
.hcd_release
= uhci_hcd_release
;
3767 uhci
->hcd_interf
.hcd_cancel_urb
= uhci_cancel_urb2
;
3768 uhci
->hcd_interf
.hcd_start
= uhci_start
;
3769 uhci
->hcd_interf
.hcd_dispatch
= uhci_dispatch
;
3771 uhci
->hcd_interf
.flags
= HCD_TYPE_UHCI
; //hcd types | hcd id
3775 generic_dispatch_irp(IN PDEVICE_OBJECT dev_obj
, IN PIRP irp
)
3777 PDEVEXT_HEADER dev_ext
;
3779 dev_ext
= (PDEVEXT_HEADER
) dev_obj
->DeviceExtension
;
3781 if (dev_ext
&& dev_ext
->dispatch
)
3782 return dev_ext
->dispatch(dev_obj
, irp
);
3784 irp
->IoStatus
.Information
= 0;
3786 EXIT_DISPATCH(STATUS_UNSUCCESSFUL
, irp
);
3791 generic_start_io(IN PDEVICE_OBJECT dev_obj
, IN PIRP irp
)
3793 PDEVEXT_HEADER dev_ext
;
3797 IoAcquireCancelSpinLock(&old_irql
);
3798 if (irp
!= dev_obj
->CurrentIrp
|| irp
->Cancel
)
3800 IoReleaseCancelSpinLock(old_irql
);
3805 (void)IoSetCancelRoutine(irp
, NULL
);
3806 IoReleaseCancelSpinLock(old_irql
);
3809 dev_ext
= (PDEVEXT_HEADER
) dev_obj
->DeviceExtension
;
3811 if (dev_ext
&& dev_ext
->start_io
)
3813 dev_ext
->start_io(dev_obj
, irp
);
3817 irp
->IoStatus
.Information
= 0;
3818 irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3820 IoStartNextPacket(dev_obj
, FALSE
);
3821 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
3826 DriverEntry(IN PDRIVER_OBJECT DriverObject
, IN PUNICODE_STRING RegistryPath
)
3828 NTSTATUS ntStatus
= STATUS_SUCCESS
;
3831 // should be done before any debug output is done.
3832 // read our debug verbosity level from the registry
3833 //NetacOD_GetRegistryDword( NetacOD_REGISTRY_PARAMETERS_PATH, //absolute registry path
3834 // L"DebugLevel", // REG_DWORD ValueName
3835 // &gDebugLevel ); // Value receiver
3837 // debug_level = DBGLVL_MAXIMUM;
3840 uhci_dbg_print_cond(DBGLVL_MINIMUM
, DEBUG_UHCI
,
3841 ("Entering DriverEntry(), RegistryPath=\n %ws\n", RegistryPath
->Buffer
));
3843 // Remember our driver object, for when we create our child PDO
3844 usb_driver_obj
= DriverObject
;
3847 // Create dispatch points for create, close, unload
3848 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = generic_dispatch_irp
;
3849 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = generic_dispatch_irp
;
3850 DriverObject
->DriverUnload
= uhci_unload
;
3852 // User mode DeviceIoControl() calls will be routed here
3853 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = generic_dispatch_irp
;
3854 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = generic_dispatch_irp
;
3856 // User mode ReadFile()/WriteFile() calls will be routed here
3857 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = generic_dispatch_irp
;
3858 DriverObject
->MajorFunction
[IRP_MJ_READ
] = generic_dispatch_irp
;
3860 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = generic_dispatch_irp
;
3861 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = generic_dispatch_irp
;
3862 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = generic_dispatch_irp
;
3864 DriverObject
->DriverStartIo
= generic_start_io
;
3865 // routines for handling system PNP and power management requests
3866 //DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = generic_dispatch_irp;
3868 // The Functional Device Object (FDO) will not be created for PNP devices until
3869 // this routine is called upon device plug-in.
3870 RtlZeroMemory(&g_dev_mgr
, sizeof(USB_DEV_MANAGER
));
3871 g_dev_mgr
.usb_driver_obj
= DriverObject
;
3874 ehci_probe(DriverObject
, RegistryPath
, &g_dev_mgr
);
3877 uhci_probe(DriverObject
, RegistryPath
, &g_dev_mgr
);
3879 if (dev_mgr_strobe(&g_dev_mgr
) == FALSE
)
3882 dev_mgr_release_hcd(&g_dev_mgr
);
3883 return STATUS_UNSUCCESSFUL
;
3886 dev_mgr_start_hcd(&g_dev_mgr
);
3888 /* Wait till all drivers are initialized */
3889 ntStatus
= KeWaitForSingleObject(&g_dev_mgr
.drivers_inited
, Executive
, KernelMode
, TRUE
, NULL
);
3891 uhci_dbg_print_cond(DBGLVL_DEFAULT
, DEBUG_UHCI
, ("DriverEntry(): exiting... (%x)\n", ntStatus
));
3892 return STATUS_SUCCESS
;
3895 //note: the initialization will be in the following order
3900 // to kill dev_mgr_thread:
3901 // dev_mgr->term_flag = TRUE;
3902 // KeSetEvent( &dev_mgr->wake_up_event );
3903 // this piece of code must run at passive-level