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
, (PLIST_ENTRY
) & pending_endp
->endp_link
);
190 alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool
, LONG count
)
192 PUHCI_PENDING_ENDP
new;
193 if (pool
== NULL
|| count
!= 1)
196 if (pool
->free_count
<= 0)
199 new = (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 bus to find uhci controller
630 for(bus
= 0; bus
< 2; bus
++) /*enum only bus0 and bus1 */
632 for(i
= 0; i
< PCI_MAX_DEVICES
; i
++)
634 slot_num
.u
.bits
.DeviceNumber
= i
;
635 for(j
= 0; j
< PCI_MAX_FUNCTIONS
; 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)
650 // well, we find our usb host controller, create device
653 pdev
= uhci_alloc(drvr_obj
, reg_path
, ((bus
<< 8) | (i
<< 3) | j
), dev_mgr
);
659 pdev
= uhci_alloc(drvr_obj
, reg_path
, ((bus
<< 8) | (i
<< 3) | j
), dev_mgr
);
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
);
701 pdev_ext
= pdev
->DeviceExtension
;
703 pdev_ext
->pci_addr
= bus_addr
;
704 bus
= (bus_addr
>> 8);
706 slot_num
.u
.AsULONG
= 0;
707 slot_num
.u
.bits
.DeviceNumber
= ((bus_addr
& 0xff) >> 3);
708 slot_num
.u
.bits
.FunctionNumber
= (bus_addr
& 0x07);
713 //now create adapter object
714 RtlZeroMemory(&dev_desc
, sizeof(dev_desc
));
716 dev_desc
.Version
= DEVICE_DESCRIPTION_VERSION
;
717 dev_desc
.Master
= TRUE
;
718 dev_desc
.ScatterGather
= TRUE
;
719 dev_desc
.Dma32BitAddresses
= TRUE
;
720 dev_desc
.BusNumber
= bus
;
721 dev_desc
.InterfaceType
= PCIBus
;
722 dev_desc
.MaximumLength
=
723 UHCI_MAX_POOL_TDS
* sizeof(UHCI_TD
) * UHCI_MAX_TD_POOLS
724 + sizeof(UHCI_QH
) * UHCI_MAX_POOL_QHS
+ sizeof(ULONG
) * UHCI_MAX_FRAMES
;
726 pdev_ext
->map_regs
= 2; // UHCI_MAX_TD_POOLS +
727 //+ BYTES_TO_PAGES( ( UHCI_MAX_POOL_TDS * 64 ) * UHCI_MAX_TD_POOLS ) ;
729 pdev_ext
->padapter
= HalGetAdapter(&dev_desc
, &pdev_ext
->map_regs
);
731 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_alloc(): padapter=0x%x\n", pdev_ext
->padapter
));
732 if (pdev_ext
->padapter
== NULL
)
735 uhci_delete_device(pdev
);
739 DbgPrint("uhci_alloc(): reg_path=%p, \n \
740 uhci_alloc(): PCIBus=0x%x, bus=0x%x, bus_addr=0x%x \n \
741 uhci_alloc(): slot_num=0x%x, &res_list=%p \n", reg_path
, (DWORD
) PCIBus
, (DWORD
) bus
,
742 (DWORD
) bus_addr
, (DWORD
) slot_num
.u
.AsULONG
, & pdev_ext
->res_list
);
744 //let's allocate resources for this device
745 DbgPrint("uhci_alloc(): about to assign slot res\n");
746 if ((status
= HalAssignSlotResources(reg_path
, NULL
, //no class name yet
747 drvr_obj
, NULL
, //no support of another uhci controller
749 bus
, slot_num
.u
.AsULONG
, &pdev_ext
->res_list
)) != STATUS_SUCCESS
)
751 DbgPrint("uhci_alloc(): error assign slot res, 0x%x\n", status
);
752 release_adapter(pdev_ext
->padapter
);
753 pdev_ext
->padapter
= NULL
;
754 uhci_delete_device(pdev
);
758 //parse the resource list
759 for(frd_num
= 0; frd_num
< (LONG
) pdev_ext
->res_list
->Count
; frd_num
++)
761 for(prd_num
= 0; prd_num
< (LONG
) pdev_ext
->res_list
->List
[frd_num
].PartialResourceList
.Count
;
764 pprd
= &pdev_ext
->res_list
->List
[frd_num
].PartialResourceList
.PartialDescriptors
[prd_num
];
765 if (pprd
->Type
== CmResourceTypePort
)
767 RtlCopyMemory(&pdev_ext
->res_port
, &pprd
->u
.Port
, sizeof(pprd
->u
.Port
));
769 else if (pprd
->Type
== CmResourceTypeInterrupt
)
771 RtlCopyMemory(&pdev_ext
->res_interrupt
, &pprd
->u
.Interrupt
, sizeof(pprd
->u
.Interrupt
));
776 //for port, translate them to system address
778 if (HalTranslateBusAddress(PCIBus
, bus
, pdev_ext
->res_port
.Start
, &addr_space
, //io space
779 &pdev_ext
->uhci
->uhci_reg_base
) != (BOOLEAN
) TRUE
)
781 DbgPrint("uhci_alloc(): error, can not translate bus address\n");
782 release_adapter(pdev_ext
->padapter
);
783 pdev_ext
->padapter
= NULL
;
784 uhci_delete_device(pdev
);
788 DbgPrint("uhci_alloc(): address space=0x%x\n, reg_base=0x%x\n",
789 addr_space
, pdev_ext
->uhci
->uhci_reg_base
.u
.LowPart
);
793 //port has been mapped to memory space
794 pdev_ext
->uhci
->port_mapped
= TRUE
;
795 pdev_ext
->uhci
->port_base
= (PBYTE
) MmMapIoSpace(pdev_ext
->uhci
->uhci_reg_base
,
796 pdev_ext
->res_port
.Length
, FALSE
);
798 //fatal error can not map the registers
799 if (pdev_ext
->uhci
->port_base
== NULL
)
801 release_adapter(pdev_ext
->padapter
);
802 pdev_ext
->padapter
= NULL
;
803 uhci_delete_device(pdev
);
810 pdev_ext
->uhci
->port_mapped
= FALSE
;
811 pdev_ext
->uhci
->port_base
= (PBYTE
) pdev_ext
->uhci
->uhci_reg_base
.LowPart
;
814 //before we connect the interrupt, we have to init uhci
815 pdev_ext
->uhci
->fsbr_cnt
= 0;
816 pdev_ext
->uhci
->pdev_ext
= pdev_ext
;
818 if (uhci_init_schedule(pdev_ext
->uhci
, pdev_ext
->padapter
) == FALSE
)
820 release_adapter(pdev_ext
->padapter
);
821 pdev_ext
->padapter
= NULL
;
822 uhci_delete_device(pdev
);
826 InitializeListHead(&pdev_ext
->uhci
->urb_list
);
827 KeInitializeSpinLock(&pdev_ext
->uhci
->pending_endp_list_lock
);
828 InitializeListHead(&pdev_ext
->uhci
->pending_endp_list
);
830 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_alloc(): pending_endp_list=0x%x\n",
831 &pdev_ext
->uhci
->pending_endp_list
));
833 init_pending_endp_pool(&pdev_ext
->uhci
->pending_endp_pool
);
834 KeInitializeTimer(&pdev_ext
->uhci
->reset_timer
);
836 vector
= HalGetInterruptVector(PCIBus
,
838 pdev_ext
->res_interrupt
.level
,
839 pdev_ext
->res_interrupt
.vector
,
843 //connect the interrupt
844 DbgPrint("uhci_alloc(): the int=0x%x\n", vector
);
845 if (IoConnectInterrupt(&pdev_ext
->uhci_int
,
848 NULL
, //&pdev_ext->uhci->frame_list_lock,
853 TRUE
, //share the vector
855 FALSE
) //No float save
862 KeInitializeDpc(&pdev_ext
->uhci_dpc
, uhci_dpc_callback
, (PVOID
) pdev_ext
->uhci
);
868 uhci_release(PDEVICE_OBJECT pdev
)
870 PDEVICE_EXTENSION pdev_ext
;
876 pdev_ext
= pdev
->DeviceExtension
;
878 if (pdev_ext
== NULL
)
881 uhci
= pdev_ext
->uhci
;
886 //pdev_ext->uhci->conn_count = 0;
887 pdev_ext
->uhci
->fsbr_cnt
= 0;
889 if (pdev_ext
->uhci_int
)
891 IoDisconnectInterrupt(pdev_ext
->uhci_int
);
892 pdev_ext
->uhci_int
= NULL
;
896 destroy_pending_endp_pool(&pdev_ext
->uhci
->pending_endp_pool
);
897 //pdev_ext->uhci->pending_endp_pool = NULL;
899 uhci_destroy_schedule(uhci
);
901 release_adapter(pdev_ext
->padapter
);
902 pdev_ext
->padapter
= NULL
;
904 uhci_delete_device(pdev
);
910 // send cmds to start the uhc
911 // shamelessly copied from linux's uhci.c (reset_hc(), configure_hc() routines)
918 PCI_SLOT_NUMBER SlotNum
;
921 uhci
= uhci_from_hcd(hcd
);
922 io_addr
= uhci
->port_base
;
925 * Reset the HC - this will force us to get a
926 * new notification of any already connected
927 * ports due to the virtual disconnect that it
930 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_HCRESET
);
931 while (READ_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
)) & USBCMD_HCRESET
)
939 /* Turn on all interrupts */
940 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBINTR
),
941 USBINTR_TIMEOUT
| USBINTR_RESUME
| USBINTR_IOC
| USBINTR_SP
);
943 /* Start at frame 0 */
944 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBFRNUM
), 0);
945 WRITE_PORT_ULONG((PULONG
) (io_addr
+ USBFLBASEADD
), uhci
->frame_list_logic_addr
.LowPart
);
947 /* Run and mark it configured with a 64-byte max packet */
948 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_RS
| USBCMD_CF
| USBCMD_MAXP
);
950 DbgPrint("uhci_start(): current uhci status=0x%x\n", uhci_status(uhci
));
953 pirq
= USBLEGSUP_DEFAULT
;
954 SlotNum
.u
.AsULONG
= 0;
955 SlotNum
.u
.bits
.DeviceNumber
= ((uhci
->pdev_ext
->pci_addr
& 0xff) >> 3);
956 SlotNum
.u
.bits
.FunctionNumber
= (uhci
->pdev_ext
->pci_addr
& 0x07);
958 DbgPrint("uhci_start(): set bus %d data at slot 0x%x\n", (uhci
->pdev_ext
->pci_addr
>> 8),
961 HalSetBusDataByOffset(PCIConfiguration
, (uhci
->pdev_ext
->pci_addr
>> 8), SlotNum
.u
.AsULONG
,
962 &pirq
, USBLEGSUP
, sizeof(pirq
));
968 uhci_stop(PUHCI_DEV uhci
)
970 PBYTE io_addr
= uhci
->port_base
;
971 // turn off all the interrupt
972 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBINTR
), 0);
973 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), 0);
977 uhci_reset(PUHCI_DEV uhci
)
979 PBYTE io_addr
= uhci
->port_base
;
982 /* Global reset for 50ms */
983 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_GRESET
);
984 //uhci_wait_ms( uhci, 50 );
987 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), 0);
988 //uhci_wait_ms( uhci, 10 );
993 uhci_suspend(PUHCI_DEV uhci
)
995 PBYTE io_addr
= uhci
->port_base
;
997 //uhci->is_suspended = 1;
998 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_EGSM
);
1003 uhci_wakeup(PUHCI_DEV uhci
)
1006 unsigned int status
;
1008 io_addr
= uhci
->port_base
;
1010 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), 0);
1012 /* wait for EOP to be sent */
1013 status
= READ_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
));
1014 while (status
& USBCMD_FGR
)
1015 status
= READ_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
));
1017 //uhci->is_suspended = 0;
1019 /* Run and mark it configured with a 64-byte max packet */
1020 WRITE_PORT_USHORT((PUSHORT
) (io_addr
+ USBCMD
), USBCMD_RS
| USBCMD_CF
| USBCMD_MAXP
);
1025 uhci_init_schedule(PUHCI_DEV uhci
, PADAPTER_OBJECT padapter
)
1029 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_init_schedule(): entering..., uhci=0x%x\n", uhci
));
1030 if (uhci
== NULL
|| padapter
== NULL
)
1033 if (init_td_pool_list(&uhci
->td_pool
, padapter
) == FALSE
)
1037 if (init_qh_pool(&uhci
->qh_pool
, padapter
) == FALSE
)
1042 //since uhci is not started we can freely access all resources.
1043 for(i
= 0; i
< UHCI_MAX_SKELTDS
; i
++)
1045 uhci
->skel_td
[i
] = alloc_td(&uhci
->td_pool
);
1046 uhci_fill_td(uhci
->skel_td
[i
], 0, (UHCI_NULL_DATA_SIZE
<< 21) | (0x7f << 8) | USB_PID_IN
, 0);
1050 uhci
->skel_td
[i
]->link
= uhci
->skel_td
[i
- 1]->phy_addr
;
1054 /*for( i = UHCI_MAX_SKELTDS - 3; i >= 0; i-- )
1056 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1057 &uhci->skel_td[ i ]->ptde->hori_link );
1060 for(i
= 0; i
< UHCI_MAX_SKELQHS
; i
++)
1062 uhci
->skel_qh
[i
] = alloc_qh(&uhci
->qh_pool
);
1065 uhci
->skel_qh
[i
- 1]->link
= uhci
->skel_qh
[i
]->phy_addr
;
1068 uhci
->skel_qh
[i
]->element
= UHCI_PTR_TERM
;
1071 uhci
->skel_int1_td
->link
= uhci
->skel_ls_control_qh
->phy_addr
;
1074 uhci_fill_td(uhci
->skel_term_td
, 0, (UHCI_NULL_DATA_SIZE
<< 21) | (0x7f << 8) | USB_PID_IN
, 0);
1075 uhci
->skel_term_td
->link
= uhci
->skel_term_td
->phy_addr
;
1077 uhci
->skel_term_qh
->link
= UHCI_PTR_TERM
;
1078 uhci
->skel_term_qh
->element
= uhci
->skel_term_td
->phy_addr
;
1080 InsertTailList(&uhci
->skel_term_qh
->pqhe
->vert_link
, &uhci
->skel_term_td
->ptde
->vert_link
);
1082 /*for( i = 0; i < UHCI_MAX_SKELQHS; i++ )
1084 InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
1085 &uhci->skel_qh[ i ]->pqhe->hori_link );
1088 if (uhci_init_frame_list(uhci
, uhci
->pdev_ext
->padapter
) == FALSE
)
1089 uhci_destroy_frame_list(uhci
);
1091 //well all have been chained, now scatter the int tds to frame-list
1092 //shamelessly pasted from linux's uhci.c :-)
1093 for(i
= 0; i
< UHCI_MAX_FRAMES
; i
++)
1123 /* Only place we don't use the frame list routines */
1124 uhci
->frame_list
[i
] = uhci
->skel_td
[irq
]->phy_addr
;
1130 uhci_destroy_schedule(PUHCI_DEV uhci
)
1134 ret
= uhci_destroy_frame_list(uhci
);
1135 ret
= destroy_qh_pool(&uhci
->qh_pool
);
1136 ret
= destroy_td_pool_list(&uhci
->td_pool
);
1143 uhci_cancel_pending_endp_urb(IN PVOID Parameter
)
1145 PLIST_ENTRY abort_list
;
1148 USE_BASIC_NON_PENDING_IRQL
;
1150 abort_list
= (PLIST_ENTRY
) Parameter
;
1152 if (abort_list
== NULL
)
1155 while (IsListEmpty(abort_list
) == FALSE
)
1157 //these devs are protected by urb's ref-count
1158 purb
= (PURB
) RemoveHeadList(abort_list
);
1160 // purb->status is set when they are added to abort_list
1162 uhci_generic_urb_completion(purb
, purb
->context
);
1164 lock_dev(pdev
, FALSE
);
1166 unlock_dev(pdev
, FALSE
);
1168 usb_free_mem(abort_list
);
1173 uhci_process_pending_endp(PUHCI_DEV uhci
)
1176 LIST_ENTRY temp_list
, abort_list
;
1179 PUSB_ENDPOINT pendp
;
1180 NTSTATUS can_submit
= STATUS_UNSUCCESSFUL
;
1181 PWORK_QUEUE_ITEM pwork_item
;
1182 PLIST_ENTRY cancel_list
;
1188 InitializeListHead(&temp_list
);
1189 InitializeListHead(&abort_list
);
1192 uhci_dbg_print(DBGLVL_MEDIUM
, ("uhci_process_pending_endp(): entering..., uhci=0x%x\n", uhci
));
1194 lock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1195 while (IsListEmpty(&uhci
->pending_endp_list
) == FALSE
)
1198 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_process_pending_endp(): pending_endp_list=0x%x\n",
1199 &uhci
->pending_endp_list
));
1201 pthis
= RemoveHeadList(&uhci
->pending_endp_list
);
1202 pendp
= ((PUHCI_PENDING_ENDP
) pthis
)->pendp
;
1203 pdev
= dev_from_endp(pendp
);
1205 lock_dev(pdev
, TRUE
);
1207 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
1209 unlock_dev(pdev
, TRUE
);
1210 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1211 //delegate to uhci_remove_device for removing the urb queue on the endpoint
1215 if (endp_state(pendp
) == USB_ENDP_FLAG_STALL
)
1217 while (IsListEmpty(&pendp
->urb_list
) == FALSE
)
1219 purb
= (PURB
) RemoveHeadList(&pendp
->urb_list
);
1220 purb
->status
= USB_STATUS_ENDPOINT_HALTED
;
1221 InsertTailList(&abort_list
, (LIST_ENTRY
*) purb
);
1223 InitializeListHead(&pendp
->urb_list
);
1224 unlock_dev(pdev
, TRUE
);
1225 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1230 if (IsListEmpty(&pendp
->urb_list
) == FALSE
)
1232 purb
= (PURB
) RemoveHeadList(&pendp
->urb_list
);
1237 InitializeListHead(&pendp
->urb_list
);
1238 unlock_dev(pdev
, TRUE
);
1239 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1243 // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
1244 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_process_pending_endp(): endp_type=0x%x\n",
1246 switch (endp_type(pendp
))
1248 case USB_ENDPOINT_XFER_BULK
:
1251 can_submit
= STATUS_UNSUCCESSFUL
;
1253 can_submit
= uhci_internal_submit_bulk(uhci
, purb
);
1257 case USB_ENDPOINT_XFER_CONTROL
:
1259 can_submit
= uhci_internal_submit_ctrl(uhci
, purb
);
1262 case USB_ENDPOINT_XFER_INT
:
1264 can_submit
= uhci_internal_submit_int(uhci
, purb
);
1267 case USB_ENDPOINT_XFER_ISOC
:
1269 can_submit
= uhci_internal_submit_iso(uhci
, purb
);
1274 if (can_submit
== STATUS_NO_MORE_ENTRIES
)
1276 //no enough bandwidth or tds
1277 InsertHeadList(&pendp
->urb_list
, (PLIST_ENTRY
) purb
);
1278 InsertTailList(&temp_list
, pthis
);
1282 // other error or success
1283 free_pending_endp(&uhci
->pending_endp_pool
, struct_ptr(pthis
, UHCI_PENDING_ENDP
, endp_link
));
1285 if (can_submit
!= STATUS_SUCCESS
)
1288 InsertTailList(&abort_list
, (LIST_ENTRY
*) purb
);
1289 uhci_dbg_print(DBGLVL_MEDIUM
, ("uhci_process_pending_endp(): unable to submit urb 0x%x, "
1290 "with status=0x%x\n", purb
, can_submit
));
1291 purb
->status
= can_submit
;
1295 unlock_dev(pdev
, TRUE
);
1298 if (IsListEmpty(&temp_list
) == FALSE
)
1300 //re-append them to the pending_endp_list
1301 ListFirst(&temp_list
, pthis
);
1302 RemoveEntryList(&temp_list
);
1303 MergeList(&uhci
->pending_endp_list
, pthis
);
1305 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1307 if (IsListEmpty(&abort_list
) == FALSE
)
1310 cancel_list
= (PLIST_ENTRY
) usb_alloc_mem(NonPagedPool
, sizeof(WORK_QUEUE_ITEM
) + sizeof(LIST_ENTRY
));
1311 ASSERT(cancel_list
);
1313 ListFirst(&abort_list
, pthis
);
1314 RemoveEntryList(&abort_list
);
1315 InsertTailList(pthis
, cancel_list
);
1317 pwork_item
= (PWORK_QUEUE_ITEM
) & cancel_list
[1];
1319 // we do not need to worry the uhci_cancel_pending_endp_urb running when the
1320 // driver is unloading since it will prevent the dev_mgr to quit till all the
1321 // reference count to the dev drop to zero.
1322 ExInitializeWorkItem(pwork_item
, uhci_cancel_pending_endp_urb
, (PVOID
) cancel_list
);
1323 ExQueueWorkItem(pwork_item
, DelayedWorkQueue
);
1329 uhci_submit_urb(PUHCI_DEV uhci
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
1332 PUHCI_PENDING_ENDP pending_endp
;
1336 if (uhci
== NULL
|| pdev
== NULL
|| pendp
== NULL
|| purb
== NULL
)
1338 uhci_dbg_print(DBGLVL_MEDIUM
,
1339 ("uhci_submit_urb(): uhci=0x%x, pdev=0x%x, pendp=0x%x, purb=0x%x "
1340 "called with invalid param!\n", uhci
, pdev
, pendp
, purb
));
1341 return STATUS_INVALID_PARAMETER
;
1344 lock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1345 lock_dev(pdev
, TRUE
);
1347 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
1349 status
= purb
->status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1353 if (dev_class(pdev
) == USB_DEV_CLASS_ROOT_HUB
)
1355 unlock_dev(pdev
, TRUE
);
1356 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1357 status
= uhci_rh_submit_urb(pdev
, purb
);
1362 purb
->pendp
= pendp
;
1364 purb
->pendp
= &pdev
->default_endp
;
1366 if (dev_from_endp(purb
->pendp
) != pdev
)
1368 uhci_dbg_print(DBGLVL_MEDIUM
,
1369 ("uhci_submit_urb(): dev_from_endp=0x%x\n, pdev=0x%x, pendp=0x%x "
1370 "devices mismatch!\n", dev_from_endp(purb
->pendp
), pdev
, pendp
));
1372 status
= purb
->status
= STATUS_INVALID_PARAMETER
;
1376 if (endp_state(purb
->pendp
) == USB_ENDP_FLAG_STALL
)
1378 status
= purb
->status
= USB_STATUS_ENDPOINT_HALTED
;
1383 purb
->rest_bytes
= purb
->data_length
;
1385 if (endp_type(purb
->pendp
) == USB_ENDPOINT_XFER_BULK
)
1386 purb
->bytes_to_transfer
= (purb
->data_length
> purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
* UHCI_MAX_TDS_PER_TRANSFER
? purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
* UHCI_MAX_TDS_PER_TRANSFER
: purb
->data_length
); //multiple transfer for large data block
1388 purb
->bytes_to_transfer
= purb
->data_length
;
1390 uhci_dbg_print(DBGLVL_MEDIUM
, ("uhci_submit_urb(): bytes_to_transfer=0x%x\n", purb
->bytes_to_transfer
));
1392 purb
->bytes_transfered
= 0;
1393 InitializeListHead(&purb
->trasac_list
);
1394 purb
->last_finished_td
= &purb
->trasac_list
;
1395 purb
->flags
&= ~(URB_FLAG_STATE_MASK
| URB_FLAG_IN_SCHEDULE
| URB_FLAG_FORCE_CANCEL
);
1396 purb
->flags
|= URB_FLAG_STATE_PENDING
;
1399 i
= IsListEmpty(&pendp
->urb_list
);
1400 InsertTailList(&pendp
->urb_list
, &purb
->urb_link
);
1402 pdev
->ref_count
++; //for urb reference
1406 //there is urb pending, simply queue it and return
1407 status
= purb
->status
= STATUS_PENDING
;
1410 else if (usb_endp_busy_count(purb
->pendp
) && endp_type(purb
->pendp
) != USB_ENDPOINT_XFER_ISOC
)
1413 //No urb waiting but urb overlap not allowed,
1414 //so leave it in queue and return, will be scheduled
1417 status
= purb
->status
= STATUS_PENDING
;
1421 pending_endp
= alloc_pending_endp(&uhci
->pending_endp_pool
, 1);
1422 if (pending_endp
== NULL
)
1425 status
= purb
->status
= STATUS_UNSUCCESSFUL
;
1429 pending_endp
->pendp
= purb
->pendp
;
1430 InsertTailList(&uhci
->pending_endp_list
, (PLIST_ENTRY
) pending_endp
);
1432 unlock_dev(pdev
, TRUE
);
1433 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1435 uhci_process_pending_endp(uhci
);
1436 return STATUS_PENDING
;
1440 RemoveEntryList((PLIST_ENTRY
) purb
);
1443 unlock_dev(pdev
, TRUE
);
1444 unlock_pending_endp_list(&uhci
->pending_endp_list_lock
);
1449 uhci_set_error_code(PURB urb
, ULONG raw_status
)
1451 if ((raw_status
& TD_CTRL_ANY_ERROR
) == 0)
1453 //test if the urb is canceled
1454 if (urb
->flags
& URB_FLAG_FORCE_CANCEL
)
1455 urb
->status
= STATUS_CANCELLED
;
1457 urb
->status
= STATUS_SUCCESS
;
1460 else if (raw_status
& TD_CTRL_BABBLE
)
1461 urb
->status
= USB_STATUS_DATA_OVERRUN
;
1463 else if (raw_status
& TD_CTRL_STALLED
)
1464 urb
->status
= USB_STATUS_STALL_PID
;
1466 else if (raw_status
& TD_CTRL_DBUFERR
)
1467 urb
->status
= USB_STATUS_BUFFER_OVERRUN
;
1469 else if (raw_status
& TD_CTRL_CRCTIMEO
)
1470 urb
->status
= USB_STATUS_CRC
;
1472 else if (raw_status
& TD_CTRL_BITSTUFF
)
1473 urb
->status
= USB_STATUS_BTSTUFF
;
1476 urb
->status
= STATUS_UNSUCCESSFUL
;
1482 uhci_sync_remove_urb_finished(PVOID context
)
1485 PLIST_ENTRY pthis
, pnext
, ptemp
;
1489 pparam
= (PSYNC_PARAM
) context
;
1490 uhci
= pparam
->uhci
;
1491 ptemp
= (PLIST_ENTRY
) pparam
->context
;
1495 return (UCHAR
) (pparam
->ret
= FALSE
);
1498 ListFirst(&uhci
->urb_list
, pthis
);
1501 //remove urbs not in the schedule
1502 ListNext(&uhci
->urb_list
, pthis
, pnext
);
1503 purb
= (PURB
) pthis
;
1505 if ((purb
->flags
& URB_FLAG_IN_SCHEDULE
) == 0)
1507 //finished or canceled( not apply for split bulk ).
1508 purb
->flags
&= ~URB_FLAG_STATE_MASK
;
1509 purb
->flags
|= URB_FLAG_STATE_FINISHED
;
1510 RemoveEntryList(pthis
);
1511 InsertTailList(ptemp
, pthis
);
1516 return (UCHAR
) TRUE
;
1520 uhci_drop_fsbr(PUHCI_DEV uhci
)
1523 return (UCHAR
) FALSE
;
1527 if (uhci
->fsbr_cnt
<= 0)
1529 uhci
->skel_term_qh
->link
= UHCI_PTR_TERM
;
1533 return (UCHAR
) TRUE
;
1537 uhci_dpc_callback(PKDPC dpc
, PVOID context
, PVOID sysarg1
, PVOID sysarg2
)
1541 LIST_HEAD temp_list
;
1542 PLIST_ENTRY pthis
, pnext
;
1545 PUHCI_PENDING_ENDP pending_endp
;
1547 PUSB_ENDPOINT pendp
;
1551 ULONG uhci_status
, urb_status
, toggle
= 0;
1553 SYNC_PARAM sync_param
;
1554 USE_BASIC_NON_PENDING_IRQL
;
1556 UNREFERENCED_PARAMETER(dpc
);
1557 UNREFERENCED_PARAMETER(sysarg2
);
1559 uhci
= (PUHCI_DEV
) context
;
1563 uhci_status
= (ULONG
) sysarg1
;
1565 InitializeListHead(&temp_list
);
1567 sync_param
.uhci
= uhci
;
1568 sync_param
.context
= (PVOID
) & temp_list
;
1570 uhci_dbg_print(DBGLVL_MAXIMUM
, ("uhci_dpc_callback(): entering..., uhci=0x%x\n", uhci
));
1571 //remove finished urb from uhci's urb-list
1572 KeSynchronizeExecution(uhci
->pdev_ext
->uhci_int
, uhci_sync_remove_urb_finished
, &sync_param
);
1574 //release resources( tds, and qhs ) the urb occupied
1575 while (IsListEmpty(&temp_list
) == FALSE
)
1577 //not in any public queue, if do not access into dev, no race
1578 //condition will occur
1579 purb
= (PURB
) RemoveHeadList(&temp_list
);
1580 urb_status
= purb
->status
;
1582 //the only place we do not use this lock on non-pending-endp-list data ops
1583 KeAcquireSpinLockAtDpcLevel(&uhci
->pending_endp_list_lock
);
1584 while (IsListEmpty(&purb
->trasac_list
) == FALSE
)
1586 pthis
= RemoveHeadList(&purb
->trasac_list
);
1588 if ((((PTD_EXTENSION
) pthis
)->flags
& UHCI_ITEM_FLAG_TYPE
) == UHCI_ITEM_FLAG_QH
)
1590 pqhe
= (PQH_EXTENSION
) pthis
;
1591 lock_qh_pool(&uhci
->qh_pool
, TRUE
);
1592 free_qh(&uhci
->qh_pool
, pqhe
->pqh
);
1593 unlock_qh_pool(&uhci
->qh_pool
, TRUE
);
1597 //must be a td chain
1598 InsertHeadList(&purb
->trasac_list
, pthis
);
1599 for(i
= 0, purb
->bytes_transfered
= 0; i
< purb
->td_count
; i
++)
1602 // accumulate data transfered in tds
1603 ptd
= ((PTD_EXTENSION
) pthis
)->ptd
;
1604 if ((ptd
->status
& TD_CTRL_ACTIVE
) == 0 && (ptd
->status
& TD_CTRL_ANY_ERROR
) == 0)
1606 j
= ptd
->status
& 0x7ff;
1607 purb
->bytes_transfered
+= ((j
== 0x7ff) ? 0 : (j
+ 1));
1610 ListNext(&purb
->trasac_list
, pthis
, pnext
);
1614 if (urb_status
& TD_CTRL_ANY_ERROR
)
1616 if (purb
->last_finished_td
!= NULL
&& purb
->last_finished_td
!= &purb
->trasac_list
)
1617 toggle
= (((PTD_EXTENSION
) purb
->last_finished_td
)->ptd
->info
& (1 << 19));
1619 //trick, remove trasac_list
1620 ListFirst(&purb
->trasac_list
, pthis
);
1621 RemoveEntryList(&purb
->trasac_list
);
1622 lock_td_pool(&uhci
->td_pool
, TRUE
);
1623 free_tds(&uhci
->td_pool
, ((PTD_EXTENSION
) pthis
)->ptd
);
1624 unlock_td_pool(&uhci
->td_pool
, TRUE
);
1625 //termination condition
1626 InitializeListHead(&purb
->trasac_list
);
1627 purb
->last_finished_td
= NULL
;
1631 if (endp_type(purb
->pendp
) == USB_ENDPOINT_XFER_ISOC
1632 || endp_type(purb
->pendp
) == USB_ENDPOINT_XFER_INT
)
1633 uhci_claim_bandwidth(uhci
, purb
, FALSE
); //release band-width
1635 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1637 uhci_set_error_code(purb
, urb_status
);
1641 //since the ref_count for the urb is not released, we can safely have one
1643 pdev
= dev_from_endp(purb
->pendp
);
1644 pendp
= purb
->pendp
;
1646 if (purb
->status
== USB_STATUS_BABBLE_DETECTED
)
1648 usb_dbg_print(DBGLVL_MEDIUM
,
1649 ("uhci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus\n"));
1651 uhci_start(&uhci
->hcd_interf
);
1654 //this will let the new request in uhci_generic_urb_completion to this endp
1655 //be processed rather than queued in the pending_endp_list
1656 lock_dev(pdev
, TRUE
);
1657 usb_endp_busy_count_dec(pendp
);
1658 unlock_dev(pdev
, TRUE
);
1660 if (usb_success(purb
->status
) == FALSE
)
1662 // set error code and complete the urb and purb is invalid from this point
1663 uhci_generic_urb_completion(purb
, purb
->context
);
1667 if ((purb
->pipe
& USB_ENDPOINT_XFERTYPE_MASK
) == USB_ENDPOINT_XFER_BULK
)
1669 purb
->rest_bytes
-= purb
->bytes_transfered
;
1670 if (purb
->rest_bytes
)
1676 uhci_generic_urb_completion(purb
, purb
->context
);
1681 uhci_generic_urb_completion(purb
, purb
->context
);
1682 //purb is now invalid
1686 KeAcquireSpinLockAtDpcLevel(&uhci
->pending_endp_list_lock
);
1687 lock_dev(pdev
, TRUE
);
1692 if (urb_status
& TD_CTRL_ANY_ERROR
&& endp_type(pendp
) != USB_ENDPOINT_XFER_CONTROL
)
1694 pendp
->flags
&= ~USB_ENDP_FLAG_STAT_MASK
;
1695 pendp
->flags
|= USB_ENDP_FLAG_STALL
;
1698 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
1700 unlock_dev(pdev
, TRUE
);
1701 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1702 if (finished
== FALSE
)
1705 purb
->status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1706 uhci_generic_urb_completion(purb
, purb
->context
);
1708 lock_dev(pdev
, TRUE
);
1710 unlock_dev(pdev
, TRUE
);
1715 if (finished
&& IsListEmpty(&pendp
->urb_list
) == TRUE
)
1717 unlock_dev(pdev
, TRUE
);
1718 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1721 else if (finished
== TRUE
)
1723 //has urb in the endp's urb-list
1724 if (usb_endp_busy_count(pendp
) > 0)
1726 //the urbs still have chance to be sheduled but not this time
1727 unlock_dev(pdev
, TRUE
);
1728 KeReleaseSpinLockFromDpcLevel(&uhci
->pending_endp_list_lock
);
1733 if (finished
== FALSE
)
1735 //a split bulk transfer
1736 purb
->bytes_transfered
= 0;
1737 purb
->bytes_to_transfer
=
1738 UHCI_MAX_TDS_PER_TRANSFER
* purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
1740 ? purb
->rest_bytes
: UHCI_MAX_TDS_PER_TRANSFER
* purb
->pendp
->pusb_endp_desc
->wMaxPacketSize
;
1742 //the urb is not finished
1743 purb
->flags
&= ~URB_FLAG_STATE_MASK
;
1744 purb
->flags
|= URB_FLAG_STATE_PENDING
;
1746 InsertHeadList(&pendp
->urb_list
, (PLIST_ENTRY
) purb
);
1749 pending_endp
= alloc_pending_endp(&uhci
->pending_endp_pool
, 1);
1750 pending_endp
->pendp
= pendp
;
1751 InsertTailList(&uhci
->pending_endp_list
, &pending_endp
->endp_link
);
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
, (PLIST_ENTRY
) urb
);
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
);
3132 lock_dev(pdev
, TRUE
);
3134 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
3136 unlock_dev(pdev
, TRUE
);
3137 goto LBL_CLIENT_PROCESS
;
3139 if (usb_error(purb
->status
))
3141 pdev
->error_count
++;
3144 if (purb
->pendp
== &pdev
->default_endp
)
3146 if (usb_halted(purb
->status
))
3148 pdev
->time_out_count
++;
3149 if (pdev
->time_out_count
> 3)
3151 dev_set_state(pdev
, USB_DEV_STATE_ZOMB
);
3152 uhci_dbg_print(DBGLVL_MAXIMUM
,
3153 ("uhci_generic_urb_completion(): contiguous error 3 times, dev 0x%x is deactivated\n",
3158 pdev
->time_out_count
= 0;
3161 unlock_dev(pdev
, TRUE
);
3164 if (purb
->completion
)
3165 purb
->completion(purb
, context
);
3167 if (old_irql
< DISPATCH_LEVEL
)
3168 KeLowerIrql(old_irql
);
3175 uhci_rh_submit_urb(PUSB_DEV pdev
, PURB purb
)
3177 PUSB_DEV_MANAGER dev_mgr
;
3179 PUSB_CTRL_SETUP_PACKET psetup
;
3183 #ifndef INCLUDE_EHCI
3184 PHUB_EXTENSION hub_ext
;
3186 PHUB2_EXTENSION hub_ext
;
3188 PUSB_PORT_STATUS ps
, psret
;
3190 USE_NON_PENDING_IRQL
;
3192 if (pdev
== NULL
|| purb
== NULL
)
3193 return STATUS_INVALID_PARAMETER
;
3195 dev_mgr
= dev_mgr_from_dev(pdev
);
3197 KeAcquireSpinLock(&dev_mgr
->timer_svc_list_lock
, &old_irql
);
3198 lock_dev(pdev
, FALSE
);
3199 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
3201 unlock_dev(pdev
, FALSE
);
3202 KeReleaseSpinLock(&dev_mgr
->timer_svc_list_lock
, old_irql
);
3203 return STATUS_DEVICE_DOES_NOT_EXIST
;
3206 uhci
= uhci_from_hcd(pdev
->hcd
);
3207 psetup
= (PUSB_CTRL_SETUP_PACKET
) purb
->setup_packet
;
3209 #ifndef INCLUDE_EHCI
3210 hub_ext
= ((PHUB_EXTENSION
) pdev
->dev_ext
);
3212 hub_ext
= ((PHUB2_EXTENSION
) pdev
->dev_ext
);
3215 switch (endp_type(purb
->pendp
))
3217 case USB_ENDPOINT_XFER_CONTROL
:
3219 if (psetup
->bmRequestType
== 0xa3 && psetup
->bRequest
== USB_REQ_GET_STATUS
)
3222 if (psetup
->wIndex
== 0 || psetup
->wIndex
> 2 || psetup
->wLength
< 4)
3224 purb
->status
= STATUS_INVALID_PARAMETER
;
3227 if (psetup
->wIndex
== 1)
3229 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC1
));
3230 ps
= &hub_ext
->rh_port1_status
;
3234 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC2
));
3235 ps
= &hub_ext
->rh_port2_status
;
3238 psret
= (PUSB_PORT_STATUS
) purb
->data_buffer
;
3239 ps
->wPortStatus
= 0;
3241 if (status
& USBPORTSC_CCS
)
3243 ps
->wPortStatus
|= USB_PORT_STAT_CONNECTION
;
3245 if (status
& USBPORTSC_PE
)
3247 ps
->wPortStatus
|= USB_PORT_STAT_ENABLE
;
3249 if (status
& USBPORTSC_PR
)
3251 ps
->wPortStatus
|= USB_PORT_STAT_RESET
;
3253 if (status
& USBPORTSC_SUSP
)
3255 ps
->wPortStatus
|= USB_PORT_STAT_SUSPEND
;
3257 if (status
& USBPORTSC_LSDA
)
3259 ps
->wPortStatus
|= USB_PORT_STAT_LOW_SPEED
;
3263 ps
->wPortStatus
|= USB_PORT_STAT_POWER
;
3265 //now set change field
3266 if (status
& USBPORTSC_CSC
)
3268 ps
->wPortChange
|= USB_PORT_STAT_C_CONNECTION
;
3270 if (status
& USBPORTSC_PEC
)
3272 ps
->wPortChange
|= USB_PORT_STAT_C_ENABLE
;
3275 //don't touch other fields, will be filled by
3278 usb_dbg_print(DBGLVL_MAXIMUM
,
3279 ("uhci_rh_submit_urb(): get port status, wPortStatus=0x%x, wPortChange=0x%x, address=0x%x\n",
3280 ps
->wPortStatus
, ps
->wPortChange
, ps
));
3282 psret
->wPortChange
= ps
->wPortChange
;
3283 psret
->wPortStatus
= ps
->wPortStatus
;
3285 purb
->status
= STATUS_SUCCESS
;
3289 else if (psetup
->bmRequestType
== 0x23 && psetup
->bRequest
== USB_REQ_CLEAR_FEATURE
)
3291 //clear-port-feature
3292 if (psetup
->wIndex
== 0 || psetup
->wIndex
> 2)
3294 purb
->status
= STATUS_INVALID_PARAMETER
;
3297 if (psetup
->wIndex
== 1)
3300 ps
= &hub_ext
->rh_port1_status
;
3305 ps
= &hub_ext
->rh_port2_status
;
3308 purb
->status
= STATUS_SUCCESS
;
3309 switch (psetup
->wValue
)
3311 case USB_PORT_FEAT_C_CONNECTION
:
3313 ps
->wPortChange
&= ~USB_PORT_STAT_C_CONNECTION
;
3314 SET_RH_PORTSTAT(i
, USBPORTSC_CSC
);
3315 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3316 usb_dbg_print(DBGLVL_MAXIMUM
,
3317 ("uhci_rh_submit_urb(): clear csc, port%d=0x%x\n", psetup
->wIndex
,
3321 case USB_PORT_FEAT_C_ENABLE
:
3323 ps
->wPortChange
&= ~USB_PORT_STAT_C_ENABLE
;
3324 SET_RH_PORTSTAT(i
, USBPORTSC_PEC
);
3325 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3326 usb_dbg_print(DBGLVL_MAXIMUM
,
3327 ("uhci_rh_submit_urb(): clear pec, port%d=0x%x\n", psetup
->wIndex
,
3331 case USB_PORT_FEAT_C_RESET
:
3333 ps
->wPortChange
&= ~USB_PORT_STAT_C_RESET
;
3334 //the reset signal is down in rh_timer_svc_reset_port_completion
3335 //so enable the port here
3336 status
= READ_PORT_USHORT((PUSHORT
)(uhci
->port_base
+ i
));
3337 usb_dbg_print(DBGLVL_MAXIMUM
,
3338 ("uhci_rh_submit_urb(): clear pr, enable pe, port%d=0x%x\n",
3339 psetup
->wIndex
, status
));
3342 case USB_PORT_FEAT_ENABLE
:
3344 ps
->wPortStatus
&= ~USB_PORT_STAT_ENABLE
;
3345 CLR_RH_PORTSTAT(i
, USBPORTSC_PE
);
3346 status
= READ_PORT_USHORT((PUSHORT
)(uhci
->port_base
+ i
));
3347 usb_dbg_print(DBGLVL_MAXIMUM
,
3348 ("uhci_rh_submit_urb(): clear pe, port%d=0x%x\n", psetup
->wIndex
,
3353 purb
->status
= STATUS_UNSUCCESSFUL
;
3357 else if (psetup
->bmRequestType
== 0xd3 && psetup
->bRequest
== HUB_REQ_GET_STATE
)
3360 if (psetup
->wIndex
== 0 || psetup
->wIndex
> 2 || psetup
->wLength
== 0)
3362 purb
->status
= STATUS_INVALID_PARAMETER
;
3366 if (psetup
->wIndex
== 1)
3374 port_status
= READ_PORT_USHORT((PUSHORT
)(uhci
->port_base
+ i
));
3375 purb
->data_buffer
[0] = (port_status
& USBPORTSC_LS
);
3377 // reverse the order
3378 purb
->data_buffer
[0] ^= 0x3;
3379 purb
->status
= STATUS_SUCCESS
;
3382 else if (psetup
->bmRequestType
== 0x23 && psetup
->bRequest
== USB_REQ_SET_FEATURE
)
3385 if (psetup
->wValue
!= USB_PORT_FEAT_RESET
)
3387 purb
->status
= STATUS_INVALID_PARAMETER
;
3388 uhci_dbg_print(DBGLVL_MAXIMUM
,
3389 ("uhci_rh_submit_urb(): set feature with wValue=0x%x\n", psetup
->wValue
));
3392 if (psetup
->wIndex
== 1)
3401 ptimer
= alloc_timer_svc(&dev_mgr
->timer_svc_pool
, 1);
3402 ptimer
->threshold
= 0; // within [ 50ms, 60ms ], one tick is 10 ms
3403 ptimer
->context
= (ULONG
) purb
;
3404 ptimer
->pdev
= pdev
;
3405 ptimer
->func
= rh_timer_svc_reset_port_completion
;
3408 pdev
->ref_count
+= 2; //one for timer and one for urb
3410 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3411 usb_dbg_print(DBGLVL_MAXIMUM
,
3412 ("uhci_rh_submit_urb(): reset port, port%d=0x%x\n", psetup
->wIndex
, status
));
3413 InsertTailList(&dev_mgr
->timer_svc_list
, &ptimer
->timer_svc_link
);
3414 purb
->status
= STATUS_PENDING
;
3418 purb
->status
= STATUS_INVALID_PARAMETER
;
3422 case USB_ENDPOINT_XFER_INT
:
3424 ptimer
= alloc_timer_svc(&dev_mgr
->timer_svc_pool
, 1);
3425 ptimer
->threshold
= RH_INTERVAL
;
3426 ptimer
->context
= (ULONG
) purb
;
3427 ptimer
->pdev
= pdev
;
3428 ptimer
->func
= rh_timer_svc_int_completion
;
3431 InsertTailList(&dev_mgr
->timer_svc_list
, &ptimer
->timer_svc_link
);
3433 usb_dbg_print(DBGLVL_ULTRA
,
3434 ("uhci_rh_submit_urb(): current rh's ref_count=0x%x\n", pdev
->ref_count
));
3435 pdev
->ref_count
+= 2; //one for timer and one for urb
3437 purb
->status
= STATUS_PENDING
;
3440 case USB_ENDPOINT_XFER_BULK
:
3441 case USB_ENDPOINT_XFER_ISOC
:
3444 purb
->status
= STATUS_INVALID_PARAMETER
;
3448 unlock_dev(pdev
, FALSE
);
3449 KeReleaseSpinLock(&dev_mgr
->timer_svc_list_lock
, old_irql
);
3450 return purb
->status
;
3453 //must have rh dev_lock acquired
3455 uhci_rh_reset_port(PHCD hcd
, UCHAR port_idx
)
3461 if (port_idx
!= 1 && port_idx
!= 2)
3476 uhci
= uhci_from_hcd(hcd
);
3477 //assert the reset signal,(implicitly disable the port)
3478 SET_RH_PORTSTAT(i
, USBPORTSC_PR
);
3479 usb_wait_ms_dpc(50);
3480 //clear the reset signal, delay port enable till clearing port feature
3481 CLR_RH_PORTSTAT(i
, USBPORTSC_PR
);
3482 usb_wait_us_dpc(10);
3483 SET_RH_PORTSTAT(i
, USBPORTSC_PE
);
3484 //recovery time 10ms
3485 usb_wait_ms_dpc(10);
3486 SET_RH_PORTSTAT(i
, 0x0a);
3488 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ i
));
3489 usb_dbg_print(DBGLVL_MAXIMUM
, ("uhci_rh_reset_port(): status after written=0x%x\n", status
));
3495 uhci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject
, IN PIRP irp
)
3497 PDEVICE_EXTENSION pdev_ext
;
3498 PUSB_DEV_MANAGER dev_mgr
;
3501 pdev_ext
= DeviceObject
->DeviceExtension
;
3502 uhci
= pdev_ext
->uhci
;
3504 dev_mgr
= uhci
->hcd_interf
.hcd_get_dev_mgr(&uhci
->hcd_interf
);
3505 return dev_mgr_dispatch(dev_mgr
, irp
);
3509 uhci_unload(IN PDRIVER_OBJECT DriverObject
)
3511 PDEVICE_OBJECT pdev
;
3512 PDEVICE_EXTENSION pdev_ext
;
3513 PUSB_DEV_MANAGER dev_mgr
;
3515 pdev
= DriverObject
->DeviceObject
;
3520 pdev_ext
= pdev
->DeviceExtension
;
3521 if (pdev_ext
== NULL
)
3524 dev_mgr
= &g_dev_mgr
;
3525 if (dev_mgr
== NULL
)
3528 // set the termination flag
3530 dev_mgr
->term_flag
= TRUE
;
3533 // wake up the thread if it is
3535 KeSetEvent(&dev_mgr
->wake_up_event
, 0, FALSE
);
3536 KeWaitForSingleObject(dev_mgr
->pthread
, Executive
, KernelMode
, TRUE
, NULL
);
3537 ObDereferenceObject(dev_mgr
->pthread
);
3538 dev_mgr
->pthread
= NULL
;
3539 // for( i = 0; i < dev_mgr->hcd_count; i++ )
3540 // dev_mgr->hcd_array[ i ]->hcd_release( dev_mgr->hcd_array[ i ]);
3541 dev_mgr_release_hcd(dev_mgr
);
3546 //the following are for hcd interface methods
3548 uhci_set_dev_mgr(struct _HCD
* hcd
, PUSB_DEV_MANAGER dev_mgr
)
3550 hcd
->dev_mgr
= dev_mgr
;
3554 uhci_get_dev_mgr(struct _HCD
*hcd
)
3556 return hcd
->dev_mgr
;
3560 uhci_get_type(struct _HCD
* hcd
)
3562 return (hcd
->flags
& HCD_TYPE_MASK
);
3566 uhci_set_id(struct _HCD
* hcd
, UCHAR id
)
3568 hcd
->flags
&= ~HCD_ID_MASK
;
3569 hcd
->flags
|= (HCD_ID_MASK
& id
);
3573 uhci_get_id(struct _HCD
*hcd
)
3575 return (UCHAR
) (hcd
->flags
& HCD_ID_MASK
);
3580 uhci_alloc_addr(struct _HCD
* hcd
)
3586 for(i
= 1; i
< MAX_DEVS
; i
++)
3588 if (hcd
->dev_addr_map
[i
>> 3] & (1 << (i
& 7)))
3601 hcd
->dev_addr_map
[i
>> 3] |= (1 << (i
& 7));
3607 uhci_free_addr(struct _HCD
* hcd
, UCHAR addr
)
3615 hcd
->dev_addr_map
[addr
>> 3] &= ~(1 << (addr
& 7));
3621 uhci_submit_urb2(struct _HCD
* hcd
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
3623 return uhci_submit_urb(uhci_from_hcd(hcd
), pdev
, pendp
, purb
);
3627 uhci_get_root_hub(struct _HCD
* hcd
)
3629 return uhci_from_hcd(hcd
)->root_hub
;
3633 uhci_set_root_hub(struct _HCD
* hcd
, PUSB_DEV root_hub
)
3635 if (hcd
== NULL
|| root_hub
== NULL
)
3637 uhci_from_hcd(hcd
)->root_hub
= root_hub
;
3642 uhci_remove_device2(struct _HCD
* hcd
, PUSB_DEV pdev
)
3644 if (hcd
== NULL
|| pdev
== NULL
)
3647 return uhci_remove_device(uhci_from_hcd(hcd
), pdev
);
3651 uhci_hcd_release(struct _HCD
* hcd
)
3654 PDEVICE_EXTENSION pdev_ext
;
3660 uhci
= uhci_from_hcd(hcd
);
3661 pdev_ext
= uhci
->pdev_ext
;
3663 return uhci_release(pdev_ext
->pdev_obj
);
3667 uhci_cancel_urb2(struct _HCD
* hcd
, PUSB_DEV pdev
, PUSB_ENDPOINT pendp
, PURB purb
)
3671 return STATUS_INVALID_PARAMETER
;
3673 uhci
= uhci_from_hcd(hcd
);
3674 return uhci_cancel_urb(uhci
, pdev
, pendp
, purb
);
3678 uhci_rh_get_dev_change(PHCD hcd
, PBYTE buf
)
3683 if (hcd
== NULL
|| buf
== NULL
)
3686 uhci
= uhci_from_hcd(hcd
);
3687 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC1
));
3688 usb_dbg_print(DBGLVL_ULTRA
, ("uhci_rh_get_dev_change(): rh port1 status=0x%x\n", status
));
3690 if ((status
& USBPORTSC_PEC
) || (status
& USBPORTSC_CSC
))
3695 status
= READ_PORT_USHORT((PUSHORT
) (uhci
->port_base
+ USBPORTSC2
));
3696 usb_dbg_print(DBGLVL_ULTRA
, ("uhci_rh_get_dev_change(): rh port2 status=0x%x\n", status
));
3698 if ((status
& USBPORTSC_PEC
) || (status
& USBPORTSC_CSC
))
3706 uhci_dispatch(PHCD hcd
, LONG disp_code
, PVOID param
) // locking depends on type of code
3713 case HCD_DISP_READ_PORT_COUNT
:
3716 return STATUS_INVALID_PARAMETER
;
3717 *((PUCHAR
) param
) = 2;
3718 return STATUS_SUCCESS
;
3720 case HCD_DISP_READ_RH_DEV_CHANGE
:
3722 if (uhci_rh_get_dev_change(hcd
, param
) == FALSE
)
3723 return STATUS_INVALID_PARAMETER
;
3724 return STATUS_SUCCESS
;
3728 return STATUS_NOT_IMPLEMENTED
;
3732 uhci_init_hcd_interface(PUHCI_DEV uhci
)
3734 uhci
->hcd_interf
.hcd_set_dev_mgr
= uhci_set_dev_mgr
;
3735 uhci
->hcd_interf
.hcd_get_dev_mgr
= uhci_get_dev_mgr
;
3736 uhci
->hcd_interf
.hcd_get_type
= uhci_get_type
;
3737 uhci
->hcd_interf
.hcd_set_id
= uhci_set_id
;
3738 uhci
->hcd_interf
.hcd_get_id
= uhci_get_id
;
3739 uhci
->hcd_interf
.hcd_alloc_addr
= uhci_alloc_addr
;
3740 uhci
->hcd_interf
.hcd_free_addr
= uhci_free_addr
;
3741 uhci
->hcd_interf
.hcd_submit_urb
= uhci_submit_urb2
;
3742 uhci
->hcd_interf
.hcd_generic_urb_completion
= uhci_generic_urb_completion
;
3743 uhci
->hcd_interf
.hcd_get_root_hub
= uhci_get_root_hub
;
3744 uhci
->hcd_interf
.hcd_set_root_hub
= uhci_set_root_hub
;
3745 uhci
->hcd_interf
.hcd_remove_device
= uhci_remove_device2
;
3746 uhci
->hcd_interf
.hcd_rh_reset_port
= uhci_rh_reset_port
;
3747 uhci
->hcd_interf
.hcd_release
= uhci_hcd_release
;
3748 uhci
->hcd_interf
.hcd_cancel_urb
= uhci_cancel_urb2
;
3749 uhci
->hcd_interf
.hcd_start
= uhci_start
;
3750 uhci
->hcd_interf
.hcd_dispatch
= uhci_dispatch
;
3752 uhci
->hcd_interf
.flags
= HCD_TYPE_UHCI
; //hcd types | hcd id
3757 generic_dispatch_irp(IN PDEVICE_OBJECT dev_obj
, IN PIRP irp
)
3759 PDEVEXT_HEADER dev_ext
;
3761 dev_ext
= (PDEVEXT_HEADER
) dev_obj
->DeviceExtension
;
3763 if (dev_ext
&& dev_ext
->dispatch
)
3764 return dev_ext
->dispatch(dev_obj
, irp
);
3766 irp
->IoStatus
.Information
= 0;
3768 EXIT_DISPATCH(STATUS_UNSUCCESSFUL
, irp
);
3773 generic_start_io(IN PDEVICE_OBJECT dev_obj
, IN PIRP irp
)
3775 PDEVEXT_HEADER dev_ext
;
3779 IoAcquireCancelSpinLock(&old_irql
);
3780 if (irp
!= dev_obj
->CurrentIrp
|| irp
->Cancel
)
3782 IoReleaseCancelSpinLock(old_irql
);
3787 (void)IoSetCancelRoutine(irp
, NULL
);
3788 IoReleaseCancelSpinLock(old_irql
);
3791 dev_ext
= (PDEVEXT_HEADER
) dev_obj
->DeviceExtension
;
3793 if (dev_ext
&& dev_ext
->start_io
)
3795 dev_ext
->start_io(dev_obj
, irp
);
3799 irp
->IoStatus
.Information
= 0;
3800 irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3802 IoStartNextPacket(dev_obj
, FALSE
);
3803 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
3807 DriverEntry(IN PDRIVER_OBJECT DriverObject
, IN PUNICODE_STRING RegistryPath
)
3810 NTSTATUS ntStatus
= STATUS_SUCCESS
;
3812 // should be done before any debug output is done.
3813 // read our debug verbosity level from the registry
3814 //NetacOD_GetRegistryDword( NetacOD_REGISTRY_PARAMETERS_PATH, //absolute registry path
3815 // L"DebugLevel", // REG_DWORD ValueName
3816 // &gDebugLevel ); // Value receiver
3818 // debug_level = DBGLVL_MAXIMUM;
3821 uhci_dbg_print_cond(DBGLVL_MINIMUM
, DEBUG_UHCI
,
3822 ("Entering DriverEntry(), RegistryPath=\n %ws\n", RegistryPath
->Buffer
));
3824 // Remember our driver object, for when we create our child PDO
3825 usb_driver_obj
= DriverObject
;
3828 // Create dispatch points for create, close, unload
3829 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = generic_dispatch_irp
;
3830 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = generic_dispatch_irp
;
3831 DriverObject
->DriverUnload
= uhci_unload
;
3833 // User mode DeviceIoControl() calls will be routed here
3834 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = generic_dispatch_irp
;
3835 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = generic_dispatch_irp
;
3837 // User mode ReadFile()/WriteFile() calls will be routed here
3838 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = generic_dispatch_irp
;
3839 DriverObject
->MajorFunction
[IRP_MJ_READ
] = generic_dispatch_irp
;
3841 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = generic_dispatch_irp
;
3842 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = generic_dispatch_irp
;
3843 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = generic_dispatch_irp
;
3845 DriverObject
->DriverStartIo
= generic_start_io
;
3846 // routines for handling system PNP and power management requests
3847 //DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = generic_dispatch_irp;
3849 // The Functional Device Object (FDO) will not be created for PNP devices until
3850 // this routine is called upon device plug-in.
3851 RtlZeroMemory(&g_dev_mgr
, sizeof(USB_DEV_MANAGER
));
3852 g_dev_mgr
.usb_driver_obj
= DriverObject
;
3855 ehci_probe(DriverObject
, RegistryPath
, &g_dev_mgr
);
3858 uhci_probe(DriverObject
, RegistryPath
, &g_dev_mgr
);
3860 if (dev_mgr_strobe(&g_dev_mgr
) == FALSE
)
3863 dev_mgr_release_hcd(&g_dev_mgr
);
3864 return STATUS_UNSUCCESSFUL
;
3867 dev_mgr_start_hcd(&g_dev_mgr
);
3869 uhci_dbg_print_cond(DBGLVL_DEFAULT
, DEBUG_UHCI
, ("DriverEntry(): exiting... (%x)\n", ntStatus
));
3870 return STATUS_SUCCESS
;
3873 //note: the initialization will be in the following order
3878 // to kill dev_mgr_thread:
3879 // dev_mgr->term_flag = TRUE;
3880 // KeSetEvent( &dev_mgr->wake_up_event );
3881 // this piece of code must run at passive-level