2006-08-18 20:37:55 +00:00
/**
* uhci . c - USB driver stack project for Windows NT 4.0
*
* Copyright ( c ) 2002 - 2004 Zhiming mypublic99 @ yahoo . com
*
* This program / include file is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program / include file is distributed in the hope that it will be
* useful , but WITHOUT ANY WARRANTY ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ( in the main directory of the distribution , the file
* COPYING ) ; if not , write to the Free Software Foundation , Inc . , 59 Temple
* Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2006-08-23 12:36:08 +00:00
# include "usbdriver.h"
2006-08-18 20:37:55 +00:00
//----------------------------------------------------------
// uhci routines
//#define DEMO
# ifdef INCLUDE_EHCI
# define rh_port1_status rh_port_status[ 1 ]
# define rh_port2_status rh_port_status[ 2 ]
2006-08-20 14:01:17 +00:00
extern PDEVICE_OBJECT ehci_probe ( PDRIVER_OBJECT drvr_obj , PUNICODE_STRING reg_path , PUSB_DEV_MANAGER dev_mgr ) ;
2006-08-18 20:37:55 +00:00
# endif
# define DEFAULT_ENDP( enDP ) \
( enDP - > flags & USB_ENDP_FLAG_DEFAULT_ENDP )
# define dev_from_endp( enDP ) \
( DEFAULT_ENDP ( enDP ) \
? ( ( PUSB_DEV ) ( enDP ) - > pusb_if ) \
: ( ( enDP ) - > pusb_if - > pusb_config - > pusb_dev ) )
# define endp_state( enDP ) ( ( enDP )->flags & USB_ENDP_FLAG_STAT_MASK )
# define endp_num( enDP ) \
( DEFAULT_ENDP ( enDP ) \
? 0 \
: ( ( enDP ) - > pusb_endp_desc - > bEndpointAddress & 0x0f ) )
# define endp_dir( enDP ) \
( DEFAULT_ENDP ( enDP ) \
? 0L \
: ( ( enDP ) - > pusb_endp_desc - > bEndpointAddress & USB_DIR_IN ) )
# define dev_set_state( pdEV, staTE ) \
( pdEV - > flags = ( ( pdEV ) - > flags & ( ~ USB_DEV_STATE_MASK ) ) | ( staTE ) )
# define endp_max_packet_size( enDP ) \
( DEFAULT_ENDP ( enDP ) \
? ( ( ( PUSB_DEV ) enDP - > pusb_if ) - > pusb_dev_desc ? \
( ( PUSB_DEV ) enDP - > pusb_if ) - > pusb_dev_desc - > bMaxPacketSize0 \
: 8 ) \
: enDP - > pusb_endp_desc - > wMaxPacketSize )
2006-08-23 22:17:09 +00:00
#if 0
/* WTF?! */
2006-08-18 20:37:55 +00:00
# define release_adapter( padapTER ) \
{ \
( ( padapTER ) ) ; \
}
2006-08-23 22:17:09 +00:00
# else
# define release_adapter( padapTER ) (void)(padapTER)
# endif
2006-08-18 20:37:55 +00:00
# define get_int_idx( _urb, _idx ) \
{ \
UCHAR interVAL ; \
interVAL = ( UCHAR ) ( ( _urb ) - > pipe > > 24 ) ; \
for ( _idx = 1 ; _idx < 9 ; _idx + + ) \
{ \
interVAL > > = 1 ; \
if ( ! interVAL ) \
break ; \
} \
_idx - - ; \
}
# define uhci_insert_urb_to_schedule( uHCI, pURB, rET ) \
{ \
SYNC_PARAM sync_param ; \
sync_param . uhci = uHCI ; \
sync_param . context = pURB ; \
\
rET = KeSynchronizeExecution ( uHCI - > pdev_ext - > uhci_int , uhci_sync_insert_urb_schedule , & sync_param ) ; \
}
//declarations
typedef struct
{
2006-08-20 14:01:17 +00:00
PUHCI_DEV uhci ;
PVOID context ;
ULONG ret ;
2006-08-18 20:37:55 +00:00
} SYNC_PARAM , * PSYNC_PARAM ;
PDEVICE_OBJECT
2006-08-20 14:01:17 +00:00
uhci_alloc ( PDRIVER_OBJECT drvr_obj , PUNICODE_STRING reg_path , ULONG bus_addr , PUSB_DEV_MANAGER dev_mgr ) ;
2006-08-18 20:37:55 +00:00
2006-08-24 12:58:52 +00:00
BOOLEAN uhci_init_schedule ( PUHCI_DEV uhci , PADAPTER_OBJECT padapter ) ;
2006-08-18 20:37:55 +00:00
2006-08-24 12:58:52 +00:00
BOOLEAN uhci_release ( PDEVICE_OBJECT pdev ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
static VOID uhci_stop ( PUHCI_DEV uhci ) ;
2006-08-18 20:37:55 +00:00
2006-08-24 12:58:52 +00:00
BOOLEAN uhci_destroy_schedule ( PUHCI_DEV uhci ) ;
2006-08-18 20:37:55 +00:00
2006-08-24 12:58:52 +00:00
BOOLEAN NTAPI uhci_sync_insert_urb_schedule ( PVOID context ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
VOID uhci_init_hcd_interface ( PUHCI_DEV uhci ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
NTSTATUS uhci_rh_submit_urb ( PUSB_DEV rh , PURB purb ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
NTSTATUS uhci_dispatch_irp ( IN PDEVICE_OBJECT DeviceObject , IN PIRP irp ) ;
extern VOID rh_timer_svc_reset_port_completion ( PUSB_DEV dev , PVOID context ) ;
extern VOID rh_timer_svc_int_completion ( PUSB_DEV dev , PVOID context ) ;
2006-10-02 21:23:41 +00:00
ULONG debug_level = DBGLVL_MINIMUM ; //DBGLVL_MAXIMUM;
2006-08-20 14:01:17 +00:00
PDRIVER_OBJECT usb_driver_obj = NULL ;
extern USB_DEV_MANAGER g_dev_mgr ;
2006-08-18 20:37:55 +00:00
//pending endpoint pool funcs
VOID
2006-08-20 14:01:17 +00:00
uhci_wait_ms ( PUHCI_DEV uhci , LONG ms )
2006-08-18 20:37:55 +00:00
{
LARGE_INTEGER lms ;
2006-08-20 14:01:17 +00:00
if ( ms < = 0 )
return ;
2006-08-18 20:37:55 +00:00
lms . QuadPart = - 10 * ms ;
2006-08-20 14:01:17 +00:00
KeSetTimer ( & uhci - > reset_timer , lms , NULL ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
KeWaitForSingleObject ( & uhci - > reset_timer , Executive , KernelMode , FALSE , NULL ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
init_pending_endp_pool ( PUHCI_PENDING_ENDP_POOL pool )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
int i ;
if ( pool = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
pool - > pending_endp_array =
usb_alloc_mem ( NonPagedPool , sizeof ( UHCI_PENDING_ENDP ) * UHCI_MAX_PENDING_ENDPS ) ;
InitializeListHead ( & pool - > free_que ) ;
pool - > free_count = 0 ;
pool - > total_count = UHCI_MAX_PENDING_ENDPS ;
KeInitializeSpinLock ( & pool - > pool_lock ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
for ( i = 0 ; i < MAX_TIMER_SVCS ; i + + )
{
free_pending_endp ( pool , & pool - > pending_endp_array [ i ] ) ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
free_pending_endp ( PUHCI_PENDING_ENDP_POOL pool , PUHCI_PENDING_ENDP pending_endp )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
if ( pool = = NULL | | pending_endp = = NULL )
{
return FALSE ;
}
RtlZeroMemory ( pending_endp , sizeof ( UHCI_PENDING_ENDP ) ) ;
InsertTailList ( & pool - > free_que , ( PLIST_ENTRY ) & pending_endp - > endp_link ) ;
pool - > free_count + + ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
PUHCI_PENDING_ENDP
2006-08-20 14:01:17 +00:00
alloc_pending_endp ( PUHCI_PENDING_ENDP_POOL pool , LONG count )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_PENDING_ENDP new ;
if ( pool = = NULL | | count ! = 1 )
return NULL ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( pool - > free_count < = 0 )
return NULL ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
new = ( PUHCI_PENDING_ENDP ) RemoveHeadList ( & pool - > free_que ) ;
pool - > free_count - - ;
return new ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
destroy_pending_endp_pool ( PUHCI_PENDING_ENDP_POOL pool )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
if ( pool = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
InitializeListHead ( & pool - > free_que ) ;
pool - > free_count = pool - > total_count = 0 ;
usb_free_mem ( pool - > pending_endp_array ) ;
pool - > pending_endp_array = NULL ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return TRUE ;
2006-08-18 20:37:55 +00:00
}
//end of pending endpoint pool funcs
static void
2006-08-20 14:01:17 +00:00
uhci_fill_td ( PUHCI_TD td , ULONG status , ULONG info , ULONG buffer )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
td - > status = status ;
td - > info = info ;
td - > buffer = buffer ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_insert_td_fl ( PUHCI_TD prev_td , PUHCI_TD ptd )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PLIST_ENTRY temp_entry ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( prev_td = = NULL | | ptd = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
temp_entry = & prev_td - > ptde - > hori_link ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
ptd - > link = ( struct_ptr ( temp_entry , TD_EXTENSION , hori_link ) ) - > ptd - > phy_addr ;
prev_td - > link = ptd - > phy_addr ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
InsertHeadList ( & prev_td - > ptde - > hori_link , & ptd - > ptde - > hori_link ) ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_remove_td_fl ( PUHCI_TD ptd )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_TD prev_td ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( ptd = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
prev_td = ( struct_ptr ( ptd - > ptde - > hori_link . Blink , TD_EXTENSION , hori_link ) ) - > ptd ;
prev_td - > link = ptd - > link ;
ptd - > link = UHCI_PTR_TERM ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
RemoveEntryList ( & ptd - > ptde - > hori_link ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return FALSE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_insert_qh_fl ( PVOID prev_item , PUHCI_QH pqh )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
//only horizontal link allowed
PUHCI_QH pprev_qh ;
PUHCI_TD pprev_td ;
PLIST_ENTRY temp_entry ;
if ( prev_item = = NULL | | pqh = = NULL )
return FALSE ;
if ( ( ( ( PUHCI_TD ) prev_item ) - > ptde - > flags & UHCI_ITEM_FLAG_TYPE ) = = UHCI_ITEM_FLAG_QH )
{
pprev_qh = ( PUHCI_QH ) prev_item ;
temp_entry = pprev_qh - > pqhe - > hori_link . Flink ;
pqh - > link = ( struct_ptr ( temp_entry , TD_EXTENSION , hori_link ) ) - > ptd - > phy_addr ;
pprev_qh - > link = pqh - > phy_addr ;
InsertHeadList ( & pprev_qh - > pqhe - > hori_link , & pqh - > pqhe - > hori_link ) ;
}
else
{
pprev_td = ( ( PUHCI_TD ) prev_item ) ;
temp_entry = pprev_td - > ptde - > hori_link . Flink ;
pprev_td - > link = pqh - > phy_addr ;
pqh - > link = ( struct_ptr ( temp_entry , TD_EXTENSION , hori_link ) ) - > ptd - > phy_addr ;
InsertHeadList ( & pprev_td - > ptde - > hori_link , & pqh - > pqhe - > hori_link ) ;
}
return FALSE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_remove_qh_fl ( PUHCI_QH pqh )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PVOID prev_item ;
PUHCI_QH pprevqh ;
PUHCI_TD pprevtd ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( pqh = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
prev_item = ( struct_ptr ( pqh - > pqhe - > hori_link . Blink , TD_EXTENSION , hori_link ) ) - > ptd ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( ( ( ( PUHCI_TD ) prev_item ) - > ptde - > flags & UHCI_ITEM_FLAG_TYPE ) = = UHCI_ITEM_FLAG_QH )
{
pprevqh = ( PUHCI_QH ) prev_item ;
pprevqh - > link = pqh - > link ;
}
else
{
pprevtd = ( ( PUHCI_TD ) prev_item ) ;
pprevtd - > link = pqh - > link ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
RemoveEntryList ( & pqh - > pqhe - > hori_link ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
pqh - > link = UHCI_PTR_TERM ;
pqh - > pqhe - > hori_link . Flink = pqh - > pqhe - > hori_link . Blink = NULL ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_init_frame_list ( PUHCI_DEV uhci , PADAPTER_OBJECT padapter )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
int i ;
if ( uhci = = NULL | | padapter = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
//note: frame_list_lock will be connected to interrupt
2006-08-20 14:01:17 +00:00
KeInitializeSpinLock ( & uhci - > frame_list_lock ) ;
uhci - > io_buf = HalAllocateCommonBuffer ( padapter , 4096 , & uhci - > io_buf_logic_addr , FALSE ) ;
if ( uhci - > io_buf = = NULL )
return FALSE ;
uhci - > frame_list =
HalAllocateCommonBuffer ( padapter ,
sizeof ( ULONG ) * UHCI_MAX_FRAMES , & uhci - > frame_list_logic_addr , FALSE ) ;
if ( uhci - > frame_list = = NULL )
return FALSE ;
RtlZeroMemory ( uhci - > frame_list , sizeof ( ULONG ) * UHCI_MAX_FRAMES ) ;
uhci - > frame_list_cpu = usb_alloc_mem ( NonPagedPool , sizeof ( FRAME_LIST_CPU_ENTRY ) * UHCI_MAX_FRAMES ) ;
if ( uhci - > frame_list_cpu = = NULL )
return FALSE ;
for ( i = 0 ; i < UHCI_MAX_FRAMES ; i + + )
InitializeListHead ( & uhci - > frame_list_cpu [ i ] . td_link ) ;
uhci - > frame_bw = usb_alloc_mem ( NonPagedPool , sizeof ( LONG ) * UHCI_MAX_FRAMES ) ;
if ( uhci - > frame_bw = = NULL )
return FALSE ;
for ( i = 0 ; i < UHCI_MAX_FRAMES ; i + + )
{
uhci - > frame_bw [ i ] = FRAME_TIME_MAX_USECS_ALLOC ;
}
uhci - > fsbr_cnt = 0 ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_destroy_frame_list ( PUHCI_DEV uhci )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( uhci - > frame_list )
HalFreeCommonBuffer ( uhci - > pdev_ext - > padapter ,
sizeof ( ULONG ) * UHCI_MAX_FRAMES ,
uhci - > frame_list_logic_addr , uhci - > frame_list , FALSE ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci - > frame_list = NULL ;
uhci - > frame_list_logic_addr . LowPart = 0 ;
2006-08-18 20:37:55 +00:00
uhci - > frame_list_logic_addr . HighPart = 0 ;
2006-08-20 14:01:17 +00:00
if ( uhci - > frame_list_cpu )
usb_free_mem ( uhci - > frame_list_cpu ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci - > frame_list_cpu = NULL ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( uhci - > frame_bw )
usb_free_mem ( uhci - > frame_bw ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci - > frame_bw = NULL ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return TRUE ;
2006-08-18 20:37:55 +00:00
}
PDEVICE_OBJECT
2006-08-20 14:01:17 +00:00
uhci_create_device ( PDRIVER_OBJECT drvr_obj , PUSB_DEV_MANAGER dev_mgr )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
NTSTATUS status ;
PDEVICE_OBJECT pdev ;
PDEVICE_EXTENSION pdev_ext ;
UNICODE_STRING dev_name ;
UNICODE_STRING symb_name ;
STRING string , another_string ;
CHAR str_dev_name [ 64 ] , str_symb_name [ 64 ] ;
UCHAR hcd_id ;
if ( drvr_obj = = NULL )
return NULL ;
ASSERT ( dev_mgr ! = NULL ) ;
2007-10-19 23:21:45 +00:00
//note: hcd count wont increment till the hcd is registered in dev_mgr
2006-08-20 14:01:17 +00:00
sprintf ( str_dev_name , " %s%d " , UHCI_DEVICE_NAME , dev_mgr - > hcd_count ) ;
sprintf ( str_symb_name , " %s%d " , DOS_DEVICE_NAME , dev_mgr - > hcd_count ) ;
RtlInitString ( & string , str_dev_name ) ;
RtlAnsiStringToUnicodeString ( & dev_name , & string , TRUE ) ;
pdev = NULL ;
status = IoCreateDevice ( drvr_obj ,
sizeof ( DEVICE_EXTENSION ) + sizeof ( UHCI_DEV ) ,
& dev_name , FILE_UHCI_DEV_TYPE , 0 , FALSE , & pdev ) ;
if ( status ! = STATUS_SUCCESS | | pdev = = NULL )
{
RtlFreeUnicodeString ( & dev_name ) ;
return NULL ;
}
pdev_ext = pdev - > DeviceExtension ;
RtlZeroMemory ( pdev_ext , sizeof ( DEVICE_EXTENSION ) + sizeof ( UHCI_DEV ) ) ;
pdev_ext - > dev_ext_hdr . type = NTDEV_TYPE_HCD ;
pdev_ext - > dev_ext_hdr . dispatch = uhci_dispatch_irp ;
pdev_ext - > dev_ext_hdr . start_io = NULL ; //we do not support startio
pdev_ext - > dev_ext_hdr . dev_mgr = dev_mgr ;
pdev_ext - > pdev_obj = pdev ;
pdev_ext - > pdrvr_obj = drvr_obj ;
pdev_ext - > uhci = ( PUHCI_DEV ) & ( pdev_ext [ 1 ] ) ;
RtlInitString ( & another_string , str_symb_name ) ;
RtlAnsiStringToUnicodeString ( & symb_name , & another_string , TRUE ) ;
IoCreateSymbolicLink ( & symb_name , & dev_name ) ;
uhci_dbg_print ( DBGLVL_MAXIMUM ,
( " uhci_create_device(): dev=0x%x \n , pdev_ext= 0x%x, uhci=0x%x, dev_mgr=0x%x \n " , pdev ,
pdev_ext , pdev_ext - > uhci , dev_mgr ) ) ;
RtlFreeUnicodeString ( & dev_name ) ;
RtlFreeUnicodeString ( & symb_name ) ;
//register with dev_mgr though it is not initilized
uhci_init_hcd_interface ( pdev_ext - > uhci ) ;
hcd_id = dev_mgr_register_hcd ( dev_mgr , & pdev_ext - > uhci - > hcd_interf ) ;
pdev_ext - > uhci - > hcd_interf . hcd_set_id ( & pdev_ext - > uhci - > hcd_interf , hcd_id ) ;
pdev_ext - > uhci - > hcd_interf . hcd_set_dev_mgr ( & pdev_ext - > uhci - > hcd_interf , dev_mgr ) ;
return pdev ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_delete_device ( PDEVICE_OBJECT pdev )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
STRING string ;
UNICODE_STRING symb_name ;
PDEVICE_EXTENSION pdev_ext ;
CHAR str_symb_name [ 64 ] ;
if ( pdev = = NULL )
return FALSE ;
pdev_ext = pdev - > DeviceExtension ;
sprintf ( str_symb_name ,
" %s%d " , DOS_DEVICE_NAME , pdev_ext - > uhci - > hcd_interf . hcd_get_id ( & pdev_ext - > uhci - > hcd_interf ) ) ;
RtlInitString ( & string , str_symb_name ) ;
RtlAnsiStringToUnicodeString ( & symb_name , & string , TRUE ) ;
IoDeleteSymbolicLink ( & symb_name ) ;
RtlFreeUnicodeString ( & symb_name ) ;
if ( pdev_ext - > res_list )
ExFreePool ( pdev_ext - > res_list ) ; // not allocated by usb_alloc_mem
IoDeleteDevice ( pdev ) ;
uhci_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_delete_device(): device deleted \n " ) ) ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
// we can not use endp here for it is within the dev scope, and
// we can not acquire the dev-lock, fortunately we saved some
// info in urb->pipe in uhci_internal_submit_XXX.
2006-08-23 22:17:09 +00:00
BOOLEAN NTAPI
2006-08-20 14:01:17 +00:00
uhci_isr ( PKINTERRUPT interrupt , PVOID context )
{
PUHCI_DEV uhci ;
USHORT status ;
PLIST_ENTRY pthis , pnext ;
PURB purb ;
2006-08-23 22:17:09 +00:00
UNREFERENCED_PARAMETER ( interrupt ) ;
UNREFERENCED_PARAMETER ( context ) ;
uhci_dbg_print ( DBGLVL_ULTRA , ( " uhci_isr(): context=0x%x \n " , context ) ) ;
2006-08-20 14:01:17 +00:00
/*
* Read the interrupt status , and write it back to clear the
* interrupt cause
*/
uhci = ( PUHCI_DEV ) context ;
if ( uhci = = NULL )
return FALSE ;
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + USBSTS ) ) ;
if ( ! status ) /* shared interrupt, not mine */
return FALSE ;
if ( status ! = 1 )
{
uhci_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_isr(): current uhci status=0x%x \n " , status ) ) ;
}
else
{
uhci_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_isr(): congratulations, no error occurs \n " ) ) ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
/* clear it */
WRITE_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + USBSTS ) , status ) ;
if ( status & ~ ( USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD ) )
{
if ( status & USBSTS_HSE )
{
DbgPrint ( " uhci_isr(): host system error, PCI problems? \n " ) ;
//for( ; ; );
}
if ( status & USBSTS_HCPE )
{
DbgPrint ( " uhci_isr(): host controller process error. something bad happened \n " ) ;
//for( ; ; );
//for( ; ; );
}
if ( ( status & USBSTS_HCH ) ) //&& !uhci->is_suspended
{
DbgPrint ( " uhci_isr(): host controller halted. very bad \n " ) ;
/* FIXME: Reset the controller, fix the offending TD */
}
}
// don't no how to handle it yet
//if (status & USBSTS_RD)
//{
//uhci_wakeup(uhci);
//}*/
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
//let's remove those force-cancel urbs from the schedule first
ListFirst ( & uhci - > urb_list , pthis ) ;
while ( pthis )
{
purb = ( PURB ) pthis ;
if ( purb - > flags & URB_FLAG_FORCE_CANCEL )
{
uhci_remove_urb_from_schedule ( uhci , purb ) ;
}
ListNext ( & uhci - > urb_list , pthis , pnext ) ;
pthis = pnext ;
}
//clear the interrupt if the urb is force canceled
uhci - > skel_term_td - > status & = ~ TD_CTRL_IOC ;
//next we need to find if anything fininshed
ListFirst ( & uhci - > urb_list , pthis ) ;
while ( pthis )
{
purb = ( PURB ) pthis ;
if ( purb - > flags & URB_FLAG_IN_SCHEDULE )
{
if ( uhci_is_xfer_finished ( purb ) )
uhci_remove_urb_from_schedule ( uhci , purb ) ;
}
ListNext ( & uhci - > urb_list , pthis , pnext ) ;
pthis = pnext ;
}
KeInsertQueueDpc ( & uhci - > pdev_ext - > uhci_dpc , uhci , 0 ) ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
BOOLEAN NTAPI
2006-08-20 14:01:17 +00:00
uhci_cal_cpu_freq ( PVOID context )
2006-08-18 20:37:55 +00:00
{
2006-08-23 22:17:09 +00:00
UNREFERENCED_PARAMETER ( context ) ;
2006-08-20 14:01:17 +00:00
usb_cal_cpu_freq ( ) ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
PDEVICE_OBJECT
2006-08-20 14:01:17 +00:00
uhci_probe ( PDRIVER_OBJECT drvr_obj , PUNICODE_STRING reg_path , PUSB_DEV_MANAGER dev_mgr )
{
2006-08-23 22:17:09 +00:00
LONG bus , i , j , ret = 0 ;
2006-08-20 14:01:17 +00:00
PCI_SLOT_NUMBER slot_num ;
PPCI_COMMON_CONFIG pci_config ;
PDEVICE_OBJECT pdev ;
BYTE buffer [ sizeof ( PCI_COMMON_CONFIG ) ] ;
LONG count ;
PDEVICE_EXTENSION pdev_ext ;
slot_num . u . AsULONG = 0 ;
pci_config = ( PPCI_COMMON_CONFIG ) buffer ;
count = 0 ;
pdev = NULL ;
//scan the bus to find uhci controller
for ( bus = 0 ; bus < 2 ; bus + + ) /*enum only bus0 and bus1 */
{
for ( i = 0 ; i < PCI_MAX_DEVICES ; i + + )
{
slot_num . u . bits . DeviceNumber = i ;
for ( j = 0 ; j < PCI_MAX_FUNCTIONS ; j + + )
{
slot_num . u . bits . FunctionNumber = j ;
ret = HalGetBusData ( PCIConfiguration ,
bus , slot_num . u . AsULONG , pci_config , PCI_COMMON_HDR_LENGTH ) ;
if ( ret = = 0 ) /*no this bus */
break ;
if ( ret = = 2 ) /*no device on the slot */
break ;
if ( pci_config - > BaseClass = = 0x0c & & pci_config - > SubClass = = 0x03 )
{
// well, we find our usb host controller, create device
2006-08-18 20:37:55 +00:00
# ifdef _MULTI_UHCI
2006-08-20 14:01:17 +00:00
{
pdev = uhci_alloc ( drvr_obj , reg_path , ( ( bus < < 8 ) | ( i < < 3 ) | j ) , dev_mgr ) ;
count + + ;
if ( ! pdev )
return NULL ;
}
2006-08-18 20:37:55 +00:00
# else
2006-08-20 14:01:17 +00:00
pdev = uhci_alloc ( drvr_obj , reg_path , ( ( bus < < 8 ) | ( i < < 3 ) | j ) , dev_mgr ) ;
if ( pdev )
goto LBL_LOOPOUT ;
2006-08-18 20:37:55 +00:00
# endif
2006-08-20 14:01:17 +00:00
}
}
if ( ret = = 0 )
break ;
}
}
2006-08-18 20:37:55 +00:00
LBL_LOOPOUT :
2006-08-20 14:01:17 +00:00
if ( pdev )
{
pdev_ext = pdev - > DeviceExtension ;
if ( pdev_ext )
{
// acquire higher irql to eliminate pre-empty
KeSynchronizeExecution ( pdev_ext - > uhci_int , uhci_cal_cpu_freq , NULL ) ;
}
}
return NULL ;
2006-08-18 20:37:55 +00:00
}
PDEVICE_OBJECT
2006-08-20 14:01:17 +00:00
uhci_alloc ( PDRIVER_OBJECT drvr_obj , PUNICODE_STRING reg_path , ULONG bus_addr , PUSB_DEV_MANAGER dev_mgr )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
LONG frd_num , prd_num ;
PDEVICE_OBJECT pdev ;
PDEVICE_EXTENSION pdev_ext ;
ULONG vector , addr_space ;
LONG bus ;
KIRQL irql ;
KAFFINITY affinity ;
DEVICE_DESCRIPTION dev_desc ;
CM_PARTIAL_RESOURCE_DESCRIPTOR * pprd ;
PCI_SLOT_NUMBER slot_num ;
NTSTATUS status ;
pdev = uhci_create_device ( drvr_obj , dev_mgr ) ;
pdev_ext = pdev - > DeviceExtension ;
pdev_ext - > pci_addr = bus_addr ;
bus = ( bus_addr > > 8 ) ;
slot_num . u . AsULONG = 0 ;
slot_num . u . bits . DeviceNumber = ( ( bus_addr & 0xff ) > > 3 ) ;
slot_num . u . bits . FunctionNumber = ( bus_addr & 0x07 ) ;
if ( pdev = = NULL )
return pdev ;
//now create adapter object
RtlZeroMemory ( & dev_desc , sizeof ( dev_desc ) ) ;
dev_desc . Version = DEVICE_DESCRIPTION_VERSION ;
dev_desc . Master = TRUE ;
dev_desc . ScatterGather = TRUE ;
dev_desc . Dma32BitAddresses = TRUE ;
dev_desc . BusNumber = bus ;
dev_desc . InterfaceType = PCIBus ;
dev_desc . MaximumLength =
UHCI_MAX_POOL_TDS * sizeof ( UHCI_TD ) * UHCI_MAX_TD_POOLS
+ sizeof ( UHCI_QH ) * UHCI_MAX_POOL_QHS + sizeof ( ULONG ) * UHCI_MAX_FRAMES ;
pdev_ext - > map_regs = 2 ; // UHCI_MAX_TD_POOLS +
//+ BYTES_TO_PAGES( ( UHCI_MAX_POOL_TDS * 64 ) * UHCI_MAX_TD_POOLS ) ;
pdev_ext - > padapter = HalGetAdapter ( & dev_desc , & pdev_ext - > map_regs ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_alloc(): padapter=0x%x \n " , pdev_ext - > padapter ) ) ;
if ( pdev_ext - > padapter = = NULL )
{
//fatal error
uhci_delete_device ( pdev ) ;
return NULL ;
}
2006-08-23 22:17:09 +00:00
DbgPrint ( " uhci_alloc(): reg_path=%p, \n \
2006-08-20 14:01:17 +00:00
uhci_alloc ( ) : PCIBus = 0 x % x , bus = 0 x % x , bus_addr = 0 x % x \ n \
2006-08-23 22:17:09 +00:00
uhci_alloc ( ) : slot_num = 0 x % x , & res_list = % p \ n " , reg_path, (DWORD) PCIBus, (DWORD) bus,
( DWORD ) bus_addr , ( DWORD ) slot_num . u . AsULONG , & pdev_ext - > res_list ) ;
2006-08-20 14:01:17 +00:00
//let's allocate resources for this device
DbgPrint ( " uhci_alloc(): about to assign slot res \n " ) ;
if ( ( status = HalAssignSlotResources ( reg_path , NULL , //no class name yet
drvr_obj , NULL , //no support of another uhci controller
PCIBus ,
bus , slot_num . u . AsULONG , & pdev_ext - > res_list ) ) ! = STATUS_SUCCESS )
{
DbgPrint ( " uhci_alloc(): error assign slot res, 0x%x \n " , status ) ;
release_adapter ( pdev_ext - > padapter ) ;
pdev_ext - > padapter = NULL ;
uhci_delete_device ( pdev ) ;
return NULL ;
}
//parse the resource list
for ( frd_num = 0 ; frd_num < ( LONG ) pdev_ext - > res_list - > Count ; frd_num + + )
{
for ( prd_num = 0 ; prd_num < ( LONG ) pdev_ext - > res_list - > List [ frd_num ] . PartialResourceList . Count ;
prd_num + + )
{
pprd = & pdev_ext - > res_list - > List [ frd_num ] . PartialResourceList . PartialDescriptors [ prd_num ] ;
if ( pprd - > Type = = CmResourceTypePort )
{
RtlCopyMemory ( & pdev_ext - > res_port , & pprd - > u . Port , sizeof ( pprd - > u . Port ) ) ;
}
else if ( pprd - > Type = = CmResourceTypeInterrupt )
{
RtlCopyMemory ( & pdev_ext - > res_interrupt , & pprd - > u . Interrupt , sizeof ( pprd - > u . Interrupt ) ) ;
}
}
}
//for port, translate them to system address
addr_space = 1 ;
if ( HalTranslateBusAddress ( PCIBus , bus , pdev_ext - > res_port . Start , & addr_space , //io space
& pdev_ext - > uhci - > uhci_reg_base ) ! = ( BOOLEAN ) TRUE )
{
DbgPrint ( " uhci_alloc(): error, can not translate bus address \n " ) ;
release_adapter ( pdev_ext - > padapter ) ;
pdev_ext - > padapter = NULL ;
uhci_delete_device ( pdev ) ;
return NULL ;
}
DbgPrint ( " uhci_alloc(): address space=0x%x \n , reg_base=0x%x \n " ,
addr_space , pdev_ext - > uhci - > uhci_reg_base . u . LowPart ) ;
if ( addr_space = = 0 )
{
2007-10-19 23:21:45 +00:00
//port has been mapped to memory space
2006-08-20 14:01:17 +00:00
pdev_ext - > uhci - > port_mapped = TRUE ;
pdev_ext - > uhci - > port_base = ( PBYTE ) MmMapIoSpace ( pdev_ext - > uhci - > uhci_reg_base ,
pdev_ext - > res_port . Length , FALSE ) ;
2007-10-19 23:21:45 +00:00
//fatal error can not map the registers
2006-08-20 14:01:17 +00:00
if ( pdev_ext - > uhci - > port_base = = NULL )
{
release_adapter ( pdev_ext - > padapter ) ;
pdev_ext - > padapter = NULL ;
uhci_delete_device ( pdev ) ;
return NULL ;
}
}
else
{
//io space
pdev_ext - > uhci - > port_mapped = FALSE ;
pdev_ext - > uhci - > port_base = ( PBYTE ) pdev_ext - > uhci - > uhci_reg_base . LowPart ;
}
//before we connect the interrupt, we have to init uhci
pdev_ext - > uhci - > fsbr_cnt = 0 ;
pdev_ext - > uhci - > pdev_ext = pdev_ext ;
if ( uhci_init_schedule ( pdev_ext - > uhci , pdev_ext - > padapter ) = = FALSE )
{
release_adapter ( pdev_ext - > padapter ) ;
pdev_ext - > padapter = NULL ;
uhci_delete_device ( pdev ) ;
return NULL ;
}
InitializeListHead ( & pdev_ext - > uhci - > urb_list ) ;
KeInitializeSpinLock ( & pdev_ext - > uhci - > pending_endp_list_lock ) ;
InitializeListHead ( & pdev_ext - > uhci - > pending_endp_list ) ;
uhci_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_alloc(): pending_endp_list=0x%x \n " ,
& pdev_ext - > uhci - > pending_endp_list ) ) ;
init_pending_endp_pool ( & pdev_ext - > uhci - > pending_endp_pool ) ;
KeInitializeTimer ( & pdev_ext - > uhci - > reset_timer ) ;
vector = HalGetInterruptVector ( PCIBus ,
bus ,
pdev_ext - > res_interrupt . level ,
pdev_ext - > res_interrupt . vector ,
& irql ,
& affinity ) ;
//connect the interrupt
DbgPrint ( " uhci_alloc(): the int=0x%x \n " , vector ) ;
if ( IoConnectInterrupt ( & pdev_ext - > uhci_int ,
uhci_isr ,
pdev_ext - > uhci ,
NULL , //&pdev_ext->uhci->frame_list_lock,
vector ,
irql ,
irql ,
LevelSensitive ,
TRUE , //share the vector
affinity ,
FALSE ) //No float save
! = STATUS_SUCCESS )
{
uhci_release ( pdev ) ;
return NULL ;
}
KeInitializeDpc ( & pdev_ext - > uhci_dpc , uhci_dpc_callback , ( PVOID ) pdev_ext - > uhci ) ;
return pdev ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_release ( PDEVICE_OBJECT pdev )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PDEVICE_EXTENSION pdev_ext ;
PUHCI_DEV uhci ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( pdev = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
pdev_ext = pdev - > DeviceExtension ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( pdev_ext = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci = pdev_ext - > uhci ;
if ( uhci = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci_stop ( uhci ) ;
//pdev_ext->uhci->conn_count = 0;
pdev_ext - > uhci - > fsbr_cnt = 0 ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( pdev_ext - > uhci_int )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
IoDisconnectInterrupt ( pdev_ext - > uhci_int ) ;
pdev_ext - > uhci_int = NULL ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
else
TRAP ( ) ;
destroy_pending_endp_pool ( & pdev_ext - > uhci - > pending_endp_pool ) ;
//pdev_ext->uhci->pending_endp_pool = NULL;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci_destroy_schedule ( uhci ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
release_adapter ( pdev_ext - > padapter ) ;
pdev_ext - > padapter = NULL ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci_delete_device ( pdev ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return FALSE ;
2006-08-18 20:37:55 +00:00
}
// send cmds to start the uhc
2006-08-25 13:20:13 +00:00
// shamelessly copied from linux's uhci.c (reset_hc(), configure_hc() routines)
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_start ( PHCD hcd )
{
PUHCI_DEV uhci ;
PBYTE io_addr ;
2006-08-25 13:20:13 +00:00
USHORT pirq ;
PCI_SLOT_NUMBER SlotNum ;
2006-08-20 14:01:17 +00:00
int timeout = 10000 ;
uhci = uhci_from_hcd ( hcd ) ;
io_addr = uhci - > port_base ;
/*
* Reset the HC - this will force us to get a
* new notification of any already connected
* ports due to the virtual disconnect that it
* implies .
*/
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) , USBCMD_HCRESET ) ;
while ( READ_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) ) & USBCMD_HCRESET )
{
if ( ! - - timeout )
{
break ;
}
}
/* Turn on all interrupts */
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBINTR ) ,
USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP ) ;
/* Start at frame 0 */
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBFRNUM ) , 0 ) ;
WRITE_PORT_ULONG ( ( PULONG ) ( io_addr + USBFLBASEADD ) , uhci - > frame_list_logic_addr . LowPart ) ;
/* Run and mark it configured with a 64-byte max packet */
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) , USBCMD_RS | USBCMD_CF | USBCMD_MAXP ) ;
DbgPrint ( " uhci_start(): current uhci status=0x%x \n " , uhci_status ( uhci ) ) ;
2006-08-25 13:20:13 +00:00
/* Enable PIRQ */
pirq = USBLEGSUP_DEFAULT ;
SlotNum . u . AsULONG = 0 ;
SlotNum . u . bits . DeviceNumber = ( ( uhci - > pdev_ext - > pci_addr & 0xff ) > > 3 ) ;
SlotNum . u . bits . FunctionNumber = ( uhci - > pdev_ext - > pci_addr & 0x07 ) ;
DbgPrint ( " uhci_start(): set bus %d data at slot 0x%x \n " , ( uhci - > pdev_ext - > pci_addr > > 8 ) ,
SlotNum . u . AsULONG ) ;
HalSetBusDataByOffset ( PCIConfiguration , ( uhci - > pdev_ext - > pci_addr > > 8 ) , SlotNum . u . AsULONG ,
& pirq , USBLEGSUP , sizeof ( pirq ) ) ;
2006-08-20 14:01:17 +00:00
return TRUE ;
2006-08-18 20:37:55 +00:00
}
VOID
2006-08-20 14:01:17 +00:00
uhci_stop ( PUHCI_DEV uhci )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PBYTE io_addr = uhci - > port_base ;
// turn off all the interrupt
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBINTR ) , 0 ) ;
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) , 0 ) ;
2006-08-18 20:37:55 +00:00
}
static VOID
2006-08-20 14:01:17 +00:00
uhci_reset ( PUHCI_DEV uhci )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PBYTE io_addr = uhci - > port_base ;
uhci_stop ( uhci ) ;
/* Global reset for 50ms */
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) , USBCMD_GRESET ) ;
//uhci_wait_ms( uhci, 50 );
usb_wait_ms_dpc ( 50 ) ;
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) , 0 ) ;
//uhci_wait_ms( uhci, 10 );
usb_wait_ms_dpc ( 10 ) ;
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
VOID
2006-08-20 14:01:17 +00:00
uhci_suspend ( PUHCI_DEV uhci )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PBYTE io_addr = uhci - > port_base ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
//uhci->is_suspended = 1;
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) , USBCMD_EGSM ) ;
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
VOID
2006-08-20 14:01:17 +00:00
uhci_wakeup ( PUHCI_DEV uhci )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PBYTE io_addr ;
unsigned int status ;
io_addr = uhci - > port_base ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) , 0 ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
/* wait for EOP to be sent */
status = READ_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) ) ;
while ( status & USBCMD_FGR )
status = READ_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
//uhci->is_suspended = 0;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
/* Run and mark it configured with a 64-byte max packet */
WRITE_PORT_USHORT ( ( PUSHORT ) ( io_addr + USBCMD ) , USBCMD_RS | USBCMD_CF | USBCMD_MAXP ) ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_init_schedule ( PUHCI_DEV uhci , PADAPTER_OBJECT padapter )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
int i , irq ;
uhci_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_init_schedule(): entering..., uhci=0x%x \n " , uhci ) ) ;
if ( uhci = = NULL | | padapter = = NULL )
return FALSE ;
if ( init_td_pool_list ( & uhci - > td_pool , padapter ) = = FALSE )
{
return FALSE ;
}
if ( init_qh_pool ( & uhci - > qh_pool , padapter ) = = FALSE )
{
return FALSE ;
}
//since uhci is not started we can freely access all resources.
for ( i = 0 ; i < UHCI_MAX_SKELTDS ; i + + )
{
uhci - > skel_td [ i ] = alloc_td ( & uhci - > td_pool ) ;
uhci_fill_td ( uhci - > skel_td [ i ] , 0 , ( UHCI_NULL_DATA_SIZE < < 21 ) | ( 0x7f < < 8 ) | USB_PID_IN , 0 ) ;
if ( i > 0 )
{
uhci - > skel_td [ i ] - > link = uhci - > skel_td [ i - 1 ] - > phy_addr ;
}
}
/*for( i = UHCI_MAX_SKELTDS - 3; i >= 0; i-- )
{
InsertTailList ( & uhci - > skel_int256_td - > ptde - > hori_link ,
& uhci - > skel_td [ i ] - > ptde - > hori_link ) ;
} */
for ( i = 0 ; i < UHCI_MAX_SKELQHS ; i + + )
{
uhci - > skel_qh [ i ] = alloc_qh ( & uhci - > qh_pool ) ;
if ( i > 0 )
{
uhci - > skel_qh [ i - 1 ] - > link = uhci - > skel_qh [ i ] - > phy_addr ;
}
uhci - > skel_qh [ i ] - > element = UHCI_PTR_TERM ;
}
uhci - > skel_int1_td - > link = uhci - > skel_ls_control_qh - > phy_addr ;
2006-08-23 22:17:09 +00:00
// Hack for PIIX
2006-08-20 14:01:17 +00:00
uhci_fill_td ( uhci - > skel_term_td , 0 , ( UHCI_NULL_DATA_SIZE < < 21 ) | ( 0x7f < < 8 ) | USB_PID_IN , 0 ) ;
uhci - > skel_term_td - > link = uhci - > skel_term_td - > phy_addr ;
uhci - > skel_term_qh - > link = UHCI_PTR_TERM ;
uhci - > skel_term_qh - > element = uhci - > skel_term_td - > phy_addr ;
InsertTailList ( & uhci - > skel_term_qh - > pqhe - > vert_link , & uhci - > skel_term_td - > ptde - > vert_link ) ;
/*for( i = 0; i < UHCI_MAX_SKELQHS; i++ )
{
InsertTailList ( & uhci - > skel_int256_td - > ptde - > hori_link ,
& uhci - > skel_qh [ i ] - > pqhe - > hori_link ) ;
} */
if ( uhci_init_frame_list ( uhci , uhci - > pdev_ext - > padapter ) = = FALSE )
uhci_destroy_frame_list ( uhci ) ;
//well all have been chained, now scatter the int tds to frame-list
2006-08-18 20:37:55 +00:00
//shamelessly pasted from linux's uhci.c :-)
2006-08-20 14:01:17 +00:00
for ( i = 0 ; i < UHCI_MAX_FRAMES ; i + + )
{
irq = 0 ;
if ( i & 1 )
{
irq + + ;
if ( i & 2 )
{
irq + + ;
if ( i & 4 )
{
irq + + ;
if ( i & 8 )
{
irq + + ;
if ( i & 16 )
{
irq + + ;
if ( i & 32 )
{
irq + + ;
if ( i & 64 )
irq + + ;
}
}
}
}
}
}
/* Only place we don't use the frame list routines */
uhci - > frame_list [ i ] = uhci - > skel_td [ irq ] - > phy_addr ;
}
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_destroy_schedule ( PUHCI_DEV uhci )
2006-08-18 20:37:55 +00:00
{
2006-08-24 12:58:52 +00:00
BOOLEAN ret ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
ret = uhci_destroy_frame_list ( uhci ) ;
ret = destroy_qh_pool ( & uhci - > qh_pool ) ;
ret = destroy_td_pool_list ( & uhci - > td_pool ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return ret ;
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
VOID NTAPI
2006-08-20 14:01:17 +00:00
uhci_cancel_pending_endp_urb ( IN PVOID Parameter )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PLIST_ENTRY abort_list ;
PUSB_DEV pdev ;
PURB purb ;
2006-08-23 22:17:09 +00:00
USE_BASIC_NON_PENDING_IRQL ;
2006-08-20 14:01:17 +00:00
abort_list = ( PLIST_ENTRY ) Parameter ;
if ( abort_list = = NULL )
return ;
while ( IsListEmpty ( abort_list ) = = FALSE )
{
//these devs are protected by urb's ref-count
purb = ( PURB ) RemoveHeadList ( abort_list ) ;
pdev = purb - > pdev ;
// purb->status is set when they are added to abort_list
uhci_generic_urb_completion ( purb , purb - > context ) ;
lock_dev ( pdev , FALSE ) ;
pdev - > ref_count - - ;
unlock_dev ( pdev , FALSE ) ;
}
usb_free_mem ( abort_list ) ;
return ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_process_pending_endp ( PUHCI_DEV uhci )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUSB_DEV pdev ;
LIST_ENTRY temp_list , abort_list ;
PLIST_ENTRY pthis ;
PURB purb ;
PUSB_ENDPOINT pendp ;
2006-08-24 12:58:52 +00:00
NTSTATUS can_submit = STATUS_UNSUCCESSFUL ;
2006-08-20 14:01:17 +00:00
PWORK_QUEUE_ITEM pwork_item ;
PLIST_ENTRY cancel_list ;
2006-08-24 16:21:16 +00:00
USE_BASIC_IRQL ;
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL )
return FALSE ;
InitializeListHead ( & temp_list ) ;
InitializeListHead ( & abort_list ) ;
purb = NULL ;
uhci_dbg_print ( DBGLVL_MEDIUM , ( " uhci_process_pending_endp(): entering..., uhci=0x%x \n " , uhci ) ) ;
lock_pending_endp_list ( & uhci - > pending_endp_list_lock ) ;
while ( IsListEmpty ( & uhci - > pending_endp_list ) = = FALSE )
{
uhci_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_process_pending_endp(): pending_endp_list=0x%x \n " ,
& uhci - > pending_endp_list ) ) ;
pthis = RemoveHeadList ( & uhci - > pending_endp_list ) ;
pendp = ( ( PUHCI_PENDING_ENDP ) pthis ) - > pendp ;
pdev = dev_from_endp ( pendp ) ;
lock_dev ( pdev , TRUE ) ;
if ( dev_state ( pdev ) = = USB_DEV_STATE_ZOMB )
{
unlock_dev ( pdev , TRUE ) ;
free_pending_endp ( & uhci - > pending_endp_pool , struct_ptr ( pthis , UHCI_PENDING_ENDP , endp_link ) ) ;
2006-08-23 22:17:09 +00:00
//delegate to uhci_remove_device for removing the urb queue on the endpoint
2006-08-20 14:01:17 +00:00
continue ;
}
if ( endp_state ( pendp ) = = USB_ENDP_FLAG_STALL )
{
while ( IsListEmpty ( & pendp - > urb_list ) = = FALSE )
{
purb = ( PURB ) RemoveHeadList ( & pendp - > urb_list ) ;
purb - > status = USB_STATUS_ENDPOINT_HALTED ;
InsertTailList ( & abort_list , ( LIST_ENTRY * ) purb ) ;
}
InitializeListHead ( & pendp - > urb_list ) ;
unlock_dev ( pdev , TRUE ) ;
free_pending_endp ( & uhci - > pending_endp_pool , struct_ptr ( pthis , UHCI_PENDING_ENDP , endp_link ) ) ;
continue ;
}
if ( IsListEmpty ( & pendp - > urb_list ) = = FALSE )
{
purb = ( PURB ) RemoveHeadList ( & pendp - > urb_list ) ;
ASSERT ( purb ) ;
}
else
{
InitializeListHead ( & pendp - > urb_list ) ;
unlock_dev ( pdev , TRUE ) ;
free_pending_endp ( & uhci - > pending_endp_pool , struct_ptr ( pthis , UHCI_PENDING_ENDP , endp_link ) ) ;
continue ;
}
// if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
2006-09-29 09:08:20 +00:00
uhci_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_process_pending_endp(): endp_type=0x%x \n " ,
endp_type ( pendp ) ) ) ;
2006-08-20 14:01:17 +00:00
switch ( endp_type ( pendp ) )
{
case USB_ENDPOINT_XFER_BULK :
{
2006-08-18 20:37:55 +00:00
# ifdef DEMO
2006-08-20 14:01:17 +00:00
can_submit = STATUS_UNSUCCESSFUL ;
2006-08-18 20:37:55 +00:00
# else
2006-08-20 14:01:17 +00:00
can_submit = uhci_internal_submit_bulk ( uhci , purb ) ;
2006-08-18 20:37:55 +00:00
# endif
2006-08-20 14:01:17 +00:00
break ;
}
case USB_ENDPOINT_XFER_CONTROL :
{
can_submit = uhci_internal_submit_ctrl ( uhci , purb ) ;
break ;
}
case USB_ENDPOINT_XFER_INT :
{
can_submit = uhci_internal_submit_int ( uhci , purb ) ;
break ;
}
case USB_ENDPOINT_XFER_ISOC :
{
can_submit = uhci_internal_submit_iso ( uhci , purb ) ;
break ;
}
}
if ( can_submit = = STATUS_NO_MORE_ENTRIES )
{
//no enough bandwidth or tds
InsertHeadList ( & pendp - > urb_list , ( PLIST_ENTRY ) purb ) ;
InsertTailList ( & temp_list , pthis ) ;
}
else
{
// other error or success
free_pending_endp ( & uhci - > pending_endp_pool , struct_ptr ( pthis , UHCI_PENDING_ENDP , endp_link ) ) ;
if ( can_submit ! = STATUS_SUCCESS )
{
//abort these URBs
InsertTailList ( & abort_list , ( LIST_ENTRY * ) purb ) ;
2006-09-08 22:00:39 +00:00
uhci_dbg_print ( DBGLVL_MEDIUM , ( " uhci_process_pending_endp(): unable to submit urb 0x%x, "
" with status=0x%x \n " , purb , can_submit ) ) ;
2006-08-20 14:01:17 +00:00
purb - > status = can_submit ;
}
}
unlock_dev ( pdev , TRUE ) ;
}
if ( IsListEmpty ( & temp_list ) = = FALSE )
{
//re-append them to the pending_endp_list
ListFirst ( & temp_list , pthis ) ;
RemoveEntryList ( & temp_list ) ;
MergeList ( & uhci - > pending_endp_list , pthis ) ;
}
unlock_pending_endp_list ( & uhci - > pending_endp_list_lock ) ;
if ( IsListEmpty ( & abort_list ) = = FALSE )
{
PLIST_ENTRY pthis ;
cancel_list = ( PLIST_ENTRY ) usb_alloc_mem ( NonPagedPool , sizeof ( WORK_QUEUE_ITEM ) + sizeof ( LIST_ENTRY ) ) ;
ASSERT ( cancel_list ) ;
ListFirst ( & abort_list , pthis ) ;
RemoveEntryList ( & abort_list ) ;
InsertTailList ( pthis , cancel_list ) ;
pwork_item = ( PWORK_QUEUE_ITEM ) & cancel_list [ 1 ] ;
// we do not need to worry the uhci_cancel_pending_endp_urb running when the
// driver is unloading since it will prevent the dev_mgr to quit till all the
// reference count to the dev drop to zero.
ExInitializeWorkItem ( pwork_item , uhci_cancel_pending_endp_urb , ( PVOID ) cancel_list ) ;
ExQueueWorkItem ( pwork_item , DelayedWorkQueue ) ;
}
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_submit_urb ( PUHCI_DEV uhci , PUSB_DEV pdev , PUSB_ENDPOINT pendp , PURB purb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
int i ;
PUHCI_PENDING_ENDP pending_endp ;
NTSTATUS status ;
2006-08-24 16:21:16 +00:00
USE_BASIC_IRQL ;
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL | | pdev = = NULL | | pendp = = NULL | | purb = = NULL )
2006-09-08 22:00:39 +00:00
{
uhci_dbg_print ( DBGLVL_MEDIUM ,
( " uhci_submit_urb(): uhci=0x%x, pdev=0x%x, pendp=0x%x, purb=0x%x "
" called with invalid param! \n " , uhci , pdev , pendp , purb ) ) ;
2006-08-20 14:01:17 +00:00
return STATUS_INVALID_PARAMETER ;
2006-09-08 22:00:39 +00:00
}
2006-08-20 14:01:17 +00:00
lock_pending_endp_list ( & uhci - > pending_endp_list_lock ) ;
lock_dev ( pdev , TRUE ) ;
if ( dev_state ( pdev ) = = USB_DEV_STATE_ZOMB )
{
status = purb - > status = STATUS_DEVICE_DOES_NOT_EXIST ;
goto LBL_OUT ;
}
if ( dev_class ( pdev ) = = USB_DEV_CLASS_ROOT_HUB )
{
unlock_dev ( pdev , TRUE ) ;
unlock_pending_endp_list ( & uhci - > pending_endp_list_lock ) ;
status = uhci_rh_submit_urb ( pdev , purb ) ;
return status ;
}
if ( pendp )
purb - > pendp = pendp ;
else
purb - > pendp = & pdev - > default_endp ;
if ( dev_from_endp ( purb - > pendp ) ! = pdev )
{
2006-09-08 22:00:39 +00:00
uhci_dbg_print ( DBGLVL_MEDIUM ,
( " uhci_submit_urb(): dev_from_endp=0x%x \n , pdev=0x%x, pendp=0x%x "
" devices mismatch! \n " , dev_from_endp ( purb - > pendp ) , pdev , pendp ) ) ;
2006-08-20 14:01:17 +00:00
status = purb - > status = STATUS_INVALID_PARAMETER ;
goto LBL_OUT ;
}
if ( endp_state ( purb - > pendp ) = = USB_ENDP_FLAG_STALL )
{
status = purb - > status = USB_STATUS_ENDPOINT_HALTED ;
goto LBL_OUT ;
}
purb - > pdev = pdev ;
purb - > rest_bytes = purb - > data_length ;
if ( endp_type ( purb - > pendp ) = = USB_ENDPOINT_XFER_BULK )
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
else
purb - > bytes_to_transfer = purb - > data_length ;
uhci_dbg_print ( DBGLVL_MEDIUM , ( " uhci_submit_urb(): bytes_to_transfer=0x%x \n " , purb - > bytes_to_transfer ) ) ;
purb - > bytes_transfered = 0 ;
InitializeListHead ( & purb - > trasac_list ) ;
purb - > last_finished_td = & purb - > trasac_list ;
purb - > flags & = ~ ( URB_FLAG_STATE_MASK | URB_FLAG_IN_SCHEDULE | URB_FLAG_FORCE_CANCEL ) ;
purb - > flags | = URB_FLAG_STATE_PENDING ;
i = IsListEmpty ( & pendp - > urb_list ) ;
InsertTailList ( & pendp - > urb_list , & purb - > urb_link ) ;
pdev - > ref_count + + ; //for urb reference
if ( i = = FALSE )
{
//there is urb pending, simply queue it and return
status = purb - > status = STATUS_PENDING ;
goto LBL_OUT ;
}
else if ( usb_endp_busy_count ( purb - > pendp ) & & endp_type ( purb - > pendp ) ! = USB_ENDPOINT_XFER_ISOC )
{
//
2007-10-19 23:21:45 +00:00
//No urb waiting but urb overlap not allowed,
2006-08-20 14:01:17 +00:00
//so leave it in queue and return, will be scheduled
//later
2006-08-18 20:37:55 +00:00
//
2006-08-20 14:01:17 +00:00
status = purb - > status = STATUS_PENDING ;
goto LBL_OUT ;
}
pending_endp = alloc_pending_endp ( & uhci - > pending_endp_pool , 1 ) ;
if ( pending_endp = = NULL )
{
//panic
status = purb - > status = STATUS_UNSUCCESSFUL ;
goto LBL_OUT2 ;
}
pending_endp - > pendp = purb - > pendp ;
InsertTailList ( & uhci - > pending_endp_list , ( PLIST_ENTRY ) pending_endp ) ;
unlock_dev ( pdev , TRUE ) ;
unlock_pending_endp_list ( & uhci - > pending_endp_list_lock ) ;
uhci_process_pending_endp ( uhci ) ;
return STATUS_PENDING ;
2006-08-18 20:37:55 +00:00
LBL_OUT2 :
2006-08-20 14:01:17 +00:00
pdev - > ref_count - - ;
RemoveEntryList ( ( PLIST_ENTRY ) purb ) ;
2006-08-18 20:37:55 +00:00
LBL_OUT :
2006-08-20 14:01:17 +00:00
unlock_dev ( pdev , TRUE ) ;
unlock_pending_endp_list ( & uhci - > pending_endp_list_lock ) ;
return status ;
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_set_error_code ( PURB urb , ULONG raw_status )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
if ( ( raw_status & TD_CTRL_ANY_ERROR ) = = 0 )
{
//test if the urb is canceled
if ( urb - > flags & URB_FLAG_FORCE_CANCEL )
urb - > status = STATUS_CANCELLED ;
else
urb - > status = STATUS_SUCCESS ;
}
else if ( raw_status & TD_CTRL_BABBLE )
urb - > status = USB_STATUS_DATA_OVERRUN ;
else if ( raw_status & TD_CTRL_STALLED )
urb - > status = USB_STATUS_STALL_PID ;
else if ( raw_status & TD_CTRL_DBUFERR )
urb - > status = USB_STATUS_BUFFER_OVERRUN ;
else if ( raw_status & TD_CTRL_CRCTIMEO )
urb - > status = USB_STATUS_CRC ;
else if ( raw_status & TD_CTRL_BITSTUFF )
urb - > status = USB_STATUS_BTSTUFF ;
else
urb - > status = STATUS_UNSUCCESSFUL ;
return urb - > status ;
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
BOOLEAN NTAPI
2006-08-20 14:01:17 +00:00
uhci_sync_remove_urb_finished ( PVOID context )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_DEV uhci ;
PLIST_ENTRY pthis , pnext , ptemp ;
PURB purb ;
PSYNC_PARAM pparam ;
pparam = ( PSYNC_PARAM ) context ;
uhci = pparam - > uhci ;
ptemp = ( PLIST_ENTRY ) pparam - > context ;
if ( uhci = = NULL )
{
2006-08-23 22:17:09 +00:00
return ( UCHAR ) ( pparam - > ret = FALSE ) ;
2006-08-20 14:01:17 +00:00
}
ListFirst ( & uhci - > urb_list , pthis ) ;
while ( pthis )
{
2006-08-18 20:37:55 +00:00
//remove urbs not in the schedule
2006-08-20 14:01:17 +00:00
ListNext ( & uhci - > urb_list , pthis , pnext ) ;
purb = ( PURB ) pthis ;
if ( ( purb - > flags & URB_FLAG_IN_SCHEDULE ) = = 0 )
{
//finished or canceled( not apply for split bulk ).
purb - > flags & = ~ URB_FLAG_STATE_MASK ;
purb - > flags | = URB_FLAG_STATE_FINISHED ;
RemoveEntryList ( pthis ) ;
InsertTailList ( ptemp , pthis ) ;
}
pthis = pnext ;
}
pparam - > ret = TRUE ;
return ( UCHAR ) TRUE ;
}
BOOLEAN
uhci_drop_fsbr ( PUHCI_DEV uhci )
{
if ( uhci = = NULL )
return ( UCHAR ) FALSE ;
uhci - > fsbr_cnt - - ;
if ( uhci - > fsbr_cnt < = 0 )
{
uhci - > skel_term_qh - > link = UHCI_PTR_TERM ;
uhci - > fsbr_cnt = 0 ;
}
return ( UCHAR ) TRUE ;
}
2006-08-23 22:17:09 +00:00
VOID NTAPI
2006-08-20 14:01:17 +00:00
uhci_dpc_callback ( PKDPC dpc , PVOID context , PVOID sysarg1 , PVOID sysarg2 )
{
PUHCI_DEV uhci ;
LIST_HEAD temp_list ;
PLIST_ENTRY pthis , pnext ;
PURB purb ;
PQH_EXTENSION pqhe ;
PUHCI_PENDING_ENDP pending_endp ;
PUSB_DEV pdev ;
PUSB_ENDPOINT pendp ;
2006-08-24 12:58:52 +00:00
BOOLEAN finished ;
2006-08-20 14:01:17 +00:00
LONG i , j ;
ULONG uhci_status , urb_status , toggle = 0 ;
SYNC_PARAM sync_param ;
2006-08-23 22:17:09 +00:00
USE_BASIC_NON_PENDING_IRQL ;
UNREFERENCED_PARAMETER ( dpc ) ;
2006-08-24 17:23:07 +00:00
UNREFERENCED_PARAMETER ( sysarg2 ) ;
2006-08-20 14:01:17 +00:00
uhci = ( PUHCI_DEV ) context ;
if ( uhci = = NULL )
return ;
uhci_status = ( ULONG ) sysarg1 ;
InitializeListHead ( & temp_list ) ;
sync_param . uhci = uhci ;
sync_param . context = ( PVOID ) & temp_list ;
uhci_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_dpc_callback(): entering..., uhci=0x%x \n " , uhci ) ) ;
2007-10-19 23:21:45 +00:00
//remove finished urb from uhci's urb-list
2006-08-20 14:01:17 +00:00
KeSynchronizeExecution ( uhci - > pdev_ext - > uhci_int , uhci_sync_remove_urb_finished , & sync_param ) ;
//release resources( tds, and qhs ) the urb occupied
while ( IsListEmpty ( & temp_list ) = = FALSE )
{
2007-10-19 23:21:45 +00:00
//not in any public queue, if do not access into dev, no race
2006-08-20 14:01:17 +00:00
//condition will occur
purb = ( PURB ) RemoveHeadList ( & temp_list ) ;
urb_status = purb - > status ;
//the only place we do not use this lock on non-pending-endp-list data ops
KeAcquireSpinLockAtDpcLevel ( & uhci - > pending_endp_list_lock ) ;
while ( IsListEmpty ( & purb - > trasac_list ) = = FALSE )
{
pthis = RemoveHeadList ( & purb - > trasac_list ) ;
if ( ( ( ( PTD_EXTENSION ) pthis ) - > flags & UHCI_ITEM_FLAG_TYPE ) = = UHCI_ITEM_FLAG_QH )
{
pqhe = ( PQH_EXTENSION ) pthis ;
lock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
free_qh ( & uhci - > qh_pool , pqhe - > pqh ) ;
unlock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
}
else
{
//must be a td chain
InsertHeadList ( & purb - > trasac_list , pthis ) ;
for ( i = 0 , purb - > bytes_transfered = 0 ; i < purb - > td_count ; i + + )
{
PUHCI_TD ptd ;
// accumulate data transfered in tds
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
if ( ( ptd - > status & TD_CTRL_ACTIVE ) = = 0 & & ( ptd - > status & TD_CTRL_ANY_ERROR ) = = 0 )
{
j = ptd - > status & 0x7ff ;
purb - > bytes_transfered + = ( ( j = = 0x7ff ) ? 0 : ( j + 1 ) ) ;
}
ListNext ( & purb - > trasac_list , pthis , pnext ) ;
pthis = pnext ;
}
if ( urb_status & TD_CTRL_ANY_ERROR )
{
if ( purb - > last_finished_td ! = NULL & & purb - > last_finished_td ! = & purb - > trasac_list )
toggle = ( ( ( PTD_EXTENSION ) purb - > last_finished_td ) - > ptd - > info & ( 1 < < 19 ) ) ;
}
//trick, remove trasac_list
ListFirst ( & purb - > trasac_list , pthis ) ;
RemoveEntryList ( & purb - > trasac_list ) ;
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
free_tds ( & uhci - > td_pool , ( ( PTD_EXTENSION ) pthis ) - > ptd ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
//termination condition
InitializeListHead ( & purb - > trasac_list ) ;
purb - > last_finished_td = NULL ;
}
}
if ( endp_type ( purb - > pendp ) = = USB_ENDPOINT_XFER_ISOC
| | endp_type ( purb - > pendp ) = = USB_ENDPOINT_XFER_INT )
uhci_claim_bandwidth ( uhci , purb , FALSE ) ; //release band-width
KeReleaseSpinLockFromDpcLevel ( & uhci - > pending_endp_list_lock ) ;
uhci_set_error_code ( purb , urb_status ) ;
finished = TRUE ;
//since the ref_count for the urb is not released, we can safely have one
//pointer to dev
pdev = dev_from_endp ( purb - > pendp ) ;
pendp = purb - > pendp ;
if ( purb - > status = = USB_STATUS_BABBLE_DETECTED )
{
usb_dbg_print ( DBGLVL_MEDIUM ,
( " uhci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus \n " ) ) ;
uhci_reset ( uhci ) ;
uhci_start ( & uhci - > hcd_interf ) ;
}
//this will let the new request in uhci_generic_urb_completion to this endp
//be processed rather than queued in the pending_endp_list
lock_dev ( pdev , TRUE ) ;
usb_endp_busy_count_dec ( pendp ) ;
unlock_dev ( pdev , TRUE ) ;
if ( usb_success ( purb - > status ) = = FALSE )
{
// set error code and complete the urb and purb is invalid from this point
uhci_generic_urb_completion ( purb , purb - > context ) ;
}
else
{
if ( ( purb - > pipe & USB_ENDPOINT_XFERTYPE_MASK ) = = USB_ENDPOINT_XFER_BULK )
{
purb - > rest_bytes - = purb - > bytes_transfered ;
if ( purb - > rest_bytes )
{
finished = FALSE ;
}
else
{
uhci_generic_urb_completion ( purb , purb - > context ) ;
}
}
else
{
uhci_generic_urb_completion ( purb , purb - > context ) ;
//purb is now invalid
}
}
KeAcquireSpinLockAtDpcLevel ( & uhci - > pending_endp_list_lock ) ;
lock_dev ( pdev , TRUE ) ;
if ( finished )
pdev - > ref_count - - ;
if ( urb_status & TD_CTRL_ANY_ERROR & & endp_type ( pendp ) ! = USB_ENDPOINT_XFER_CONTROL )
{
pendp - > flags & = ~ USB_ENDP_FLAG_STAT_MASK ;
pendp - > flags | = USB_ENDP_FLAG_STALL ;
}
if ( dev_state ( pdev ) = = USB_DEV_STATE_ZOMB )
{
unlock_dev ( pdev , TRUE ) ;
KeReleaseSpinLockFromDpcLevel ( & uhci - > pending_endp_list_lock ) ;
if ( finished = = FALSE )
{
purb - > status = STATUS_DEVICE_DOES_NOT_EXIST ;
uhci_generic_urb_completion ( purb , purb - > context ) ;
lock_dev ( pdev , TRUE ) ;
pdev - > ref_count - - ;
unlock_dev ( pdev , TRUE ) ;
}
continue ;
}
if ( finished & & IsListEmpty ( & pendp - > urb_list ) = = TRUE )
{
unlock_dev ( pdev , TRUE ) ;
KeReleaseSpinLockFromDpcLevel ( & uhci - > pending_endp_list_lock ) ;
continue ;
}
else if ( finished = = TRUE )
{
//has urb in the endp's urb-list
if ( usb_endp_busy_count ( pendp ) > 0 )
{
//the urbs still have chance to be sheduled but not this time
unlock_dev ( pdev , TRUE ) ;
KeReleaseSpinLockFromDpcLevel ( & uhci - > pending_endp_list_lock ) ;
continue ;
}
}
if ( finished = = FALSE )
{
//a split bulk transfer
purb - > bytes_transfered = 0 ;
purb - > bytes_to_transfer =
UHCI_MAX_TDS_PER_TRANSFER * purb - > pendp - > pusb_endp_desc - > wMaxPacketSize
> purb - > rest_bytes
? purb - > rest_bytes : UHCI_MAX_TDS_PER_TRANSFER * purb - > pendp - > pusb_endp_desc - > wMaxPacketSize ;
//the urb is not finished
purb - > flags & = ~ URB_FLAG_STATE_MASK ;
purb - > flags | = URB_FLAG_STATE_PENDING ;
InsertHeadList ( & pendp - > urb_list , ( PLIST_ENTRY ) purb ) ;
}
pending_endp = alloc_pending_endp ( & uhci - > pending_endp_pool , 1 ) ;
pending_endp - > pendp = pendp ;
InsertTailList ( & uhci - > pending_endp_list , & pending_endp - > endp_link ) ;
unlock_dev ( pdev , TRUE ) ;
KeReleaseSpinLockFromDpcLevel ( & uhci - > pending_endp_list_lock ) ;
}
//ah...exhausted, let's find some in the pending_endp_list to rock
uhci_process_pending_endp ( uhci ) ;
return ;
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_add_device ( PUHCI_DEV uhci , PUSB_DEV dev )
{
if ( dev = = NULL | | uhci = = NULL )
return FALSE ;
return TRUE ;
}
2006-08-23 22:17:09 +00:00
BOOLEAN NTAPI
2006-08-20 14:01:17 +00:00
uhci_sync_cancel_urbs_dev ( PVOID context )
{
//cancel all the urbs on one dev
PUHCI_DEV uhci ;
PUSB_DEV pdev , dest_dev ;
PSYNC_PARAM sync_param ;
PLIST_ENTRY pthis , pnext ;
LONG count ;
sync_param = ( PSYNC_PARAM ) context ;
dest_dev = ( PUSB_DEV ) sync_param - > context ;
uhci = sync_param - > uhci ;
if ( uhci = = NULL | | dest_dev = = NULL )
{
2006-08-23 22:17:09 +00:00
return ( UCHAR ) ( sync_param - > ret = FALSE ) ;
2006-08-20 14:01:17 +00:00
}
count = 0 ;
ListFirst ( & uhci - > urb_list , pthis ) ;
while ( pthis )
{
pdev = dev_from_endp ( ( ( PURB ) pthis ) - > pendp ) ;
if ( pdev = = dest_dev )
{
( ( PURB ) pthis ) - > flags | = URB_FLAG_FORCE_CANCEL ;
}
ListNext ( & uhci - > urb_list , pthis , pnext ) ;
pthis = pnext ;
count + + ;
}
if ( count )
uhci - > skel_term_td - > status | = TD_CTRL_IOC ;
2006-08-23 22:17:09 +00:00
return ( UCHAR ) ( sync_param - > ret = TRUE ) ;
2006-08-20 14:01:17 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_remove_device ( PUHCI_DEV uhci , PUSB_DEV dev )
{
PUHCI_PENDING_ENDP ppending_endp ;
PLIST_ENTRY pthis , pnext ;
PURB purb ;
LIST_HEAD temp_list ;
int i , j , k ;
SYNC_PARAM sync_param ;
2006-08-24 16:21:16 +00:00
USE_BASIC_IRQL ;
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL | | dev = = NULL )
return FALSE ;
InitializeListHead ( & temp_list ) ;
//free pending endp that has urb queued from pending endp list
lock_pending_endp_list ( & uhci - > pending_endp_list_lock ) ;
ListFirst ( & uhci - > pending_endp_list , pthis ) ;
while ( pthis )
{
ppending_endp = ( PUHCI_PENDING_ENDP ) pthis ;
ListNext ( & uhci - > pending_endp_list , pthis , pnext ) ;
if ( dev_from_endp ( ppending_endp - > pendp ) = = dev )
{
RemoveEntryList ( pthis ) ;
free_pending_endp ( & uhci - > pending_endp_pool , struct_ptr ( pthis , UHCI_PENDING_ENDP , endp_link ) ) ;
}
pthis = pnext ;
}
unlock_pending_endp_list ( & uhci - > pending_endp_list_lock ) ;
//cancel all the urbs in the urb-list
sync_param . uhci = uhci ;
sync_param . context = ( PVOID ) dev ;
KeSynchronizeExecution ( uhci - > pdev_ext - > uhci_int , uhci_sync_cancel_urbs_dev , & sync_param ) ;
//cancel all the urb in the endp's urb-list
k = 0 ;
lock_dev ( dev , FALSE ) ;
if ( dev - > usb_config )
{
2007-10-19 23:21:45 +00:00
//only for configed dev
2006-08-20 14:01:17 +00:00
for ( i = 0 ; i < dev - > usb_config - > if_count ; i + + )
{
for ( j = 0 ; j < dev - > usb_config - > interf [ i ] . endp_count ; j + + )
{
ListFirst ( & dev - > usb_config - > interf [ i ] . endp [ j ] . urb_list , pthis ) ;
while ( pthis )
{
ListNext ( & dev - > usb_config - > interf [ i ] . endp [ j ] . urb_list , pthis , pnext ) ;
RemoveEntryList ( pthis ) ;
InsertHeadList ( & temp_list , pthis ) ;
pthis = pnext ;
k + + ;
}
}
}
}
ListFirst ( & dev - > default_endp . urb_list , pthis ) ;
while ( pthis )
{
ListNext ( & dev - > default_endp . urb_list , pthis , pnext ) ;
RemoveEntryList ( pthis ) ;
InsertHeadList ( & temp_list , pthis ) ;
pthis = pnext ;
k + + ;
}
unlock_dev ( dev , FALSE ) ;
if ( IsListEmpty ( & temp_list ) = = FALSE )
{
for ( i = 0 ; i < k ; i + + )
{
//complete those urbs with error
pthis = RemoveHeadList ( & temp_list ) ;
purb = ( PURB ) pthis ;
purb - > status = STATUS_DEVICE_DOES_NOT_EXIST ;
{
uhci_generic_urb_completion ( purb , purb - > context ) ;
}
}
}
lock_dev ( dev , FALSE ) dev - > ref_count - = k ;
unlock_dev ( dev , FALSE ) ;
return TRUE ;
}
//
// assume that the urb has its rest_bytes and bytes_to_transfer set
// and bytes_transfered is zeroed.
// dev_lock must be acquired outside
// urb comes from dev's endpoint urb-list. it is already removed from
// the endpoint urb-list.
//
2006-08-23 22:17:09 +00:00
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_internal_submit_bulk ( PUHCI_DEV uhci , PURB urb )
{
LONG max_packet_size , td_count , offset , bytes_to_transfer , data_load ;
PBYTE start_addr ;
PUHCI_TD ptd ;
PUHCI_QH pqh ;
LIST_ENTRY td_list , * pthis , * pnext ;
2006-08-24 12:58:52 +00:00
BOOLEAN old_toggle , toggle , ret ;
2006-08-20 14:01:17 +00:00
UCHAR pid ;
if ( uhci = = NULL | | urb = = NULL )
return STATUS_INVALID_PARAMETER ;
max_packet_size = endp_max_packet_size ( urb - > pendp ) ;
if ( urb - > bytes_to_transfer = = 0 )
{
return STATUS_INVALID_PARAMETER ;
}
td_count = ( urb - > bytes_to_transfer + max_packet_size - 1 ) / max_packet_size ;
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( can_transfer ( & uhci - > td_pool , td_count ) = = FALSE )
{
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
return STATUS_NO_MORE_ENTRIES ;
}
ptd = alloc_tds ( & uhci - > td_pool , td_count ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( ptd = = NULL )
{
return STATUS_UNSUCCESSFUL ;
}
InitializeListHead ( & td_list ) ;
InsertTailList ( & ptd - > ptde - > vert_link , & td_list ) ;
ListFirst ( & td_list , pthis ) ;
ListNext ( & td_list , pthis , pnext ) ;
start_addr = & urb - > data_buffer [ urb - > data_length - urb - > rest_bytes ] ;
offset = 0 ;
old_toggle = toggle = urb - > pendp - > flags & USB_ENDP_FLAG_DATATOGGLE ? TRUE : FALSE ;
bytes_to_transfer = urb - > bytes_to_transfer ;
urb - > pipe = ( ( max_packet_size - 1 ) < < 21 )
| ( ( ULONG ) endp_num ( urb - > pendp ) < < 15 )
| ( dev_from_endp ( urb - > pendp ) - > dev_addr < < 8 )
| ( ( ULONG ) endp_dir ( urb - > pendp ) ) | USB_ENDPOINT_XFER_BULK ;
pid = ( ( ( ULONG ) urb - > pendp - > pusb_endp_desc - > bEndpointAddress & USB_DIR_IN ) ? USB_PID_IN : USB_PID_OUT ) ;
while ( pthis )
{
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
data_load = max_packet_size < bytes_to_transfer ? max_packet_size : bytes_to_transfer ;
ptd - > purb = urb ;
uhci_fill_td ( ptd ,
( 3 < < TD_CTRL_C_ERR_SHIFT )
| ( TD_CTRL_ACTIVE ) ,
( ( data_load - 1 ) < < 21 )
| ( toggle < < 19 )
| ( ( ULONG ) endp_num ( urb - > pendp ) < < 15 )
| ( dev_from_endp ( urb - > pendp ) - > dev_addr < < 8 )
| pid , MmGetPhysicalAddress ( start_addr + offset ) . LowPart ) ;
bytes_to_transfer - = data_load ;
offset + = data_load ;
if ( pnext )
{
ptd - > link = ( ( PTD_EXTENSION ) pnext ) - > ptd - > phy_addr ;
}
else
{
//Last one, enable ioc and short packet detect if necessary
ptd - > link = UHCI_PTR_TERM ;
ptd - > status | = TD_CTRL_IOC ;
if ( bytes_to_transfer < max_packet_size & & ( pid = = USB_PID_IN ) )
{
//ptd->status |= TD_CTRL_SPD;
}
}
pthis = pnext ;
toggle ^ = 1 ;
if ( pthis )
ListNext ( & td_list , pthis , pnext ) ;
}
ListFirst ( & td_list , pthis ) ;
RemoveEntryList ( & td_list ) ;
lock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
pqh = alloc_qh ( & uhci - > qh_pool ) ;
unlock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
if ( pqh = = NULL )
{
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( pthis )
free_tds ( & uhci - > td_pool , ( ( PTD_EXTENSION ) pthis ) - > ptd ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
return STATUS_NO_MORE_ENTRIES ;
}
urb - > td_count = td_count ;
uhci_insert_tds_qh ( pqh , ( ( PTD_EXTENSION ) pthis ) - > ptd ) ;
uhci_insert_qh_urb ( urb , pqh ) ;
urb - > pendp - > flags =
( urb - > pendp - > flags & ~ USB_ENDP_FLAG_DATATOGGLE ) | ( toggle ? USB_ENDP_FLAG_DATATOGGLE : 0 ) ;
usb_endp_busy_count_inc ( urb - > pendp ) ;
uhci_insert_urb_to_schedule ( uhci , urb , ret ) ;
if ( ret = = FALSE )
{
// undo all we have done
RemoveEntryList ( & pqh - > pqhe - > vert_link ) ; //remove qh from td_chain
RemoveEntryList ( & urb - > trasac_list ) ;
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( pthis )
free_tds ( & uhci - > td_pool , ( ( PTD_EXTENSION ) pthis ) - > ptd ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
lock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
if ( pqh )
free_qh ( & uhci - > qh_pool , pqh ) ;
unlock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
InitializeListHead ( & urb - > trasac_list ) ;
usb_endp_busy_count_dec ( urb - > pendp ) ;
urb - > pendp - > flags =
( urb - > pendp - > flags & ~ USB_ENDP_FLAG_DATATOGGLE ) | ( old_toggle ? USB_ENDP_FLAG_DATATOGGLE : 0 ) ;
return STATUS_UNSUCCESSFUL ;
}
return STATUS_SUCCESS ;
}
2006-08-23 22:17:09 +00:00
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_internal_submit_ctrl ( PUHCI_DEV uhci , PURB urb )
{
LIST_ENTRY td_list , * pthis , * pnext ;
LONG i , td_count ;
LONG toggle ;
LONG max_packet_size , bytes_to_transfer , bytes_rest , start_idx ;
PUHCI_TD ptd ;
PUHCI_QH pqh ;
ULONG dev_addr ;
PUSB_DEV pdev ;
2006-08-24 12:58:52 +00:00
BOOLEAN ret ;
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL | | urb = = NULL )
return STATUS_INVALID_PARAMETER ;
toggle = 0 ;
bytes_rest = urb - > rest_bytes ;
bytes_to_transfer = urb - > bytes_to_transfer ;
max_packet_size = endp_max_packet_size ( urb - > pendp ) ;
start_idx = urb - > data_length - urb - > rest_bytes ;
td_count = 2 + ( urb - > bytes_to_transfer + max_packet_size - 1 ) / max_packet_size ;
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( can_transfer ( & uhci - > td_pool , td_count ) = = FALSE )
{
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
return STATUS_NO_MORE_ENTRIES ;
}
ptd = alloc_tds ( & uhci - > td_pool , td_count ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( ptd = = NULL )
{
return STATUS_UNSUCCESSFUL ;
}
InsertTailList ( & ptd - > ptde - > vert_link , & td_list ) ;
ListFirst ( & td_list , pthis ) ;
ListNext ( & td_list , pthis , pnext ) ;
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
pdev = dev_from_endp ( urb - > pendp ) ;
dev_addr = pdev - > dev_addr ;
if ( dev_state ( pdev ) < = USB_DEV_STATE_RESET )
dev_addr = 0 ;
usb_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_internal_submit_ctrl(): dev_addr =0x%x \n " , dev_addr ) ) ;
RtlCopyMemory ( uhci - > io_buf , urb - > setup_packet , 8 ) ;
if ( ( urb - > setup_packet [ 0 ] & USB_DIR_IN ) = = 0 ) //out
RtlCopyMemory ( & uhci - > io_buf [ 8 ] , urb - > data_buffer , bytes_to_transfer ) ;
else
RtlZeroMemory ( & uhci - > io_buf [ 8 ] , bytes_to_transfer ) ;
uhci_fill_td ( ptd ,
( 3 < < TD_CTRL_C_ERR_SHIFT ) | ( TD_CTRL_ACTIVE ) ,
( 7 < < 21 ) | ( ( ( ULONG ) endp_num ( urb - > pendp ) ) < < 15 ) | ( dev_addr < < 8 ) | ( USB_PID_SETUP ) ,
//uhci->io_buf_logic_addr.LowPart);
MmGetPhysicalAddress ( urb - > setup_packet ) . LowPart ) ;
ptd - > link = ( ( PTD_EXTENSION ) pnext ) - > ptd - > phy_addr ;
pthis = pnext ;
ListNext ( & td_list , pthis , pnext ) ;
urb - > pipe = ( ( max_packet_size - 1 ) < < 21 )
| ( ( ULONG ) endp_num ( urb - > pendp ) < < 15 )
| ( dev_addr < < 8 ) | ( pdev - > flags & USB_DEV_FLAG_LOW_SPEED ) | USB_ENDPOINT_XFER_CONTROL ;
for ( i = 0 , toggle = 1 ; ( ( i < td_count - 2 ) & & pthis ) ; i + + , toggle ^ = 1 )
{
//construct tds for DATA packets of data stage.
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
uhci_fill_td ( ptd ,
( 3 < < TD_CTRL_C_ERR_SHIFT )
| ( TD_CTRL_ACTIVE ) ,
( ( bytes_to_transfer >
max_packet_size ? max_packet_size - 1 : bytes_to_transfer -
1 ) < < 21 ) | ( toggle < < 19 ) | ( ( ( ULONG ) endp_num ( urb - >
pendp ) ) < < 15 ) | ( dev_addr < < 8 ) |
( ( urb - > setup_packet [ 0 ] & USB_DIR_IN ) ? USB_PID_IN : USB_PID_OUT ) ,
//uhci->io_buf_logic_addr.LowPart + 8 + i * max_packet_size );
MmGetPhysicalAddress ( & urb - > data_buffer [ start_idx + i * max_packet_size ] ) . LowPart ) ;
if ( pnext )
ptd - > link = ( ( PTD_EXTENSION ) pnext ) - > ptd - > phy_addr ;
if ( i < td_count - 3 )
{
bytes_to_transfer - = max_packet_size ;
}
else
{
if ( bytes_to_transfer > 0 )
{
if ( bytes_to_transfer < max_packet_size & & ( urb - > setup_packet [ 0 ] & USB_DIR_IN ) )
ptd - > status | = TD_CTRL_SPD ;
}
}
pthis = pnext ;
if ( pthis )
ListNext ( & td_list , pthis , pnext ) ;
}
if ( pnext )
ptd - > link = ( ( PTD_EXTENSION ) pnext ) - > ptd - > phy_addr ;
ListFirstPrev ( & td_list , pthis ) ;
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
//the last is an IN transaction
uhci_fill_td ( ptd ,
( 3 < < TD_CTRL_C_ERR_SHIFT )
| ( TD_CTRL_ACTIVE | TD_CTRL_IOC ) ,
( UHCI_NULL_DATA_SIZE < < 21 )
| ( 1 < < 19 )
| ( ( ( ULONG ) endp_num ( urb - > pendp ) ) < < 15 )
| ( dev_addr < < 8 )
| ( ( td_count > 2 )
? ( ( urb - > setup_packet [ 0 ] & USB_DIR_IN ) ? USB_PID_OUT : USB_PID_IN ) : USB_PID_IN ) , 0 ) ;
ptd - > link = UHCI_PTR_TERM ;
ListFirst ( & td_list , pthis ) ;
RemoveEntryList ( & td_list ) ;
lock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
pqh = alloc_qh ( & uhci - > qh_pool ) ;
unlock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
if ( pqh = = NULL )
{
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( pthis )
free_tds ( & uhci - > td_pool , ( ( PTD_EXTENSION ) pthis ) - > ptd ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
return STATUS_NO_MORE_ENTRIES ;
}
urb - > td_count = td_count ;
uhci_insert_tds_qh ( pqh , ( ( PTD_EXTENSION ) pthis ) - > ptd ) ;
uhci_insert_qh_urb ( urb , pqh ) ;
usb_endp_busy_count_inc ( urb - > pendp ) ;
uhci_insert_urb_to_schedule ( uhci , urb , ret ) ;
if ( ret = = FALSE )
{
RemoveEntryList ( & pqh - > pqhe - > vert_link ) ;
RemoveEntryList ( & urb - > trasac_list ) ;
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( pthis )
free_tds ( & uhci - > td_pool , ( ( PTD_EXTENSION ) pthis ) - > ptd ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
lock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
if ( pqh )
free_qh ( & uhci - > qh_pool , pqh ) ;
unlock_qh_pool ( & uhci - > qh_pool , TRUE ) ;
InitializeListHead ( & urb - > trasac_list ) ;
usb_endp_busy_count_dec ( urb - > pendp ) ;
return STATUS_UNSUCCESSFUL ;
}
return STATUS_SUCCESS ;
}
2006-08-23 22:17:09 +00:00
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_internal_submit_int ( PUHCI_DEV uhci , PURB urb )
{
LONG i ;
LONG toggle = 0 ;
LONG max_packet_size ;
PUHCI_TD ptd ;
2006-08-24 12:58:52 +00:00
BOOLEAN ret ;
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL | | urb = = NULL )
2006-09-08 22:00:39 +00:00
{
uhci_dbg_print ( DBGLVL_MEDIUM ,
( " uhci_internal_submit_int(): uhci=0x%x, urb=0x%x "
" returning STATUS_INVALID_PARAMETER! \n " , uhci , urb ) ) ;
2006-08-20 14:01:17 +00:00
return STATUS_INVALID_PARAMETER ;
2006-09-08 22:00:39 +00:00
}
2006-08-20 14:01:17 +00:00
toggle = ( urb - > pendp - > flags & USB_ENDP_FLAG_DATATOGGLE ) ? TRUE : FALSE ;
max_packet_size = endp_max_packet_size ( urb - > pendp ) ;
if ( max_packet_size < urb - > data_length | | max_packet_size = = 0 | | max_packet_size > 64 )
{
2006-09-08 22:00:39 +00:00
uhci_dbg_print ( DBGLVL_MEDIUM ,
( " uhci_internal_submit_int(): max_packet_size=%d, urb->data_length=%d "
" returning STATUS_INVALID_PARAMETER! \n " , max_packet_size , urb - > data_length ) ) ;
2006-08-20 14:01:17 +00:00
return STATUS_INVALID_PARAMETER ;
}
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
ptd = alloc_td ( & uhci - > td_pool ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( ptd = = NULL )
return STATUS_NO_MORE_ENTRIES ;
for ( i = 1 ; i < = 7 ; i + + )
{
if ( ( ( ULONG ) max_packet_size ) > > i )
continue ;
else
break ;
}
i - - ;
i & = 7 ;
urb - > pipe = ( ( ( ULONG ) urb - > pendp - > pusb_endp_desc - > bInterval ) < < 24 )
| ( i < < 21 )
| ( toggle < < 19 )
| ( ( ULONG ) endp_num ( urb - > pendp ) < < 15 )
| ( ( ( ULONG ) dev_from_endp ( urb - > pendp ) - > dev_addr ) < < 8 )
| USB_DIR_IN | ( dev_from_endp ( urb - > pendp ) - > flags & USB_DEV_FLAG_LOW_SPEED ) | USB_ENDPOINT_XFER_INT ;
uhci_fill_td ( ptd ,
( 3 < < TD_CTRL_C_ERR_SHIFT )
| ( TD_CTRL_ACTIVE )
| ( ( urb - > data_length < max_packet_size ? TD_CTRL_SPD : 0 ) )
| ( TD_CTRL_IOC ) ,
( ( ( ULONG ) max_packet_size - 1 ) < < 21 )
| ( toggle < < 19 )
| ( ( ULONG ) endp_num ( urb - > pendp ) < < 15 )
| ( ( ( ULONG ) dev_from_endp ( urb - > pendp ) - > dev_addr & 0x7f ) < < 8 )
| USB_PID_IN , MmGetPhysicalAddress ( urb - > data_buffer ) . LowPart ) ;
toggle ^ = 1 ;
urb - > td_count = 1 ;
InitializeListHead ( & urb - > trasac_list ) ;
InsertTailList ( & urb - > trasac_list , & ptd - > ptde - > vert_link ) ;
//indirectly guarded by pending_endp_list_lock
if ( uhci_claim_bandwidth ( uhci , urb , TRUE ) = = FALSE )
{
InitializeListHead ( & urb - > trasac_list ) ;
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
free_td ( & uhci - > td_pool , ptd ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
return STATUS_NO_MORE_ENTRIES ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
urb - > pendp - > flags = ( urb - > pendp - > flags & ~ USB_ENDP_FLAG_DATATOGGLE ) | ( toggle < < 31 ) ;
usb_endp_busy_count_inc ( urb - > pendp ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci_insert_urb_to_schedule ( uhci , urb , ret ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( ret = = FALSE )
{
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
if ( ptd )
free_td ( & uhci - > td_pool , ptd ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
InitializeListHead ( & urb - > trasac_list ) ;
usb_endp_busy_count_dec ( urb - > pendp ) ;
urb - > pendp - > flags = ( urb - > pendp - > flags & ~ USB_ENDP_FLAG_DATATOGGLE ) | ( ( toggle ^ 1 ) < < 31 ) ;
uhci_claim_bandwidth ( uhci , urb , FALSE ) ;
return STATUS_UNSUCCESSFUL ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return STATUS_SUCCESS ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
2006-08-23 22:17:09 +00:00
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_internal_submit_iso ( PUHCI_DEV uhci , PURB urb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_TD ptd ;
LIST_ENTRY td_list , * pthis , * pnext ;
int i ;
2006-08-24 12:58:52 +00:00
BOOLEAN toggle , ret ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL | | urb = = NULL )
return STATUS_INVALID_PARAMETER ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( urb - > iso_frame_count = = 0 )
return STATUS_INVALID_PARAMETER ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( can_transfer ( & uhci - > td_pool , urb - > iso_frame_count ) = = FALSE )
{
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
return STATUS_NO_MORE_ENTRIES ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
ptd = alloc_tds ( & uhci - > td_pool , urb - > iso_frame_count ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( ptd = = NULL )
{
return STATUS_UNSUCCESSFUL ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
InsertTailList ( & ptd - > ptde - > vert_link , & td_list ) ;
ListFirst ( & td_list , pthis ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
urb - > td_count = urb - > iso_frame_count ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
urb - > pipe = ( ( ( ULONG ) urb - > iso_packet_desc [ 0 ] . length ) < < 21 )
| ( ( ULONG ) endp_num ( urb - > pendp ) < < 15 )
| ( ( ( ULONG ) dev_from_endp ( urb - > pendp ) - > dev_addr ) < < 8 )
| ( ( ULONG ) endp_dir ( urb - > pendp ) ) | USB_ENDPOINT_XFER_ISOC ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
for ( i = 0 ; i < urb - > iso_frame_count & & pthis ; i + + )
{
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
uhci_fill_td ( ptd ,
( 3 < < TD_CTRL_C_ERR_SHIFT )
| ( TD_CTRL_ACTIVE )
| ( TD_CTRL_IOS ) ,
( ( ( ULONG ) urb - > iso_packet_desc [ i ] . length - 1 ) < < 21 )
| ( 0 < < 19 )
| ( ( ULONG ) endp_num ( urb - > pendp ) < < 15 )
| ( ( ( ULONG ) dev_from_endp ( urb - > pendp ) - > dev_addr ) < < 8 )
| ( ( urb - > pendp - > pusb_endp_desc - > bEndpointAddress & USB_DIR_IN )
? USB_PID_OUT : USB_PID_IN ) ,
MmGetPhysicalAddress ( & urb - > data_buffer [ urb - > iso_packet_desc [ i ] . offset ] ) . LowPart ) ;
toggle ^ = 1 ;
ListNext ( & td_list , pthis , pnext ) ;
pthis = pnext ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
ptd - > status | = TD_CTRL_IOC ; //need interrupt
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
ListFirst ( & td_list , pthis ) ;
RemoveEntryList ( & td_list ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
InsertTailList ( pthis , & urb - > trasac_list ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
//indirectly guarded by pending_endp_list_lock
if ( uhci_claim_bandwidth ( uhci , urb , TRUE ) = = FALSE )
{
//bad news: we can not allocate the enough bandwidth for the urb
RemoveEntryList ( & urb - > trasac_list ) ;
InitializeListHead ( & urb - > trasac_list ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
free_tds ( & uhci - > td_pool , ( ( PTD_EXTENSION ) pthis ) - > ptd ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
return STATUS_NO_MORE_ENTRIES ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
usb_endp_busy_count_inc ( urb - > pendp ) ;
uhci_insert_urb_to_schedule ( uhci , urb , ret ) ;
if ( ret = = FALSE )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
usb_endp_busy_count_dec ( urb - > pendp ) ;
RemoveEntryList ( & urb - > trasac_list ) ;
lock_td_pool ( & uhci - > td_pool , TRUE ) ;
free_tds ( & uhci - > td_pool , ( ( PTD_EXTENSION ) pthis ) - > ptd ) ;
unlock_td_pool ( & uhci - > td_pool , TRUE ) ;
uhci_claim_bandwidth ( uhci , urb , FALSE ) ;
return STATUS_UNSUCCESSFUL ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return STATUS_SUCCESS ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
// runs in uhci_isr
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_is_xfer_finished ( PURB urb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PLIST_ENTRY pthis , pnext ;
PUHCI_TD ptd ;
2006-08-24 12:58:52 +00:00
BOOLEAN ret = TRUE ;
2006-08-20 14:01:17 +00:00
PTD_EXTENSION ptde ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( urb - > last_finished_td = = NULL )
{
urb - > last_finished_td = & urb - > trasac_list ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( & urb - > trasac_list = = urb - > last_finished_td )
ListFirst ( & urb - > trasac_list , pthis )
2006-08-23 22:17:09 +00:00
else
2006-08-20 14:01:17 +00:00
ListNext ( & urb - > trasac_list , urb - > last_finished_td , pthis ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
while ( pthis )
{
if ( ( ( ( PTD_EXTENSION ) pthis ) - > flags & UHCI_ITEM_FLAG_TYPE ) ! = UHCI_ITEM_FLAG_TD )
{
ListNext ( & urb - > trasac_list , pthis , pnext ) ;
pthis = pnext ;
continue ;
}
else
{
ptde = ( PTD_EXTENSION ) pthis ;
ptd = ptde - > ptd ;
ASSERT ( ptd ! = NULL ) ;
if ( ptd - > status & TD_CTRL_ACTIVE )
{
//still active
ret = FALSE ;
break ;
}
//let's see whether error occured
if ( ( ptd - > status & TD_CTRL_ANY_ERROR ) = = 0 )
{
urb - > last_finished_td = pthis ;
ListNext ( & urb - > trasac_list , pthis , pnext ) ;
pthis = pnext ;
continue ;
}
else
{
urb - > status = ptd - > status ;
pthis = NULL ;
continue ;
}
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( pthis = = NULL )
ret = TRUE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return ret ;
2006-08-18 20:37:55 +00:00
}
// executed in isr, and have frame_list_lock acquired, so
// never try to acquire any spin-lock
// remove the bulk urb from schedule, and mark it not in
// the schedule
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_remove_urb_from_schedule ( PUHCI_DEV uhci , PURB urb )
2006-08-18 20:37:55 +00:00
{
2006-08-24 12:58:52 +00:00
BOOLEAN ret = FALSE ;
2006-08-20 14:01:17 +00:00
{
switch ( urb - > pipe & USB_ENDPOINT_XFERTYPE_MASK )
{
case USB_ENDPOINT_XFER_BULK :
{
ret = uhci_remove_bulk_from_schedule ( uhci , urb ) ;
break ;
}
case USB_ENDPOINT_XFER_CONTROL :
{
ret = uhci_remove_ctrl_from_schedule ( uhci , urb ) ;
break ;
}
case USB_ENDPOINT_XFER_INT :
{
ret = uhci_remove_int_from_schedule ( uhci , urb ) ;
break ;
}
case USB_ENDPOINT_XFER_ISOC :
{
ret = uhci_remove_iso_from_schedule ( uhci , urb ) ;
break ;
}
}
}
return ret ;
2006-08-18 20:37:55 +00:00
}
// executed in isr, and have frame_list_lock acquired, so
// never try to acquire any spin-lock
// remove the bulk urb from schedule, and mark it not in
// the schedule
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_remove_bulk_from_schedule ( PUHCI_DEV uhci , PURB urb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_QH pqh , pnext_qh , pprev_qh ;
PLIST_ENTRY pthis , pnext , pprev ;
LONG i ;
if ( uhci = = NULL | | urb = = NULL )
return FALSE ;
ListFirst ( & urb - > trasac_list , pthis ) ;
pqh = ( ( PQH_EXTENSION ) pthis ) - > pqh ;
ListFirst ( & pqh - > pqhe - > hori_link , pnext ) ;
ListFirstPrev ( & pqh - > pqhe - > hori_link , pprev ) ;
if ( pprev = = NULL | | pnext = = NULL )
return FALSE ;
pnext_qh = struct_ptr ( pnext , QH_EXTENSION , hori_link ) - > pqh ;
pprev_qh = struct_ptr ( pprev , QH_EXTENSION , hori_link ) - > pqh ;
if ( pprev ! = pnext )
{
2007-10-19 23:21:45 +00:00
//not the last one
2006-08-20 14:01:17 +00:00
pprev_qh - > link = pnext_qh - > phy_addr ;
}
else
{
2007-10-19 23:21:45 +00:00
//only two qhs in the list
2006-08-20 14:01:17 +00:00
for ( i = 0 ; i < UHCI_MAX_SKELQHS ; i + + )
{
if ( pprev_qh = = uhci - > skel_qh [ i ] )
{
break ;
}
}
ASSERT ( i < UHCI_MAX_SKELQHS - 1 ) ;
pprev_qh - > link = uhci - > skel_qh [ i + 1 ] - > phy_addr ;
}
RemoveEntryList ( & pqh - > pqhe - > hori_link ) ;
urb - > flags & = ~ URB_FLAG_IN_SCHEDULE ;
if ( ( urb - > pipe & USB_DEV_FLAG_LOW_SPEED ) = = 0 )
uhci_drop_fsbr ( uhci ) ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_remove_iso_from_schedule ( PUHCI_DEV uhci , PURB urb )
2006-08-18 20:37:55 +00:00
{
2006-08-23 22:17:09 +00:00
PUHCI_TD ptd , pprev_td ;
2006-08-20 14:01:17 +00:00
PLIST_ENTRY pthis , pnext , pprev ;
int i , idx ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL | | urb = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
ListFirst ( & urb - > trasac_list , pthis ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
for ( i = 0 ; i < urb - > iso_frame_count & & pthis ; i + + )
{
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
idx = ( urb - > iso_start_frame + i ) & ( UHCI_MAX_FRAMES - 1 ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
ListFirstPrev ( & ptd - > ptde - > hori_link , pprev ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( pprev = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( pprev = = & uhci - > frame_list_cpu [ idx ] . td_link )
{
uhci - > frame_list [ idx ] = ptd - > link ;
}
2006-08-18 20:37:55 +00:00
else
2006-08-20 14:01:17 +00:00
{
pprev_td = struct_ptr ( pprev , TD_EXTENSION , hori_link ) - > ptd ;
pprev_td - > link = ptd - > link ;
}
RemoveEntryList ( & ptd - > ptde - > hori_link ) ;
ListNext ( & urb - > trasac_list , pthis , pnext ) ;
pthis = pnext ;
}
urb - > flags & = ~ URB_FLAG_IN_SCHEDULE ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_remove_int_from_schedule ( PUHCI_DEV uhci , PURB urb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_TD ptd , pnext_td , pprev_td ;
PLIST_ENTRY pthis , pnext , pprev ;
LONG i ;
if ( uhci = = NULL | | urb = = NULL )
return FALSE ;
ListFirst ( & urb - > trasac_list , pthis ) ;
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
ListFirst ( & ptd - > ptde - > hori_link , pnext ) ;
ListFirstPrev ( & ptd - > ptde - > hori_link , pprev ) ;
if ( pprev = = NULL | | pnext = = NULL )
return FALSE ;
pnext_td = struct_ptr ( pnext , TD_EXTENSION , hori_link ) - > ptd ;
pprev_td = struct_ptr ( pprev , TD_EXTENSION , hori_link ) - > ptd ;
if ( pprev_td ! = pnext_td )
pprev_td - > link = pnext_td - > phy_addr ;
else
{
//the last one
for ( i = UHCI_MAX_SKELTDS - 2 ; i > = 0 ; i - - )
{
//UHCI_MAX_SKELTDS -1 skel tds for int transfer
if ( pprev_td = = uhci - > skel_td [ i ] )
break ;
}
ASSERT ( i > = 0 ) ;
if ( i = = 0 )
{
pprev_td - > link = uhci - > skel_qh [ 0 ] - > phy_addr ;
}
else
{
pprev_td - > link = uhci - > skel_td [ i - 1 ] - > phy_addr ;
}
}
RemoveEntryList ( & ptd - > ptde - > hori_link ) ;
urb - > flags & = ~ URB_FLAG_IN_SCHEDULE ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_insert_tds_qh ( PUHCI_QH pqh , PUHCI_TD td_chain )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
if ( pqh = = NULL | | td_chain = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
InsertTailList ( & td_chain - > ptde - > vert_link , & pqh - > pqhe - > vert_link ) ;
pqh - > element = td_chain - > phy_addr ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_insert_qh_urb ( PURB urb , PUHCI_QH qh_chain )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
if ( urb = = NULL | | qh_chain = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
InsertTailList ( & qh_chain - > pqhe - > vert_link , & urb - > trasac_list ) ;
qh_chain - > pqhe - > purb = urb ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
// must have dev_lock and frame_list_lock acquired
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_insert_urb_schedule ( PUHCI_DEV uhci , PURB urb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_QH pqh , pskel_qh , pnext_qh ;
PUHCI_TD ptd , plast_td ;
PLIST_ENTRY pthis , pnext ;
int i ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL | | urb = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
ListFirst ( & urb - > trasac_list , pthis ) ;
if ( pthis = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
InsertTailList ( & uhci - > urb_list , ( PLIST_ENTRY ) urb ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
urb - > flags & = ~ URB_FLAG_STATE_MASK ;
urb - > flags | = URB_FLAG_STATE_IN_PROCESS | URB_FLAG_IN_SCHEDULE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
switch ( endp_type ( urb - > pendp ) )
{
case USB_ENDPOINT_XFER_CONTROL :
{
pqh = ( ( PQH_EXTENSION ) pthis ) - > pqh ;
if ( ( dev_from_endp ( urb - > pendp ) - > flags & USB_DEV_FLAG_LOW_SPEED ) = = 0 )
{
pskel_qh = uhci - > skel_hs_control_qh ;
pnext_qh = uhci - > skel_bulk_qh ;
}
else
{
pskel_qh = uhci - > skel_ls_control_qh ;
pnext_qh = uhci - > skel_hs_control_qh ;
}
ListFirstPrev ( & pskel_qh - > pqhe - > hori_link , pthis ) ;
if ( pthis = = NULL )
pthis = & pskel_qh - > pqhe - > hori_link ;
InsertTailList ( & pskel_qh - > pqhe - > hori_link , & pqh - > pqhe - > hori_link ) ;
pqh - > link = pnext_qh - > phy_addr ;
struct_ptr ( pthis , QH_EXTENSION , hori_link ) - > pqh - > link = pqh - > phy_addr ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
//full speed band reclaimation
if ( ( urb - > pipe & USB_DEV_FLAG_LOW_SPEED ) = = 0 )
{
uhci - > fsbr_cnt + + ;
if ( uhci - > fsbr_cnt = = 1 )
{
uhci - > skel_term_qh - > link = uhci - > skel_hs_control_qh - > phy_addr ;
}
}
return TRUE ;
}
case USB_ENDPOINT_XFER_BULK :
{
pqh = ( ( PQH_EXTENSION ) pthis ) - > pqh ;
ListFirstPrev ( & uhci - > skel_bulk_qh - > pqhe - > hori_link , pthis ) ;
if ( pthis = = NULL )
pthis = & uhci - > skel_bulk_qh - > pqhe - > hori_link ;
InsertTailList ( & uhci - > skel_bulk_qh - > pqhe - > hori_link , & pqh - > pqhe - > hori_link ) ;
pqh - > link = uhci - > skel_term_qh - > phy_addr ;
struct_ptr ( pthis , QH_EXTENSION , hori_link ) - > pqh - > link = pqh - > phy_addr ;
2006-08-18 20:37:55 +00:00
//full speed band reclaimation
2006-08-20 14:01:17 +00:00
uhci - > fsbr_cnt + + ;
if ( uhci - > fsbr_cnt = = 1 )
{
uhci - > skel_term_qh - > link = uhci - > skel_hs_control_qh - > phy_addr ; ;
}
return TRUE ;
}
case USB_ENDPOINT_XFER_INT :
{
2006-08-18 20:37:55 +00:00
//bandwidth claim is done outside
2006-08-20 14:01:17 +00:00
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
get_int_idx ( urb , i ) ;
ListFirstPrev ( & uhci - > skel_td [ i ] - > ptde - > hori_link , pthis ) ;
if ( pthis = = NULL )
pthis = & uhci - > skel_td [ i ] - > ptde - > hori_link ;
InsertTailList ( & uhci - > skel_td [ i ] - > ptde - > hori_link , & ptd - > ptde - > hori_link ) ;
if ( i > 0 )
{
ptd - > link = uhci - > skel_td [ i - 1 ] - > phy_addr ;
}
else if ( i = = 0 )
{
ptd - > link = uhci - > skel_qh [ 0 ] - > phy_addr ;
}
//finally link the previous td to this td
struct_ptr ( pthis , TD_EXTENSION , hori_link ) - > ptd - > link = ptd - > phy_addr ;
return TRUE ;
}
case USB_ENDPOINT_XFER_ISOC :
{
for ( i = 0 ; i < urb - > iso_frame_count ; i + + )
{
ptd = ( ( PTD_EXTENSION ) pthis ) - > ptd ;
InsertTailList ( & uhci - > frame_list_cpu [ ( urb - > iso_start_frame + i ) & 0x3ff ] . td_link ,
& ptd - > ptde - > hori_link ) ;
if ( IsListEmpty ( & uhci - > frame_list_cpu [ ( urb - > iso_start_frame + i ) & 0x3ff ] . td_link ) = = TRUE )
{
ptd - > link = uhci - > frame_list [ ( urb - > iso_start_frame + i ) & 0x3ff ] ;
uhci - > frame_list [ i ] = ptd - > phy_addr ;
}
else
{
ListFirstPrev ( & uhci - > frame_list_cpu [ ( urb - > iso_start_frame + i ) & 0x3ff ] . td_link , pnext ) ;
plast_td = struct_ptr ( pnext , TD_EXTENSION , hori_link ) - > ptd ;
ptd - > link = plast_td - > link ;
plast_td - > link = ptd - > phy_addr ;
}
ListNext ( & urb - > trasac_list , pthis , pnext ) ;
pthis = pnext ;
}
return TRUE ;
}
}
return FALSE ;
2006-08-18 20:37:55 +00:00
}
//this function used as the KeSynchronizeExecution param to delegate control to uhci_insert_urb_schedule
2006-08-24 12:58:52 +00:00
BOOLEAN NTAPI
2006-08-20 14:01:17 +00:00
uhci_sync_insert_urb_schedule ( PVOID context )
{
PSYNC_PARAM sync_param ;
PUHCI_DEV uhci ;
PURB purb ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
sync_param = ( PSYNC_PARAM ) context ;
if ( sync_param = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci = sync_param - > uhci ;
purb = ( PURB ) sync_param - > context ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL | | purb = = NULL )
2006-08-23 22:17:09 +00:00
return ( UCHAR ) ( sync_param - > ret = FALSE ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return ( UCHAR ) ( sync_param - > ret = uhci_insert_urb_schedule ( uhci , purb ) ) ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
// be sure pending_endp_list_lock acquired
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_claim_bandwidth ( PUHCI_DEV uhci ,
PURB urb ,
2006-08-24 12:58:52 +00:00
BOOLEAN claim_bw //true to claim bandwidth, false to free bandwidth
2006-08-20 14:01:17 +00:00
)
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
UCHAR type ;
2006-08-24 12:58:52 +00:00
BOOLEAN ls , can_alloc ;
2006-08-20 14:01:17 +00:00
LONG bus_time , us ;
LONG i , idx , j , start_frame , interval ;
if ( urb = = NULL )
return FALSE ;
can_alloc = TRUE ;
type = ( UCHAR ) ( urb - > pipe & USB_ENDPOINT_XFERTYPE_MASK ) ;
if ( type = = USB_ENDPOINT_XFER_BULK | | type = = USB_ENDPOINT_XFER_CONTROL )
{
return FALSE ;
}
ls = ( urb - > pipe & USB_DEV_FLAG_LOW_SPEED ) ? TRUE : FALSE ;
if ( type = = USB_ENDPOINT_XFER_INT )
{
start_frame = 0 ;
i = urb - > data_length ;
bus_time = usb_calc_bus_time ( ls , FALSE , FALSE , i ) ;
us = ns_to_us ( bus_time ) ;
i = ( urb - > pipe > > 24 ) ; //polling interval
for ( interval = 0 , j = 0 ; j < 8 ; j + + )
{
if ( i & ( 1 < < j ) )
{
interval = j ;
}
}
interval = 1 < < interval ;
start_frame = interval - 1 ;
if ( claim_bw )
{
for ( idx = 0 ; idx < UHCI_MAX_FRAMES ; idx + = interval )
{
if ( uhci - > frame_bw [ idx ] < us )
{
can_alloc = FALSE ;
break ;
}
}
if ( ! can_alloc )
{
return FALSE ;
}
for ( idx = start_frame ; idx < UHCI_MAX_FRAMES ; idx + = interval )
{
uhci - > frame_bw [ idx ] - = us ;
}
}
else
{
for ( idx = start_frame ; idx < UHCI_MAX_FRAMES ; idx + = interval )
{
uhci - > frame_bw [ idx ] + = us ;
}
}
}
else if ( type = = USB_ENDPOINT_XFER_ISOC )
{
if ( claim_bw )
{
for ( i = 0 ; i < urb - > iso_frame_count ; i + + )
{
bus_time = usb_calc_bus_time ( FALSE ,
( urb - > pipe & USB_DIR_IN )
? TRUE : FALSE , TRUE , urb - > iso_packet_desc [ i ] . length ) ;
urb - > iso_packet_desc [ i ] . bus_time = ns_to_us ( bus_time ) ;
}
for ( i = 0 ; i < urb - > iso_frame_count ; i + + )
{
if ( uhci - > frame_bw [ ( urb - > iso_start_frame + i ) & 0x3ff ] < urb - > iso_packet_desc [ i ] . bus_time )
{
can_alloc = FALSE ;
break ;
}
}
if ( ! can_alloc )
{
return FALSE ;
}
for ( i = 0 ; i < urb - > iso_frame_count ; i + + )
{
uhci - > frame_bw [ ( urb - > iso_start_frame + i ) & 0x3ff ] - = urb - > iso_packet_desc [ i ] . bus_time ;
}
}
else
{
for ( i = 0 ; i < urb - > iso_frame_count ; i + + )
{
uhci - > frame_bw [ ( urb - > iso_start_frame + i ) & 0x3ff ] + = urb - > iso_packet_desc [ i ] . bus_time ;
}
}
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
return TRUE ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
//cancel a single urb
2006-08-23 22:17:09 +00:00
BOOLEAN NTAPI
2006-08-20 14:01:17 +00:00
uhci_sync_cancel_urb ( PVOID context )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_DEV uhci ;
PSYNC_PARAM sync_param ;
PURB purb2 , dest_urb ;
PLIST_ENTRY pthis , pnext ;
2006-08-24 12:58:52 +00:00
BOOLEAN found = FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( context = = NULL )
return FALSE ;
sync_param = ( PSYNC_PARAM ) context ;
uhci = sync_param - > uhci ;
dest_urb = ( PURB ) sync_param - > context ;
if ( uhci = = NULL | | dest_urb = = NULL )
2006-08-23 22:17:09 +00:00
return ( UCHAR ) ( sync_param - > ret = FALSE ) ;
2006-08-20 14:01:17 +00:00
ListFirst ( & uhci - > urb_list , pthis ) ;
while ( pthis )
{
purb2 = ( PURB ) pthis ;
if ( purb2 = = dest_urb )
{
found = TRUE ;
purb2 - > flags | = URB_FLAG_FORCE_CANCEL ;
break ;
}
ListNext ( & uhci - > urb_list , pthis , pnext ) ;
pthis = pnext ;
}
if ( found )
uhci - > skel_term_td - > status | = TD_CTRL_IOC ;
return ( UCHAR ) ( sync_param - > ret = found ) ;
2006-08-18 20:37:55 +00:00
}
//note any fields of the purb can not be referenced unless it is found in some queue
2006-08-20 14:01:17 +00:00
NTSTATUS
uhci_cancel_urb ( PUHCI_DEV uhci , PUSB_DEV pdev , PUSB_ENDPOINT pendp , PURB purb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PLIST_ENTRY pthis , pnext ;
2006-08-24 12:58:52 +00:00
BOOLEAN found ;
2006-08-20 14:01:17 +00:00
PURB purb2 ;
SYNC_PARAM sync_param ;
2006-08-23 22:17:09 +00:00
USE_BASIC_NON_PENDING_IRQL ;
2006-08-20 14:01:17 +00:00
if ( uhci = = NULL | | purb = = NULL | | pdev = = NULL | | pendp = = NULL )
return STATUS_INVALID_PARAMETER ;
lock_dev ( pdev , FALSE ) ;
if ( dev_state ( pdev ) = = USB_DEV_STATE_ZOMB )
{
unlock_dev ( pdev , FALSE ) ;
//delegate to remove device for this job
return STATUS_DEVICE_DOES_NOT_EXIST ;
}
if ( dev_from_endp ( pendp ) ! = pdev )
{
unlock_dev ( pdev , FALSE ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( endp_state ( pendp ) = = USB_ENDP_FLAG_STALL )
{
//it will be canceled in uhci_process_pending_endp
unlock_dev ( pdev , FALSE ) ;
return USB_STATUS_ENDPOINT_HALTED ;
}
found = FALSE ;
ListFirst ( & pendp - > urb_list , pthis ) ;
while ( pthis )
{
purb2 = ( PURB ) pthis ;
if ( purb2 = = purb )
{
found = TRUE ;
RemoveEntryList ( pthis ) ;
InitializeListHead ( pthis ) ;
break ;
}
ListNext ( & pendp - > urb_list , pthis , pnext ) ;
pthis = pnext ;
}
unlock_dev ( pdev , FALSE ) ;
if ( found )
{
purb - > status = STATUS_CANCELLED ;
uhci_generic_urb_completion ( purb , purb - > context ) ;
lock_dev ( pdev , FALSE ) ;
pdev - > ref_count - - ;
unlock_dev ( pdev , FALSE ) ;
return STATUS_SUCCESS ;
}
// search the urb in the urb-list and try to cancel
sync_param . uhci = uhci ;
sync_param . context = purb ;
KeSynchronizeExecution ( uhci - > pdev_ext - > uhci_int , uhci_sync_cancel_urb , & sync_param ) ;
2006-08-24 17:23:07 +00:00
found = ( BOOLEAN ) sync_param . ret ;
2006-08-20 14:01:17 +00:00
if ( found )
return USB_STATUS_CANCELING ;
return STATUS_INVALID_PARAMETER ;
2006-08-18 20:37:55 +00:00
}
VOID
2006-08-20 14:01:17 +00:00
uhci_generic_urb_completion ( PURB purb , PVOID context )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUSB_DEV pdev ;
2006-08-23 22:17:09 +00:00
USE_NON_PENDING_IRQL ;
2006-08-20 14:01:17 +00:00
old_irql = KeGetCurrentIrql ( ) ;
if ( old_irql > DISPATCH_LEVEL )
TRAP ( ) ;
if ( old_irql < DISPATCH_LEVEL )
KeRaiseIrql ( DISPATCH_LEVEL , & old_irql ) ;
pdev = purb - > pdev ;
if ( purb = = NULL )
return ;
if ( pdev = = NULL )
return ;
lock_dev ( pdev , TRUE ) ;
if ( dev_state ( pdev ) = = USB_DEV_STATE_ZOMB )
{
unlock_dev ( pdev , TRUE ) ;
goto LBL_CLIENT_PROCESS ;
}
if ( usb_error ( purb - > status ) )
{
pdev - > error_count + + ;
}
if ( purb - > pendp = = & pdev - > default_endp )
{
if ( usb_halted ( purb - > status ) )
{
pdev - > time_out_count + + ;
if ( pdev - > time_out_count > 3 )
{
dev_set_state ( pdev , USB_DEV_STATE_ZOMB ) ;
uhci_dbg_print ( DBGLVL_MAXIMUM ,
( " uhci_generic_urb_completion(): contiguous error 3 times, dev 0x%x is deactivated \n " ,
pdev ) ) ;
}
}
else
pdev - > time_out_count = 0 ;
}
unlock_dev ( pdev , TRUE ) ;
LBL_CLIENT_PROCESS :
if ( purb - > completion )
purb - > completion ( purb , context ) ;
if ( old_irql < DISPATCH_LEVEL )
KeLowerIrql ( old_irql ) ;
return ;
2006-08-18 20:37:55 +00:00
}
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_rh_submit_urb ( PUSB_DEV pdev , PURB purb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUSB_DEV_MANAGER dev_mgr ;
PTIMER_SVC ptimer ;
PUSB_CTRL_SETUP_PACKET psetup ;
PUHCI_DEV uhci ;
NTSTATUS status ;
2006-08-23 22:17:09 +00:00
USHORT port_status ;
2006-08-18 20:37:55 +00:00
# ifndef INCLUDE_EHCI
2006-08-20 14:01:17 +00:00
PHUB_EXTENSION hub_ext ;
2006-08-18 20:37:55 +00:00
# else
2006-08-20 14:01:17 +00:00
PHUB2_EXTENSION hub_ext ;
2006-08-18 20:37:55 +00:00
# endif
2006-08-20 14:01:17 +00:00
PUSB_PORT_STATUS ps , psret ;
LONG i ;
2006-08-23 22:17:09 +00:00
USE_NON_PENDING_IRQL ;
2006-08-20 14:01:17 +00:00
if ( pdev = = NULL | | purb = = NULL )
return STATUS_INVALID_PARAMETER ;
dev_mgr = dev_mgr_from_dev ( pdev ) ;
KeAcquireSpinLock ( & dev_mgr - > timer_svc_list_lock , & old_irql ) ;
lock_dev ( pdev , FALSE ) ;
if ( dev_state ( pdev ) = = USB_DEV_STATE_ZOMB )
{
unlock_dev ( pdev , FALSE ) ;
KeReleaseSpinLock ( & dev_mgr - > timer_svc_list_lock , old_irql ) ;
return STATUS_DEVICE_DOES_NOT_EXIST ;
}
uhci = uhci_from_hcd ( pdev - > hcd ) ;
psetup = ( PUSB_CTRL_SETUP_PACKET ) purb - > setup_packet ;
2006-08-18 20:37:55 +00:00
# ifndef INCLUDE_EHCI
2006-08-20 14:01:17 +00:00
hub_ext = ( ( PHUB_EXTENSION ) pdev - > dev_ext ) ;
2006-08-18 20:37:55 +00:00
# else
2006-08-20 14:01:17 +00:00
hub_ext = ( ( PHUB2_EXTENSION ) pdev - > dev_ext ) ;
2006-08-18 20:37:55 +00:00
# endif
2006-08-20 14:01:17 +00:00
switch ( endp_type ( purb - > pendp ) )
{
case USB_ENDPOINT_XFER_CONTROL :
{
if ( psetup - > bmRequestType = = 0xa3 & & psetup - > bRequest = = USB_REQ_GET_STATUS )
{
//get-port-status
if ( psetup - > wIndex = = 0 | | psetup - > wIndex > 2 | | psetup - > wLength < 4 )
{
purb - > status = STATUS_INVALID_PARAMETER ;
break ;
}
if ( psetup - > wIndex = = 1 )
{
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + USBPORTSC1 ) ) ;
ps = & hub_ext - > rh_port1_status ;
}
else
{
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + USBPORTSC2 ) ) ;
ps = & hub_ext - > rh_port2_status ;
}
psret = ( PUSB_PORT_STATUS ) purb - > data_buffer ;
ps - > wPortStatus = 0 ;
if ( status & USBPORTSC_CCS )
{
ps - > wPortStatus | = USB_PORT_STAT_CONNECTION ;
}
if ( status & USBPORTSC_PE )
{
ps - > wPortStatus | = USB_PORT_STAT_ENABLE ;
}
if ( status & USBPORTSC_PR )
{
ps - > wPortStatus | = USB_PORT_STAT_RESET ;
}
if ( status & USBPORTSC_SUSP )
{
ps - > wPortStatus | = USB_PORT_STAT_SUSPEND ;
}
if ( status & USBPORTSC_LSDA )
{
ps - > wPortStatus | = USB_PORT_STAT_LOW_SPEED ;
}
//always power on
ps - > wPortStatus | = USB_PORT_STAT_POWER ;
//now set change field
if ( status & USBPORTSC_CSC )
{
ps - > wPortChange | = USB_PORT_STAT_C_CONNECTION ;
}
if ( status & USBPORTSC_PEC )
{
ps - > wPortChange | = USB_PORT_STAT_C_ENABLE ;
}
//don't touch other fields, will be filled by
//other function
usb_dbg_print ( DBGLVL_MAXIMUM ,
( " uhci_rh_submit_urb(): get port status, wPortStatus=0x%x, wPortChange=0x%x, address=0x%x \n " ,
ps - > wPortStatus , ps - > wPortChange , ps ) ) ;
psret - > wPortChange = ps - > wPortChange ;
psret - > wPortStatus = ps - > wPortStatus ;
purb - > status = STATUS_SUCCESS ;
break ;
}
else if ( psetup - > bmRequestType = = 0x23 & & psetup - > bRequest = = USB_REQ_CLEAR_FEATURE )
{
//clear-port-feature
if ( psetup - > wIndex = = 0 | | psetup - > wIndex > 2 )
{
purb - > status = STATUS_INVALID_PARAMETER ;
break ;
}
if ( psetup - > wIndex = = 1 )
{
i = USBPORTSC1 ;
ps = & hub_ext - > rh_port1_status ;
}
else
{
i = USBPORTSC2 ;
ps = & hub_ext - > rh_port2_status ;
}
purb - > status = STATUS_SUCCESS ;
switch ( psetup - > wValue )
{
case USB_PORT_FEAT_C_CONNECTION :
{
ps - > wPortChange & = ~ USB_PORT_STAT_C_CONNECTION ;
SET_RH_PORTSTAT ( i , USBPORTSC_CSC ) ;
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + i ) ) ;
usb_dbg_print ( DBGLVL_MAXIMUM ,
( " uhci_rh_submit_urb(): clear csc, port%d=0x%x \n " , psetup - > wIndex ,
status ) ) ;
break ;
}
case USB_PORT_FEAT_C_ENABLE :
{
ps - > wPortChange & = ~ USB_PORT_STAT_C_ENABLE ;
SET_RH_PORTSTAT ( i , USBPORTSC_PEC ) ;
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + i ) ) ;
usb_dbg_print ( DBGLVL_MAXIMUM ,
( " uhci_rh_submit_urb(): clear pec, port%d=0x%x \n " , psetup - > wIndex ,
status ) ) ;
break ;
}
case USB_PORT_FEAT_C_RESET :
{
ps - > wPortChange & = ~ USB_PORT_STAT_C_RESET ;
//the reset signal is down in rh_timer_svc_reset_port_completion
//so enable the port here
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + i ) ) ;
usb_dbg_print ( DBGLVL_MAXIMUM ,
( " uhci_rh_submit_urb(): clear pr, enable pe, port%d=0x%x \n " ,
psetup - > wIndex , status ) ) ;
break ;
}
case USB_PORT_FEAT_ENABLE :
{
ps - > wPortStatus & = ~ USB_PORT_STAT_ENABLE ;
CLR_RH_PORTSTAT ( i , USBPORTSC_PE ) ;
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + i ) ) ;
usb_dbg_print ( DBGLVL_MAXIMUM ,
( " uhci_rh_submit_urb(): clear pe, port%d=0x%x \n " , psetup - > wIndex ,
status ) ) ;
break ;
}
default :
purb - > status = STATUS_UNSUCCESSFUL ;
}
break ;
}
else if ( psetup - > bmRequestType = = 0xd3 & & psetup - > bRequest = = HUB_REQ_GET_STATE )
{
2007-10-19 23:21:45 +00:00
// get bus state
2006-08-20 14:01:17 +00:00
if ( psetup - > wIndex = = 0 | | psetup - > wIndex > 2 | | psetup - > wLength = = 0 )
{
purb - > status = STATUS_INVALID_PARAMETER ;
break ;
}
if ( psetup - > wIndex = = 1 )
{
i = USBPORTSC1 ;
}
else
{
i = USBPORTSC2 ;
}
2006-08-23 22:17:09 +00:00
port_status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + i ) ) ;
purb - > data_buffer [ 0 ] = ( port_status & USBPORTSC_LS ) ;
2006-08-20 14:01:17 +00:00
// reverse the order
purb - > data_buffer [ 0 ] ^ = 0x3 ;
purb - > status = STATUS_SUCCESS ;
break ;
}
else if ( psetup - > bmRequestType = = 0x23 & & psetup - > bRequest = = USB_REQ_SET_FEATURE )
{
//reset port
if ( psetup - > wValue ! = USB_PORT_FEAT_RESET )
{
purb - > status = STATUS_INVALID_PARAMETER ;
uhci_dbg_print ( DBGLVL_MAXIMUM ,
( " uhci_rh_submit_urb(): set feature with wValue=0x%x \n " , psetup - > wValue ) ) ;
break ;
}
if ( psetup - > wIndex = = 1 )
{
i = USBPORTSC1 ;
}
else
{
i = USBPORTSC2 ;
}
ptimer = alloc_timer_svc ( & dev_mgr - > timer_svc_pool , 1 ) ;
ptimer - > threshold = 0 ; // within [ 50ms, 60ms ], one tick is 10 ms
ptimer - > context = ( ULONG ) purb ;
ptimer - > pdev = pdev ;
ptimer - > func = rh_timer_svc_reset_port_completion ;
//start the timer
pdev - > ref_count + = 2 ; //one for timer and one for urb
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + i ) ) ;
usb_dbg_print ( DBGLVL_MAXIMUM ,
( " uhci_rh_submit_urb(): reset port, port%d=0x%x \n " , psetup - > wIndex , status ) ) ;
InsertTailList ( & dev_mgr - > timer_svc_list , & ptimer - > timer_svc_link ) ;
purb - > status = STATUS_PENDING ;
}
else
{
purb - > status = STATUS_INVALID_PARAMETER ;
}
break ;
}
case USB_ENDPOINT_XFER_INT :
{
ptimer = alloc_timer_svc ( & dev_mgr - > timer_svc_pool , 1 ) ;
ptimer - > threshold = RH_INTERVAL ;
ptimer - > context = ( ULONG ) purb ;
ptimer - > pdev = pdev ;
ptimer - > func = rh_timer_svc_int_completion ;
//start the timer
InsertTailList ( & dev_mgr - > timer_svc_list , & ptimer - > timer_svc_link ) ;
2006-08-23 22:17:09 +00:00
usb_dbg_print ( DBGLVL_ULTRA ,
2006-08-20 14:01:17 +00:00
( " uhci_rh_submit_urb(): current rh's ref_count=0x%x \n " , pdev - > ref_count ) ) ;
pdev - > ref_count + = 2 ; //one for timer and one for urb
purb - > status = STATUS_PENDING ;
break ;
}
case USB_ENDPOINT_XFER_BULK :
case USB_ENDPOINT_XFER_ISOC :
default :
{
purb - > status = STATUS_INVALID_PARAMETER ;
break ;
}
}
unlock_dev ( pdev , FALSE ) ;
KeReleaseSpinLock ( & dev_mgr - > timer_svc_list_lock , old_irql ) ;
return purb - > status ;
2006-08-18 20:37:55 +00:00
}
//must have rh dev_lock acquired
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_rh_reset_port ( PHCD hcd , UCHAR port_idx )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
LONG i ;
PUHCI_DEV uhci ;
ULONG status ;
if ( port_idx ! = 1 & & port_idx ! = 2 )
return FALSE ;
if ( hcd = = NULL )
return FALSE ;
if ( port_idx = = 1 )
{
i = USBPORTSC1 ;
}
else
{
i = USBPORTSC2 ;
}
uhci = uhci_from_hcd ( hcd ) ;
//assert the reset signal,(implicitly disable the port)
SET_RH_PORTSTAT ( i , USBPORTSC_PR ) ;
usb_wait_ms_dpc ( 50 ) ;
//clear the reset signal, delay port enable till clearing port feature
CLR_RH_PORTSTAT ( i , USBPORTSC_PR ) ;
usb_wait_us_dpc ( 10 ) ;
SET_RH_PORTSTAT ( i , USBPORTSC_PE ) ;
//recovery time 10ms
usb_wait_ms_dpc ( 10 ) ;
SET_RH_PORTSTAT ( i , 0x0a ) ;
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + i ) ) ;
usb_dbg_print ( DBGLVL_MAXIMUM , ( " uhci_rh_reset_port(): status after written=0x%x \n " , status ) ) ;
return TRUE ;
2006-08-18 20:37:55 +00:00
}
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_dispatch_irp ( IN PDEVICE_OBJECT DeviceObject , IN PIRP irp )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PDEVICE_EXTENSION pdev_ext ;
PUSB_DEV_MANAGER dev_mgr ;
PUHCI_DEV uhci ;
pdev_ext = DeviceObject - > DeviceExtension ;
uhci = pdev_ext - > uhci ;
dev_mgr = uhci - > hcd_interf . hcd_get_dev_mgr ( & uhci - > hcd_interf ) ;
return dev_mgr_dispatch ( dev_mgr , irp ) ;
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
VOID NTAPI
2006-08-20 14:01:17 +00:00
uhci_unload ( IN PDRIVER_OBJECT DriverObject )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PDEVICE_OBJECT pdev ;
PDEVICE_EXTENSION pdev_ext ;
PUSB_DEV_MANAGER dev_mgr ;
pdev = DriverObject - > DeviceObject ;
if ( pdev = = NULL )
return ;
pdev_ext = pdev - > DeviceExtension ;
if ( pdev_ext = = NULL )
return ;
dev_mgr = & g_dev_mgr ;
if ( dev_mgr = = NULL )
return ;
//
// set the termination flag
//
dev_mgr - > term_flag = TRUE ;
2006-08-18 20:37:55 +00:00
//
2007-10-19 23:21:45 +00:00
// wake up the thread if it is
2006-08-20 14:01:17 +00:00
//
KeSetEvent ( & dev_mgr - > wake_up_event , 0 , FALSE ) ;
KeWaitForSingleObject ( dev_mgr - > pthread , Executive , KernelMode , TRUE , NULL ) ;
ObDereferenceObject ( dev_mgr - > pthread ) ;
dev_mgr - > pthread = NULL ;
// for( i = 0; i < dev_mgr->hcd_count; i++ )
// dev_mgr->hcd_array[ i ]->hcd_release( dev_mgr->hcd_array[ i ]);
dev_mgr_release_hcd ( dev_mgr ) ;
return ;
2006-08-18 20:37:55 +00:00
}
//the following are for hcd interface methods
VOID
2006-08-20 14:01:17 +00:00
uhci_set_dev_mgr ( struct _HCD * hcd , PUSB_DEV_MANAGER dev_mgr )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
hcd - > dev_mgr = dev_mgr ;
2006-08-18 20:37:55 +00:00
}
PUSB_DEV_MANAGER
2006-08-20 14:01:17 +00:00
uhci_get_dev_mgr ( struct _HCD * hcd )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
return hcd - > dev_mgr ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
ULONG
uhci_get_type ( struct _HCD * hcd )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
return ( hcd - > flags & HCD_TYPE_MASK ) ;
2006-08-18 20:37:55 +00:00
}
VOID
2006-08-20 14:01:17 +00:00
uhci_set_id ( struct _HCD * hcd , UCHAR id )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
hcd - > flags & = ~ HCD_ID_MASK ;
hcd - > flags | = ( HCD_ID_MASK & id ) ;
2006-08-18 20:37:55 +00:00
}
UCHAR
2006-08-20 14:01:17 +00:00
uhci_get_id ( struct _HCD * hcd )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
return ( UCHAR ) ( hcd - > flags & HCD_ID_MASK ) ;
2006-08-18 20:37:55 +00:00
}
UCHAR
2006-08-20 14:01:17 +00:00
uhci_alloc_addr ( struct _HCD * hcd )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
LONG i ;
if ( hcd = = NULL )
return 0 ;
for ( i = 1 ; i < MAX_DEVS ; i + + )
{
if ( hcd - > dev_addr_map [ i > > 3 ] & ( 1 < < ( i & 7 ) ) )
{
continue ;
}
else
{
break ;
}
}
if ( i > = MAX_DEVS )
return 0xff ;
hcd - > dev_addr_map [ i > > 3 ] | = ( 1 < < ( i & 7 ) ) ;
hcd - > conn_count + + ;
return ( BYTE ) i ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
2006-08-18 20:37:55 +00:00
VOID
2006-08-20 14:01:17 +00:00
uhci_free_addr ( struct _HCD * hcd , UCHAR addr )
{
if ( addr & 0x80 )
return ;
if ( hcd = = NULL )
return ;
hcd - > dev_addr_map [ addr > > 3 ] & = ~ ( 1 < < ( addr & 7 ) ) ;
return ;
2006-08-18 20:37:55 +00:00
}
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_submit_urb2 ( struct _HCD * hcd , PUSB_DEV pdev , PUSB_ENDPOINT pendp , PURB purb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
return uhci_submit_urb ( uhci_from_hcd ( hcd ) , pdev , pendp , purb ) ;
2006-08-18 20:37:55 +00:00
}
PUSB_DEV
2006-08-20 14:01:17 +00:00
uhci_get_root_hub ( struct _HCD * hcd )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
return uhci_from_hcd ( hcd ) - > root_hub ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
2006-08-18 20:37:55 +00:00
VOID
2006-08-20 14:01:17 +00:00
uhci_set_root_hub ( struct _HCD * hcd , PUSB_DEV root_hub )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
if ( hcd = = NULL | | root_hub = = NULL )
return ;
uhci_from_hcd ( hcd ) - > root_hub = root_hub ;
return ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_remove_device2 ( struct _HCD * hcd , PUSB_DEV pdev )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
if ( hcd = = NULL | | pdev = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return uhci_remove_device ( uhci_from_hcd ( hcd ) , pdev ) ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_hcd_release ( struct _HCD * hcd )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_DEV uhci ;
PDEVICE_EXTENSION pdev_ext ;
if ( hcd = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci = uhci_from_hcd ( hcd ) ;
pdev_ext = uhci - > pdev_ext ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return uhci_release ( pdev_ext - > pdev_obj ) ;
2006-08-18 20:37:55 +00:00
}
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_cancel_urb2 ( struct _HCD * hcd , PUSB_DEV pdev , PUSB_ENDPOINT pendp , PURB purb )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_DEV uhci ;
if ( hcd = = NULL )
return STATUS_INVALID_PARAMETER ;
uhci = uhci_from_hcd ( hcd ) ;
return uhci_cancel_urb ( uhci , pdev , pendp , purb ) ;
2006-08-18 20:37:55 +00:00
}
2006-08-24 12:58:52 +00:00
BOOLEAN
2006-08-20 14:01:17 +00:00
uhci_rh_get_dev_change ( PHCD hcd , PBYTE buf )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PUHCI_DEV uhci ;
ULONG status ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( hcd = = NULL | | buf = = NULL )
return FALSE ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci = uhci_from_hcd ( hcd ) ;
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + USBPORTSC1 ) ) ;
2006-08-23 22:17:09 +00:00
usb_dbg_print ( DBGLVL_ULTRA , ( " uhci_rh_get_dev_change(): rh port1 status=0x%x \n " , status ) ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( ( status & USBPORTSC_PEC ) | | ( status & USBPORTSC_CSC ) )
{
buf [ 0 ] | = ( 1 < < 1 ) ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
status = READ_PORT_USHORT ( ( PUSHORT ) ( uhci - > port_base + USBPORTSC2 ) ) ;
2006-08-23 22:17:09 +00:00
usb_dbg_print ( DBGLVL_ULTRA , ( " uhci_rh_get_dev_change(): rh port2 status=0x%x \n " , status ) ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
if ( ( status & USBPORTSC_PEC ) | | ( status & USBPORTSC_CSC ) )
{
buf [ 0 ] | = ( 1 < < 2 ) ;
}
return TRUE ;
2006-08-18 20:37:55 +00:00
}
NTSTATUS
2006-08-20 14:01:17 +00:00
uhci_dispatch ( PHCD hcd , LONG disp_code , PVOID param ) // locking depends on type of code
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
if ( hcd = = NULL )
return FALSE ;
switch ( disp_code )
{
case HCD_DISP_READ_PORT_COUNT :
{
if ( param = = NULL )
return STATUS_INVALID_PARAMETER ;
* ( ( PUCHAR ) param ) = 2 ;
return STATUS_SUCCESS ;
}
case HCD_DISP_READ_RH_DEV_CHANGE :
{
if ( uhci_rh_get_dev_change ( hcd , param ) = = FALSE )
return STATUS_INVALID_PARAMETER ;
return STATUS_SUCCESS ;
}
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
return STATUS_NOT_IMPLEMENTED ;
2006-08-18 20:37:55 +00:00
}
2006-08-20 14:01:17 +00:00
2006-08-18 20:37:55 +00:00
VOID
2006-08-20 14:01:17 +00:00
uhci_init_hcd_interface ( PUHCI_DEV uhci )
{
uhci - > hcd_interf . hcd_set_dev_mgr = uhci_set_dev_mgr ;
uhci - > hcd_interf . hcd_get_dev_mgr = uhci_get_dev_mgr ;
uhci - > hcd_interf . hcd_get_type = uhci_get_type ;
uhci - > hcd_interf . hcd_set_id = uhci_set_id ;
uhci - > hcd_interf . hcd_get_id = uhci_get_id ;
uhci - > hcd_interf . hcd_alloc_addr = uhci_alloc_addr ;
uhci - > hcd_interf . hcd_free_addr = uhci_free_addr ;
uhci - > hcd_interf . hcd_submit_urb = uhci_submit_urb2 ;
uhci - > hcd_interf . hcd_generic_urb_completion = uhci_generic_urb_completion ;
uhci - > hcd_interf . hcd_get_root_hub = uhci_get_root_hub ;
uhci - > hcd_interf . hcd_set_root_hub = uhci_set_root_hub ;
uhci - > hcd_interf . hcd_remove_device = uhci_remove_device2 ;
uhci - > hcd_interf . hcd_rh_reset_port = uhci_rh_reset_port ;
uhci - > hcd_interf . hcd_release = uhci_hcd_release ;
uhci - > hcd_interf . hcd_cancel_urb = uhci_cancel_urb2 ;
uhci - > hcd_interf . hcd_start = uhci_start ;
uhci - > hcd_interf . hcd_dispatch = uhci_dispatch ;
uhci - > hcd_interf . flags = HCD_TYPE_UHCI ; //hcd types | hcd id
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
NTSTATUS NTAPI
2006-08-20 14:01:17 +00:00
generic_dispatch_irp ( IN PDEVICE_OBJECT dev_obj , IN PIRP irp )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PDEVEXT_HEADER dev_ext ;
dev_ext = ( PDEVEXT_HEADER ) dev_obj - > DeviceExtension ;
if ( dev_ext & & dev_ext - > dispatch )
return dev_ext - > dispatch ( dev_obj , irp ) ;
irp - > IoStatus . Information = 0 ;
EXIT_DISPATCH ( STATUS_UNSUCCESSFUL , irp ) ;
2006-08-18 20:37:55 +00:00
}
2006-08-23 22:17:09 +00:00
VOID NTAPI
2006-08-20 14:01:17 +00:00
generic_start_io ( IN PDEVICE_OBJECT dev_obj , IN PIRP irp )
2006-08-18 20:37:55 +00:00
{
2006-08-20 14:01:17 +00:00
PDEVEXT_HEADER dev_ext ;
KIRQL old_irql ;
IoAcquireCancelSpinLock ( & old_irql ) ;
if ( irp ! = dev_obj - > CurrentIrp | | irp - > Cancel )
{
IoReleaseCancelSpinLock ( old_irql ) ;
return ;
}
else
{
2006-08-23 22:17:09 +00:00
( void ) IoSetCancelRoutine ( irp , NULL ) ;
2006-08-20 14:01:17 +00:00
IoReleaseCancelSpinLock ( old_irql ) ;
}
dev_ext = ( PDEVEXT_HEADER ) dev_obj - > DeviceExtension ;
if ( dev_ext & & dev_ext - > start_io )
{
dev_ext - > start_io ( dev_obj , irp ) ;
return ;
}
irp - > IoStatus . Information = 0 ;
irp - > IoStatus . Status = STATUS_UNSUCCESSFUL ;
IoStartNextPacket ( dev_obj , FALSE ) ;
IoCompleteRequest ( irp , IO_NO_INCREMENT ) ;
2006-08-18 20:37:55 +00:00
}
NTSTATUS
2006-08-20 14:01:17 +00:00
DriverEntry ( IN PDRIVER_OBJECT DriverObject , IN PUNICODE_STRING RegistryPath )
2006-08-18 20:37:55 +00:00
{
2006-08-24 18:48:15 +00:00
# if DBG
2006-08-18 20:37:55 +00:00
NTSTATUS ntStatus = STATUS_SUCCESS ;
2006-08-20 14:01:17 +00:00
// should be done before any debug output is done.
2006-08-18 20:37:55 +00:00
// read our debug verbosity level from the registry
//NetacOD_GetRegistryDword( NetacOD_REGISTRY_PARAMETERS_PATH, //absolute registry path
2006-08-20 14:01:17 +00:00
// L"DebugLevel", // REG_DWORD ValueName
// &gDebugLevel ); // Value receiver
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
// debug_level = DBGLVL_MAXIMUM;
2006-08-18 20:37:55 +00:00
# endif
2006-08-20 14:01:17 +00:00
uhci_dbg_print_cond ( DBGLVL_MINIMUM , DEBUG_UHCI ,
( " Entering DriverEntry(), RegistryPath= \n %ws \n " , RegistryPath - > Buffer ) ) ;
2006-08-18 20:37:55 +00:00
// Remember our driver object, for when we create our child PDO
usb_driver_obj = DriverObject ;
//
// Create dispatch points for create, close, unload
2006-08-20 14:01:17 +00:00
DriverObject - > MajorFunction [ IRP_MJ_CREATE ] = generic_dispatch_irp ;
DriverObject - > MajorFunction [ IRP_MJ_CLOSE ] = generic_dispatch_irp ;
2006-08-18 20:37:55 +00:00
DriverObject - > DriverUnload = uhci_unload ;
// User mode DeviceIoControl() calls will be routed here
2006-08-20 14:01:17 +00:00
DriverObject - > MajorFunction [ IRP_MJ_DEVICE_CONTROL ] = generic_dispatch_irp ;
DriverObject - > MajorFunction [ IRP_MJ_INTERNAL_DEVICE_CONTROL ] = generic_dispatch_irp ;
2006-08-18 20:37:55 +00:00
// User mode ReadFile()/WriteFile() calls will be routed here
2006-08-20 14:01:17 +00:00
DriverObject - > MajorFunction [ IRP_MJ_WRITE ] = generic_dispatch_irp ;
DriverObject - > MajorFunction [ IRP_MJ_READ ] = generic_dispatch_irp ;
DriverObject - > MajorFunction [ IRP_MJ_SHUTDOWN ] = generic_dispatch_irp ;
DriverObject - > MajorFunction [ IRP_MJ_SCSI ] = generic_dispatch_irp ;
DriverObject - > MajorFunction [ IRP_MJ_FLUSH_BUFFERS ] = generic_dispatch_irp ;
DriverObject - > DriverStartIo = generic_start_io ;
// routines for handling system PNP and power management requests
2006-08-18 20:37:55 +00:00
//DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = generic_dispatch_irp;
2007-10-19 23:21:45 +00:00
// The Functional Device Object (FDO) will not be created for PNP devices until
2006-08-18 20:37:55 +00:00
// this routine is called upon device plug-in.
2006-08-20 14:01:17 +00:00
RtlZeroMemory ( & g_dev_mgr , sizeof ( USB_DEV_MANAGER ) ) ;
g_dev_mgr . usb_driver_obj = DriverObject ;
2006-08-18 20:37:55 +00:00
# ifdef INCLUDE_EHCI
2006-08-20 14:01:17 +00:00
ehci_probe ( DriverObject , RegistryPath , & g_dev_mgr ) ;
2006-08-18 20:37:55 +00:00
# endif
2006-08-20 14:01:17 +00:00
uhci_probe ( DriverObject , RegistryPath , & g_dev_mgr ) ;
if ( dev_mgr_strobe ( & g_dev_mgr ) = = FALSE )
{
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
dev_mgr_release_hcd ( & g_dev_mgr ) ;
return STATUS_UNSUCCESSFUL ;
}
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
dev_mgr_start_hcd ( & g_dev_mgr ) ;
2006-08-18 20:37:55 +00:00
2006-08-20 14:01:17 +00:00
uhci_dbg_print_cond ( DBGLVL_DEFAULT , DEBUG_UHCI , ( " DriverEntry(): exiting... (%x) \n " , ntStatus ) ) ;
return STATUS_SUCCESS ;
2006-08-18 20:37:55 +00:00
}
//note: the initialization will be in the following order
// uhci_probe
// dev_mgr_strobe
// uhci_start
// to kill dev_mgr_thread:
// dev_mgr->term_flag = TRUE;
// KeSetEvent( &dev_mgr->wake_up_event );
// this piece of code must run at passive-level