mirror of
https://github.com/reactos/reactos.git
synced 2024-07-21 03:37:57 +00:00
Separate Device Manager code (what was left from it in hub.c) from Hub code
svn path=/trunk/; revision=23890
This commit is contained in:
parent
252a2d1598
commit
7bfe48177c
|
@ -21,6 +21,23 @@
|
|||
|
||||
#include "usbdriver.h"
|
||||
|
||||
#define realloc_buf( pdEV, puRB ) \
|
||||
{\
|
||||
PBYTE data_buf;\
|
||||
int i;\
|
||||
data_buf = usb_alloc_mem( NonPagedPool, ( pdEV )->desc_buf_size += 1024 );\
|
||||
RtlZeroMemory( data_buf, ( pdEV )->desc_buf_size );\
|
||||
for( i = 0; i < ( LONG )( puRB )->context; i++ )\
|
||||
{\
|
||||
data_buf[ i ] = ( pdEV )->desc_buf[ i ];\
|
||||
}\
|
||||
usb_free_mem( ( pdEV )->desc_buf );\
|
||||
( pdEV )->desc_buf = data_buf;\
|
||||
( pdEV )->pusb_dev_desc = ( PUSB_DEVICE_DESC )( pdEV )->desc_buf;\
|
||||
( puRB )->data_buffer = &data_buf[ ( LONG ) ( puRB )->context ];\
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
USB_DRIVER g_driver_list[DEVMGR_MAX_DRIVERS];
|
||||
|
@ -742,3 +759,758 @@ dev_mgr_disconnect_dev(PUSB_DEV pdev)
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
//called in hub_set_address_completion
|
||||
BOOLEAN
|
||||
dev_mgr_start_config_dev(PUSB_DEV pdev)
|
||||
{
|
||||
PBYTE data_buf;
|
||||
PUSB_CTRL_SETUP_PACKET psetup;
|
||||
PURB purb;
|
||||
PHCD hcd;
|
||||
USE_BASIC_NON_PENDING_IRQL;
|
||||
|
||||
hcd_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_start_config_dev: pdev=%p\n", pdev));
|
||||
|
||||
if (pdev == NULL)
|
||||
return FALSE;
|
||||
|
||||
lock_dev(pdev, TRUE);
|
||||
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hcd = pdev->hcd;
|
||||
|
||||
//first, get device descriptor
|
||||
purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
|
||||
data_buf = usb_alloc_mem(NonPagedPool, 512);
|
||||
if (purb == NULL)
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RtlZeroMemory(purb, sizeof(URB));
|
||||
RtlZeroMemory(data_buf, 512);
|
||||
|
||||
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
|
||||
|
||||
purb->data_buffer = data_buf; // user data
|
||||
purb->data_length = 8; // get partial desc
|
||||
|
||||
pdev->desc_buf = data_buf;
|
||||
pdev->desc_buf_size = 512;
|
||||
|
||||
purb->pdev = pdev;
|
||||
purb->pendp = &pdev->default_endp; //pipe for current transfer
|
||||
|
||||
purb->completion = dev_mgr_get_desc_completion;
|
||||
purb->reference = 0;
|
||||
|
||||
InitializeListHead(&purb->trasac_list);
|
||||
|
||||
psetup->bmRequestType = 0x80;
|
||||
psetup->bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
psetup->wValue = (USB_DT_DEVICE << 8) | 0;
|
||||
psetup->wIndex = 0;
|
||||
psetup->wLength = 8; //sizeof( USB_DEVICE_DESC );
|
||||
unlock_dev(pdev, TRUE);
|
||||
|
||||
if (hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb) != STATUS_PENDING)
|
||||
{
|
||||
usb_free_mem(purb);
|
||||
usb_free_mem(data_buf);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
dev_mgr_get_desc_completion(PURB purb, PVOID context)
|
||||
{
|
||||
PUSB_DEV pdev;
|
||||
PUSB_CONFIGURATION_DESC pconfig_desc;
|
||||
PUSB_ENDPOINT pendp;
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
NTSTATUS status;
|
||||
PUSB_CTRL_SETUP_PACKET psetup;
|
||||
PHCD hcd;
|
||||
|
||||
USE_BASIC_NON_PENDING_IRQL;;
|
||||
|
||||
if (purb == NULL)
|
||||
return;
|
||||
|
||||
hcd_dbg_print(DBGLVL_MAXIMUM,
|
||||
("dev_mgr_get_desc_completion: purb->reference=%d\n", purb->reference));
|
||||
|
||||
pdev = purb->pdev;
|
||||
pendp = purb->pendp;
|
||||
|
||||
if (pdev == NULL || pendp == NULL)
|
||||
{
|
||||
usb_free_mem(purb);
|
||||
purb = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
lock_dev(pdev, TRUE);
|
||||
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
goto LBL_OUT;
|
||||
}
|
||||
|
||||
pendp = &pdev->default_endp;
|
||||
dev_mgr = dev_mgr_from_dev(pdev);
|
||||
hcd = pdev->hcd;
|
||||
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
|
||||
|
||||
if (usb_error(purb->status))
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
hcd_dbg_print(DBGLVL_MAXIMUM,
|
||||
("dev_mgr_get_desc_completion: can not get dev desc ref=0x%x, status=0x%x\n",
|
||||
purb->reference, purb->status));
|
||||
goto LBL_OUT;
|
||||
}
|
||||
|
||||
switch (purb->reference)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
//only partial dev_desc
|
||||
//enable the dev specific default endp maxpacketsize
|
||||
pdev->pusb_dev_desc = (PUSB_DEVICE_DESC) purb->data_buffer;
|
||||
|
||||
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
|
||||
psetup->wLength = sizeof(USB_DEVICE_DESC);
|
||||
|
||||
//get the complete dev_desc
|
||||
purb->reference = 1;
|
||||
purb->status = 0;
|
||||
purb->data_length = sizeof(USB_DEVICE_DESC);
|
||||
|
||||
unlock_dev(pdev, TRUE);
|
||||
|
||||
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
goto LBL_OUT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
//let's begin to get config descriptors.
|
||||
if (pdev->pusb_dev_desc->bNumConfigurations == 0)
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
goto LBL_OUT;
|
||||
}
|
||||
|
||||
purb->data_buffer += sizeof(USB_DEVICE_DESC);
|
||||
purb->data_length = 8;
|
||||
purb->reference++;
|
||||
purb->context = (PVOID) sizeof(USB_DEVICE_DESC);
|
||||
purb->status = 0;
|
||||
|
||||
psetup->wValue = (USB_DT_CONFIG << 8) | 0;
|
||||
psetup->wLength = 8;
|
||||
unlock_dev(pdev, TRUE);
|
||||
|
||||
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
|
||||
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
goto LBL_OUT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LONG config_idx;
|
||||
config_idx = (purb->reference >> 1) - 1;
|
||||
if ((purb->reference & 1) == 0)
|
||||
{
|
||||
//partial config desc is obtained.
|
||||
pconfig_desc = (PUSB_CONFIGURATION_DESC) purb->data_buffer;
|
||||
if (pconfig_desc->wTotalLength >= 1024)
|
||||
{
|
||||
//treat as an error
|
||||
unlock_dev(pdev, TRUE);
|
||||
goto LBL_OUT;
|
||||
|
||||
}
|
||||
|
||||
if (pconfig_desc->wTotalLength > (USHORT) (pdev->desc_buf_size - (LONG) purb->context))
|
||||
{
|
||||
//rewind the 8-byte hdr
|
||||
*((PULONG) & context) -= 8;
|
||||
realloc_buf(pdev, purb);
|
||||
}
|
||||
purb->data_length = pconfig_desc->wTotalLength;
|
||||
psetup->wLength = pconfig_desc->wTotalLength;
|
||||
purb->reference++;
|
||||
unlock_dev(pdev, TRUE);
|
||||
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
|
||||
if (status != STATUS_PENDING)
|
||||
goto LBL_OUT;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//complete desc is returned.
|
||||
if (config_idx + 1 < pdev->pusb_dev_desc->bNumConfigurations)
|
||||
{
|
||||
//still have configurations left
|
||||
*((PULONG) & context) += psetup->wLength;
|
||||
purb->data_buffer = &pdev->desc_buf[(LONG) context];
|
||||
purb->data_length = 8;
|
||||
psetup->wLength = 8;
|
||||
psetup->wValue = (((USB_DT_CONFIG) << 8) | (config_idx + 1));
|
||||
purb->reference++;
|
||||
purb->context = context;
|
||||
|
||||
if (((LONG) context) + 8 > pdev->desc_buf_size)
|
||||
realloc_buf(pdev, purb);
|
||||
|
||||
purb->status = 0;
|
||||
unlock_dev(pdev, TRUE);
|
||||
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
|
||||
if (status != STATUS_PENDING)
|
||||
goto LBL_OUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
//config descriptors have all been fetched
|
||||
unlock_dev(pdev, TRUE);
|
||||
usb_free_mem(purb);
|
||||
purb = NULL;
|
||||
|
||||
// load driver for the device
|
||||
dev_mgr_start_select_driver(pdev);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LBL_OUT:
|
||||
usb_free_mem(purb);
|
||||
purb = NULL;
|
||||
|
||||
lock_dev(pdev, TRUE);
|
||||
if (dev_state(pdev) != USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
if (pdev->desc_buf)
|
||||
{
|
||||
usb_free_mem(pdev->desc_buf);
|
||||
pdev->desc_buf_size = 0;
|
||||
pdev->desc_buf = NULL;
|
||||
pdev->pusb_dev_desc = NULL;
|
||||
pdev->usb_config = NULL;
|
||||
}
|
||||
}
|
||||
unlock_dev(pdev, TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_start_select_driver(PUSB_DEV pdev)
|
||||
{
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
PUSB_EVENT pevent;
|
||||
BOOLEAN bret;
|
||||
|
||||
USE_BASIC_NON_PENDING_IRQL;;
|
||||
|
||||
if (pdev == NULL)
|
||||
return FALSE;
|
||||
|
||||
dev_mgr = dev_mgr_from_dev(pdev);
|
||||
KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
|
||||
lock_dev(pdev, TRUE);
|
||||
|
||||
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
bret = FALSE;
|
||||
goto LBL_OUT;
|
||||
}
|
||||
|
||||
pevent = alloc_event(&dev_mgr->event_pool, 1);
|
||||
if (pevent == NULL)
|
||||
{
|
||||
bret = FALSE;
|
||||
goto LBL_OUT;
|
||||
}
|
||||
pevent->flags = USB_EVENT_FLAG_ACTIVE;
|
||||
pevent->event = USB_EVENT_DEFAULT;
|
||||
pevent->pdev = pdev;
|
||||
pevent->context = 0;
|
||||
pevent->param = 0;
|
||||
pevent->pnext = 0; //vertical queue for serialized operation
|
||||
pevent->process_event = dev_mgr_event_select_driver;
|
||||
pevent->process_queue = event_list_default_process_queue;
|
||||
|
||||
InsertTailList(&dev_mgr->event_list, &pevent->event_link);
|
||||
KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE);
|
||||
bret = TRUE;
|
||||
|
||||
LBL_OUT:
|
||||
unlock_dev(pdev, TRUE);
|
||||
KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
|
||||
return bret;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_connect_to_dev(PVOID Parameter)
|
||||
{
|
||||
PUSB_DEV pdev;
|
||||
DEV_HANDLE dev_handle;
|
||||
NTSTATUS status;
|
||||
PUSB_DRIVER pdriver;
|
||||
PCONNECT_DATA pcd = (PCONNECT_DATA) Parameter;
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
CONNECT_DATA param;
|
||||
|
||||
if (pcd == NULL)
|
||||
return FALSE;
|
||||
dev_handle = pcd->dev_handle;
|
||||
pdriver = pcd->pdriver;
|
||||
dev_mgr = pcd->dev_mgr;
|
||||
|
||||
param.dev_mgr = dev_mgr;
|
||||
param.pdriver = pdriver;
|
||||
param.dev_handle = 0; //not used
|
||||
|
||||
status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev);
|
||||
if (status != STATUS_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
usb_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_connect_to_dev(): about to call driver's dev_connect\n"));
|
||||
status = pdriver->disp_tbl.dev_connect(¶m, dev_handle);
|
||||
usb_unlock_dev(pdev);
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
dev_mgr_event_select_driver(PUSB_DEV pdev, ULONG event, ULONG context, ULONG param)
|
||||
{
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
PUSB_DRIVER pdriver, pcand;
|
||||
LONG credit, match, i;
|
||||
DEV_HANDLE handle = 0;
|
||||
CONNECT_DATA cd;
|
||||
|
||||
USE_BASIC_NON_PENDING_IRQL;
|
||||
|
||||
UNREFERENCED_PARAMETER(param);
|
||||
UNREFERENCED_PARAMETER(context);
|
||||
|
||||
usb_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_event_select_driver(): pdev=%p event=0x%x\n", pdev, event));
|
||||
|
||||
if (pdev == NULL)
|
||||
return;
|
||||
|
||||
lock_dev(pdev, FALSE);
|
||||
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
unlock_dev(pdev, FALSE);
|
||||
return;
|
||||
}
|
||||
dev_mgr = dev_mgr_from_dev(pdev);
|
||||
|
||||
pcand = NULL;
|
||||
match = 0;
|
||||
for(i = HUB_DRIVER_IDX; i < DEVMGR_MAX_DRIVERS; i++)
|
||||
{
|
||||
//bypass root-hub driver with idx zero
|
||||
pdriver = (PUSB_DRIVER) & dev_mgr->driver_list[i];
|
||||
|
||||
if (pdriver->driver_desc.flags & USB_DRIVER_FLAG_DEV_CAPABLE)
|
||||
credit = dev_mgr_score_driver_for_dev(dev_mgr, pdriver, pdev->pusb_dev_desc);
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (credit > match)
|
||||
pcand = pdriver, match = credit;
|
||||
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
// we set class driver here
|
||||
// pdev->dev_driver = pcand;
|
||||
handle = usb_make_handle(pdev->dev_id, 0, 0);
|
||||
}
|
||||
unlock_dev(pdev, FALSE);
|
||||
|
||||
if (match)
|
||||
{
|
||||
|
||||
cd.dev_handle = handle;
|
||||
cd.pdriver = pcand;
|
||||
cd.dev_mgr = dev_mgr;
|
||||
|
||||
if (dev_mgr_connect_to_dev(&cd))
|
||||
return;
|
||||
|
||||
// ExInitializeWorkItem( pwork_item, dev_mgr_connect_to_dev, ( PVOID )pcd );
|
||||
// ExQueueWorkItem( pwork_item, DelayedWorkQueue );
|
||||
}
|
||||
cd.dev_handle = handle;
|
||||
cd.pdriver = &dev_mgr->driver_list[GEN_DRIVER_IDX];
|
||||
cd.dev_mgr = dev_mgr;
|
||||
dev_mgr_connect_to_dev(&cd);
|
||||
return;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_build_usb_endp(PUSB_INTERFACE pif, PUSB_ENDPOINT pendp, PUSB_ENDPOINT_DESC pendp_desc)
|
||||
{
|
||||
if (pendp == NULL || pif == NULL || pendp_desc == NULL)
|
||||
return FALSE;
|
||||
|
||||
pendp->flags = 0;
|
||||
InitializeListHead(&pendp->urb_list); //pending urb queue
|
||||
pendp->pusb_if = pif;
|
||||
pendp->pusb_endp_desc = pendp_desc;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_build_usb_if(PUSB_CONFIGURATION pcfg, PUSB_INTERFACE pif, PUSB_INTERFACE_DESC pif_desc, BOOLEAN alt_if)
|
||||
{
|
||||
LONG i;
|
||||
PUSB_ENDPOINT_DESC pendp_desc;
|
||||
|
||||
if (pcfg == NULL || pif == NULL || pif_desc == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (alt_if == FALSE)
|
||||
{
|
||||
pif->endp_count = pif_desc->bNumEndpoints > MAX_ENDPS_PER_IF
|
||||
? MAX_ENDPS_PER_IF : pif_desc->bNumEndpoints;
|
||||
|
||||
pif->pif_drv = NULL;
|
||||
pif->pusb_config = pcfg;
|
||||
pif->pusb_if_desc = pif_desc;
|
||||
pif->if_ext_size = 0;
|
||||
pif->if_ext = NULL;
|
||||
|
||||
InitializeListHead(&pif->altif_list);
|
||||
pif->altif_count = 0;
|
||||
|
||||
pendp_desc = (PUSB_ENDPOINT_DESC) (&((PBYTE) pif_desc)[sizeof(USB_INTERFACE_DESC)]);
|
||||
|
||||
for(i = 0; i < pif->endp_count; i++, pendp_desc++)
|
||||
{
|
||||
dev_mgr_build_usb_endp(pif, &pif->endp[i], pendp_desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PUSB_INTERFACE paltif;
|
||||
PLIST_ENTRY pthis, pnext;
|
||||
|
||||
pif->altif_count++;
|
||||
paltif = usb_alloc_mem(NonPagedPool, sizeof(USB_INTERFACE));
|
||||
RtlZeroMemory(paltif, sizeof(USB_INTERFACE));
|
||||
InsertTailList(&pif->altif_list, &paltif->altif_list);
|
||||
paltif->pif_drv = NULL;
|
||||
paltif->pusb_config = pcfg;
|
||||
paltif->pusb_if_desc = pif_desc;
|
||||
paltif->if_ext_size = 0;
|
||||
paltif->if_ext = NULL;
|
||||
paltif->endp_count = pif_desc->bNumEndpoints > MAX_ENDPS_PER_IF
|
||||
? MAX_ENDPS_PER_IF : pif_desc->bNumEndpoints;
|
||||
|
||||
ListFirst(&pif->altif_list, pthis);
|
||||
|
||||
while (pthis)
|
||||
{
|
||||
//synchronize the altif_count;
|
||||
PUSB_INTERFACE pthis_if;
|
||||
pthis_if = (PUSB_INTERFACE) (((PBYTE) pthis) - offsetof(USB_INTERFACE, altif_list));
|
||||
pthis_if->altif_count = pif->altif_count;
|
||||
ListNext(&pif->altif_list, pthis, pnext);
|
||||
}
|
||||
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
dev_mgr_build_usb_config(PUSB_DEV pdev, PBYTE pbuf, ULONG config_val, LONG config_count)
|
||||
{
|
||||
PUSB_CONFIGURATION pcfg;
|
||||
PUSB_INTERFACE_DESC pif_desc;
|
||||
PUSB_INTERFACE pif;
|
||||
int i;
|
||||
LONG if_count;
|
||||
|
||||
if (pdev == NULL || pbuf == NULL)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
|
||||
pdev->usb_config = usb_alloc_mem(NonPagedPool, sizeof(USB_CONFIGURATION));
|
||||
pcfg = pdev->usb_config;
|
||||
|
||||
if (pdev->usb_config == NULL)
|
||||
return STATUS_NO_MEMORY;
|
||||
|
||||
RtlZeroMemory(pcfg, sizeof(USB_CONFIGURATION));
|
||||
pcfg->pusb_config_desc = usb_find_config_desc_by_val(pbuf, config_val, config_count);
|
||||
|
||||
if (pcfg->pusb_config_desc == NULL)
|
||||
{
|
||||
usb_free_mem(pcfg);
|
||||
pdev->usb_config = NULL;
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
pcfg->if_count = pcfg->pusb_config_desc->bNumInterfaces;
|
||||
pcfg->pusb_dev = pdev;
|
||||
pif_desc = (PUSB_INTERFACE_DESC) & ((PBYTE) pcfg->pusb_config_desc)[sizeof(USB_CONFIGURATION_DESC)];
|
||||
if_count = pcfg->if_count;
|
||||
|
||||
for(i = 0; i < if_count; i++, pif_desc++)
|
||||
{
|
||||
if (pif_desc->bAlternateSetting == 0)
|
||||
{
|
||||
dev_mgr_build_usb_if(pcfg, &pcfg->interf[i], pif_desc, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
i--;
|
||||
pif = &pcfg->interf[i];
|
||||
dev_mgr_build_usb_if(pcfg, pif, pif_desc, TRUE);
|
||||
}
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
dev_mgr_destroy_usb_config(PUSB_CONFIGURATION pcfg)
|
||||
{
|
||||
long i;
|
||||
PLIST_ENTRY pthis;
|
||||
PUSB_INTERFACE pif;
|
||||
|
||||
if (pcfg == NULL)
|
||||
return FALSE;
|
||||
|
||||
for(i = 0; i < pcfg->if_count; i++)
|
||||
{
|
||||
pif = &pcfg->interf[i];
|
||||
|
||||
if (pif->altif_count)
|
||||
{
|
||||
ListFirst(&pif->altif_list, pthis);
|
||||
while (pthis)
|
||||
{
|
||||
PUSB_INTERFACE pthis_if;
|
||||
pthis_if = (PUSB_INTERFACE) (((PBYTE) pthis) - offsetof(USB_INTERFACE, altif_list));
|
||||
RemoveEntryList(pthis);
|
||||
usb_free_mem(pthis_if);
|
||||
if (IsListEmpty(&pif->altif_list) == TRUE)
|
||||
break;
|
||||
|
||||
ListFirst(&pif->altif_list, pthis);
|
||||
}
|
||||
}
|
||||
}
|
||||
usb_free_mem(pcfg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define is_dev_product_match( pdriVER, pdev_DESC ) \
|
||||
( ( pdriVER )->driver_desc.vendor_id == ( pdev_DESC )->idVendor \
|
||||
&& ( pdriVER )->driver_desc.product_id == ( pdev_DESC )->idProduct )
|
||||
|
||||
LONG
|
||||
dev_mgr_score_driver_for_dev(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver, PUSB_DEVICE_DESC pdev_desc)
|
||||
{
|
||||
LONG credit = 0;
|
||||
|
||||
UNREFERENCED_PARAMETER(dev_mgr);
|
||||
|
||||
//assume supports all the sub_class are supported if sub_class is zero
|
||||
if (pdriver->driver_desc.dev_class == pdev_desc->bDeviceClass)
|
||||
{
|
||||
if (pdriver->driver_desc.dev_sub_class == 0 && pdriver->driver_desc.dev_protocol == 0)
|
||||
credit = 3;
|
||||
else if (pdriver->driver_desc.dev_sub_class == pdev_desc->bDeviceSubClass)
|
||||
{
|
||||
if (pdriver->driver_desc.dev_protocol == 0)
|
||||
credit = 6;
|
||||
else if (pdriver->driver_desc.dev_protocol == pdev_desc->bDeviceProtocol)
|
||||
credit = 9;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dev_product_match(pdriver, pdev_desc))
|
||||
credit += 20;
|
||||
|
||||
return credit;
|
||||
}
|
||||
|
||||
LONG
|
||||
dev_mgr_score_driver_for_if(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver, PUSB_INTERFACE_DESC pif_desc)
|
||||
{
|
||||
LONG credit;
|
||||
|
||||
if (pdriver == NULL
|
||||
|| !(pdriver->driver_desc.flags & USB_DRIVER_FLAG_IF_CAPABLE) || pif_desc == NULL || dev_mgr == NULL)
|
||||
return 0;
|
||||
|
||||
if (is_header_match((PBYTE) pif_desc, USB_DT_INTERFACE) == FALSE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
credit = 0;
|
||||
if ((pdriver->driver_desc.if_class == pif_desc->bInterfaceClass))
|
||||
{
|
||||
if (pdriver->driver_desc.if_sub_class == 0 && pdriver->driver_desc.if_protocol == 0)
|
||||
credit = 2;
|
||||
if (pdriver->driver_desc.if_sub_class == pif_desc->bInterfaceSubClass)
|
||||
{
|
||||
if (pdriver->driver_desc.if_protocol == 0)
|
||||
credit = 4;
|
||||
if (pdriver->driver_desc.if_protocol == pif_desc->bInterfaceProtocol)
|
||||
credit = 6;
|
||||
}
|
||||
}
|
||||
else
|
||||
credit = 1;
|
||||
|
||||
return credit;
|
||||
}
|
||||
|
||||
#define is_equal_driver( pd1, pd2, ret ) \
|
||||
{\
|
||||
int i;\
|
||||
ret = TRUE;\
|
||||
PUSB_DRIVER pdr1, pdr2;\
|
||||
pdr1 = ( PUSB_DRIVER )( pd1 );\
|
||||
pdr2 = ( PUSB_DRIVER ) ( pd2 );\
|
||||
for( i = 0; i < 16; i++ )\
|
||||
{\
|
||||
if( pdr1->driver_name[ i ] != pdr2->driver_name[ i ] )\
|
||||
{\
|
||||
ret = FALSE;\
|
||||
break;\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
|
||||
//return value is the hcd id
|
||||
UCHAR
|
||||
dev_mgr_register_hcd(PUSB_DEV_MANAGER dev_mgr, PHCD hcd)
|
||||
{
|
||||
if (dev_mgr == NULL || hcd == NULL)
|
||||
return 0xff;
|
||||
|
||||
if (dev_mgr->hcd_count >= MAX_HCDS)
|
||||
return 0xff;
|
||||
|
||||
dev_mgr->hcd_array[dev_mgr->hcd_count++] = hcd;
|
||||
return dev_mgr->hcd_count - 1;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_register_irp(PUSB_DEV_MANAGER dev_mgr, PIRP pirp, PURB purb)
|
||||
{
|
||||
if (dev_mgr == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (add_irp_to_list(&dev_mgr->irp_list, pirp, purb))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
TRAP();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//caller must guarantee that when this func is called,
|
||||
//the urb associated must exist.
|
||||
PURB
|
||||
dev_mgr_remove_irp(PUSB_DEV_MANAGER dev_mgr, PIRP pirp)
|
||||
{
|
||||
PURB purb;
|
||||
if (dev_mgr == NULL)
|
||||
return NULL;
|
||||
|
||||
purb = remove_irp_from_list(&dev_mgr->irp_list, pirp, NULL);
|
||||
return purb;
|
||||
}
|
||||
|
||||
VOID
|
||||
dev_mgr_cancel_irp(PDEVICE_OBJECT dev_obj, PIRP pirp)
|
||||
{
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
PDEVEXT_HEADER pdev_ext_hdr;
|
||||
|
||||
pdev_ext_hdr = (PDEVEXT_HEADER) dev_obj->DeviceExtension;
|
||||
dev_mgr = pdev_ext_hdr->dev_mgr;
|
||||
|
||||
if (dev_obj->CurrentIrp == pirp)
|
||||
{
|
||||
IoReleaseCancelSpinLock(pirp->CancelIrql);
|
||||
// we did not IoStartNextPacket, leave it for the urb completion
|
||||
}
|
||||
else
|
||||
{
|
||||
KeRemoveEntryDeviceQueue(&dev_obj->DeviceQueue, &pirp->Tail.Overlay.DeviceQueueEntry);
|
||||
IoReleaseCancelSpinLock(pirp->CancelIrql);
|
||||
|
||||
pirp->IoStatus.Information = 0;
|
||||
pirp->IoStatus.Status = STATUS_CANCELLED;
|
||||
IoCompleteRequest(pirp, IO_NO_INCREMENT);
|
||||
// the device queue is moved on, no need to call IoStartNextPacket
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// remove the irp and call the dev_mgr_cancel_irp
|
||||
// the completion will be done in urb completion
|
||||
//
|
||||
remove_irp_from_list(&dev_mgr->irp_list, pirp, dev_mgr);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// release the hcd
|
||||
VOID
|
||||
dev_mgr_release_hcd(PUSB_DEV_MANAGER dev_mgr)
|
||||
{
|
||||
LONG i;
|
||||
PHCD hcd;
|
||||
for(i = 0; i < dev_mgr->hcd_count; i++)
|
||||
{
|
||||
hcd = dev_mgr->hcd_array[i];
|
||||
hcd->hcd_release(hcd);
|
||||
dev_mgr->hcd_array[i] = 0;
|
||||
}
|
||||
dev_mgr->hcd_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
dev_mgr_start_hcd(PUSB_DEV_MANAGER dev_mgr)
|
||||
{
|
||||
LONG i;
|
||||
PHCD hcd;
|
||||
for(i = 0; i < dev_mgr->hcd_count; i++)
|
||||
{
|
||||
hcd = dev_mgr->hcd_array[i];
|
||||
hcd->hcd_start(hcd);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -45,22 +45,6 @@
|
|||
\
|
||||
}
|
||||
|
||||
#define realloc_buf( pdEV, puRB ) \
|
||||
{\
|
||||
PBYTE data_buf;\
|
||||
int i;\
|
||||
data_buf = usb_alloc_mem( NonPagedPool, ( pdEV )->desc_buf_size += 1024 );\
|
||||
RtlZeroMemory( data_buf, ( pdEV )->desc_buf_size );\
|
||||
for( i = 0; i < ( LONG )( puRB )->context; i++ )\
|
||||
{\
|
||||
data_buf[ i ] = ( pdEV )->desc_buf[ i ];\
|
||||
}\
|
||||
usb_free_mem( ( pdEV )->desc_buf );\
|
||||
( pdEV )->desc_buf = data_buf;\
|
||||
( pdEV )->pusb_dev_desc = ( PUSB_DEVICE_DESC )( pdEV )->desc_buf;\
|
||||
( puRB )->data_buffer = &data_buf[ ( LONG ) ( puRB )->context ];\
|
||||
}
|
||||
|
||||
extern ULONG cpu_clock_freq;
|
||||
|
||||
BOOLEAN hub_check_reset_port_status(PUSB_DEV pdev, LONG port_idx);
|
||||
|
@ -1923,761 +1907,6 @@ hub_reexamine_port_status_queue(PUSB_DEV hub_dev, ULONG port_idx, BOOLEAN from_d
|
|||
return;
|
||||
}
|
||||
|
||||
//called in hub_set_address_completion
|
||||
BOOLEAN
|
||||
dev_mgr_start_config_dev(PUSB_DEV pdev)
|
||||
{
|
||||
PBYTE data_buf;
|
||||
PUSB_CTRL_SETUP_PACKET psetup;
|
||||
PURB purb;
|
||||
PHCD hcd;
|
||||
USE_BASIC_NON_PENDING_IRQL;
|
||||
|
||||
hcd_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_start_config_dev: pdev=%p\n", pdev));
|
||||
|
||||
if (pdev == NULL)
|
||||
return FALSE;
|
||||
|
||||
lock_dev(pdev, TRUE);
|
||||
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hcd = pdev->hcd;
|
||||
|
||||
//first, get device descriptor
|
||||
purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
|
||||
data_buf = usb_alloc_mem(NonPagedPool, 512);
|
||||
if (purb == NULL)
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RtlZeroMemory(purb, sizeof(URB));
|
||||
RtlZeroMemory(data_buf, 512);
|
||||
|
||||
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
|
||||
|
||||
purb->data_buffer = data_buf; // user data
|
||||
purb->data_length = 8; // get partial desc
|
||||
|
||||
pdev->desc_buf = data_buf;
|
||||
pdev->desc_buf_size = 512;
|
||||
|
||||
purb->pdev = pdev;
|
||||
purb->pendp = &pdev->default_endp; //pipe for current transfer
|
||||
|
||||
purb->completion = dev_mgr_get_desc_completion;
|
||||
purb->reference = 0;
|
||||
|
||||
InitializeListHead(&purb->trasac_list);
|
||||
|
||||
psetup->bmRequestType = 0x80;
|
||||
psetup->bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
psetup->wValue = (USB_DT_DEVICE << 8) | 0;
|
||||
psetup->wIndex = 0;
|
||||
psetup->wLength = 8; //sizeof( USB_DEVICE_DESC );
|
||||
unlock_dev(pdev, TRUE);
|
||||
|
||||
if (hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb) != STATUS_PENDING)
|
||||
{
|
||||
usb_free_mem(purb);
|
||||
usb_free_mem(data_buf);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
dev_mgr_get_desc_completion(PURB purb, PVOID context)
|
||||
{
|
||||
PUSB_DEV pdev;
|
||||
PUSB_CONFIGURATION_DESC pconfig_desc;
|
||||
PUSB_ENDPOINT pendp;
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
NTSTATUS status;
|
||||
PUSB_CTRL_SETUP_PACKET psetup;
|
||||
PHCD hcd;
|
||||
|
||||
USE_BASIC_NON_PENDING_IRQL;;
|
||||
|
||||
if (purb == NULL)
|
||||
return;
|
||||
|
||||
hcd_dbg_print(DBGLVL_MAXIMUM,
|
||||
("dev_mgr_get_desc_completion: purb->reference=%d\n", purb->reference));
|
||||
|
||||
pdev = purb->pdev;
|
||||
pendp = purb->pendp;
|
||||
|
||||
if (pdev == NULL || pendp == NULL)
|
||||
{
|
||||
usb_free_mem(purb);
|
||||
purb = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
lock_dev(pdev, TRUE);
|
||||
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
goto LBL_OUT;
|
||||
}
|
||||
|
||||
pendp = &pdev->default_endp;
|
||||
dev_mgr = dev_mgr_from_dev(pdev);
|
||||
hcd = pdev->hcd;
|
||||
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
|
||||
|
||||
if (usb_error(purb->status))
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
hcd_dbg_print(DBGLVL_MAXIMUM,
|
||||
("dev_mgr_get_desc_completion: can not get dev desc ref=0x%x, status=0x%x\n",
|
||||
purb->reference, purb->status));
|
||||
goto LBL_OUT;
|
||||
}
|
||||
|
||||
switch (purb->reference)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
//only partial dev_desc
|
||||
//enable the dev specific default endp maxpacketsize
|
||||
pdev->pusb_dev_desc = (PUSB_DEVICE_DESC) purb->data_buffer;
|
||||
|
||||
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
|
||||
psetup->wLength = sizeof(USB_DEVICE_DESC);
|
||||
|
||||
//get the complete dev_desc
|
||||
purb->reference = 1;
|
||||
purb->status = 0;
|
||||
purb->data_length = sizeof(USB_DEVICE_DESC);
|
||||
|
||||
unlock_dev(pdev, TRUE);
|
||||
|
||||
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
goto LBL_OUT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
//let's begin to get config descriptors.
|
||||
if (pdev->pusb_dev_desc->bNumConfigurations == 0)
|
||||
{
|
||||
unlock_dev(pdev, TRUE);
|
||||
goto LBL_OUT;
|
||||
}
|
||||
|
||||
purb->data_buffer += sizeof(USB_DEVICE_DESC);
|
||||
purb->data_length = 8;
|
||||
purb->reference++;
|
||||
purb->context = (PVOID) sizeof(USB_DEVICE_DESC);
|
||||
purb->status = 0;
|
||||
|
||||
psetup->wValue = (USB_DT_CONFIG << 8) | 0;
|
||||
psetup->wLength = 8;
|
||||
unlock_dev(pdev, TRUE);
|
||||
|
||||
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
|
||||
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
goto LBL_OUT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LONG config_idx;
|
||||
config_idx = (purb->reference >> 1) - 1;
|
||||
if ((purb->reference & 1) == 0)
|
||||
{
|
||||
//partial config desc is obtained.
|
||||
pconfig_desc = (PUSB_CONFIGURATION_DESC) purb->data_buffer;
|
||||
if (pconfig_desc->wTotalLength >= 1024)
|
||||
{
|
||||
//treat as an error
|
||||
unlock_dev(pdev, TRUE);
|
||||
goto LBL_OUT;
|
||||
|
||||
}
|
||||
|
||||
if (pconfig_desc->wTotalLength > (USHORT) (pdev->desc_buf_size - (LONG) purb->context))
|
||||
{
|
||||
//rewind the 8-byte hdr
|
||||
*((PULONG) & context) -= 8;
|
||||
realloc_buf(pdev, purb);
|
||||
}
|
||||
purb->data_length = pconfig_desc->wTotalLength;
|
||||
psetup->wLength = pconfig_desc->wTotalLength;
|
||||
purb->reference++;
|
||||
unlock_dev(pdev, TRUE);
|
||||
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
|
||||
if (status != STATUS_PENDING)
|
||||
goto LBL_OUT;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//complete desc is returned.
|
||||
if (config_idx + 1 < pdev->pusb_dev_desc->bNumConfigurations)
|
||||
{
|
||||
//still have configurations left
|
||||
*((PULONG) & context) += psetup->wLength;
|
||||
purb->data_buffer = &pdev->desc_buf[(LONG) context];
|
||||
purb->data_length = 8;
|
||||
psetup->wLength = 8;
|
||||
psetup->wValue = (((USB_DT_CONFIG) << 8) | (config_idx + 1));
|
||||
purb->reference++;
|
||||
purb->context = context;
|
||||
|
||||
if (((LONG) context) + 8 > pdev->desc_buf_size)
|
||||
realloc_buf(pdev, purb);
|
||||
|
||||
purb->status = 0;
|
||||
unlock_dev(pdev, TRUE);
|
||||
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
|
||||
if (status != STATUS_PENDING)
|
||||
goto LBL_OUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
//config descriptors have all been fetched
|
||||
unlock_dev(pdev, TRUE);
|
||||
usb_free_mem(purb);
|
||||
purb = NULL;
|
||||
|
||||
// load driver for the device
|
||||
dev_mgr_start_select_driver(pdev);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LBL_OUT:
|
||||
usb_free_mem(purb);
|
||||
purb = NULL;
|
||||
|
||||
lock_dev(pdev, TRUE);
|
||||
if (dev_state(pdev) != USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
if (pdev->desc_buf)
|
||||
{
|
||||
usb_free_mem(pdev->desc_buf);
|
||||
pdev->desc_buf_size = 0;
|
||||
pdev->desc_buf = NULL;
|
||||
pdev->pusb_dev_desc = NULL;
|
||||
pdev->usb_config = NULL;
|
||||
}
|
||||
}
|
||||
unlock_dev(pdev, TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_start_select_driver(PUSB_DEV pdev)
|
||||
{
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
PUSB_EVENT pevent;
|
||||
BOOLEAN bret;
|
||||
|
||||
USE_BASIC_NON_PENDING_IRQL;;
|
||||
|
||||
if (pdev == NULL)
|
||||
return FALSE;
|
||||
|
||||
dev_mgr = dev_mgr_from_dev(pdev);
|
||||
KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
|
||||
lock_dev(pdev, TRUE);
|
||||
|
||||
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
bret = FALSE;
|
||||
goto LBL_OUT;
|
||||
}
|
||||
|
||||
pevent = alloc_event(&dev_mgr->event_pool, 1);
|
||||
if (pevent == NULL)
|
||||
{
|
||||
bret = FALSE;
|
||||
goto LBL_OUT;
|
||||
}
|
||||
pevent->flags = USB_EVENT_FLAG_ACTIVE;
|
||||
pevent->event = USB_EVENT_DEFAULT;
|
||||
pevent->pdev = pdev;
|
||||
pevent->context = 0;
|
||||
pevent->param = 0;
|
||||
pevent->pnext = 0; //vertical queue for serialized operation
|
||||
pevent->process_event = dev_mgr_event_select_driver;
|
||||
pevent->process_queue = event_list_default_process_queue;
|
||||
|
||||
InsertTailList(&dev_mgr->event_list, &pevent->event_link);
|
||||
KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE);
|
||||
bret = TRUE;
|
||||
|
||||
LBL_OUT:
|
||||
unlock_dev(pdev, TRUE);
|
||||
KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
|
||||
return bret;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_connect_to_dev(PVOID Parameter)
|
||||
{
|
||||
PUSB_DEV pdev;
|
||||
DEV_HANDLE dev_handle;
|
||||
NTSTATUS status;
|
||||
PUSB_DRIVER pdriver;
|
||||
PCONNECT_DATA pcd = (PCONNECT_DATA) Parameter;
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
CONNECT_DATA param;
|
||||
|
||||
if (pcd == NULL)
|
||||
return FALSE;
|
||||
dev_handle = pcd->dev_handle;
|
||||
pdriver = pcd->pdriver;
|
||||
dev_mgr = pcd->dev_mgr;
|
||||
|
||||
param.dev_mgr = dev_mgr;
|
||||
param.pdriver = pdriver;
|
||||
param.dev_handle = 0; //not used
|
||||
|
||||
status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev);
|
||||
if (status != STATUS_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
usb_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_connect_to_dev(): about to call driver's dev_connect\n"));
|
||||
status = pdriver->disp_tbl.dev_connect(¶m, dev_handle);
|
||||
usb_unlock_dev(pdev);
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
dev_mgr_event_select_driver(PUSB_DEV pdev, ULONG event, ULONG context, ULONG param)
|
||||
{
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
PUSB_DRIVER pdriver, pcand;
|
||||
LONG credit, match, i;
|
||||
DEV_HANDLE handle = 0;
|
||||
CONNECT_DATA cd;
|
||||
|
||||
USE_BASIC_NON_PENDING_IRQL;
|
||||
|
||||
UNREFERENCED_PARAMETER(param);
|
||||
UNREFERENCED_PARAMETER(context);
|
||||
|
||||
usb_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_event_select_driver(): pdev=%p event=0x%x\n", pdev, event));
|
||||
|
||||
if (pdev == NULL)
|
||||
return;
|
||||
|
||||
lock_dev(pdev, FALSE);
|
||||
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
||||
{
|
||||
unlock_dev(pdev, FALSE);
|
||||
return;
|
||||
}
|
||||
dev_mgr = dev_mgr_from_dev(pdev);
|
||||
|
||||
pcand = NULL;
|
||||
match = 0;
|
||||
for(i = HUB_DRIVER_IDX; i < DEVMGR_MAX_DRIVERS; i++)
|
||||
{
|
||||
//bypass root-hub driver with idx zero
|
||||
pdriver = (PUSB_DRIVER) & dev_mgr->driver_list[i];
|
||||
|
||||
if (pdriver->driver_desc.flags & USB_DRIVER_FLAG_DEV_CAPABLE)
|
||||
credit = dev_mgr_score_driver_for_dev(dev_mgr, pdriver, pdev->pusb_dev_desc);
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (credit > match)
|
||||
pcand = pdriver, match = credit;
|
||||
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
// we set class driver here
|
||||
// pdev->dev_driver = pcand;
|
||||
handle = usb_make_handle(pdev->dev_id, 0, 0);
|
||||
}
|
||||
unlock_dev(pdev, FALSE);
|
||||
|
||||
if (match)
|
||||
{
|
||||
|
||||
cd.dev_handle = handle;
|
||||
cd.pdriver = pcand;
|
||||
cd.dev_mgr = dev_mgr;
|
||||
|
||||
if (dev_mgr_connect_to_dev(&cd))
|
||||
return;
|
||||
|
||||
// ExInitializeWorkItem( pwork_item, dev_mgr_connect_to_dev, ( PVOID )pcd );
|
||||
// ExQueueWorkItem( pwork_item, DelayedWorkQueue );
|
||||
}
|
||||
cd.dev_handle = handle;
|
||||
cd.pdriver = &dev_mgr->driver_list[GEN_DRIVER_IDX];
|
||||
cd.dev_mgr = dev_mgr;
|
||||
dev_mgr_connect_to_dev(&cd);
|
||||
return;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_build_usb_endp(PUSB_INTERFACE pif, PUSB_ENDPOINT pendp, PUSB_ENDPOINT_DESC pendp_desc)
|
||||
{
|
||||
if (pendp == NULL || pif == NULL || pendp_desc == NULL)
|
||||
return FALSE;
|
||||
|
||||
pendp->flags = 0;
|
||||
InitializeListHead(&pendp->urb_list); //pending urb queue
|
||||
pendp->pusb_if = pif;
|
||||
pendp->pusb_endp_desc = pendp_desc;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_build_usb_if(PUSB_CONFIGURATION pcfg, PUSB_INTERFACE pif, PUSB_INTERFACE_DESC pif_desc, BOOLEAN alt_if)
|
||||
{
|
||||
LONG i;
|
||||
PUSB_ENDPOINT_DESC pendp_desc;
|
||||
|
||||
if (pcfg == NULL || pif == NULL || pif_desc == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (alt_if == FALSE)
|
||||
{
|
||||
pif->endp_count = pif_desc->bNumEndpoints > MAX_ENDPS_PER_IF
|
||||
? MAX_ENDPS_PER_IF : pif_desc->bNumEndpoints;
|
||||
|
||||
pif->pif_drv = NULL;
|
||||
pif->pusb_config = pcfg;
|
||||
pif->pusb_if_desc = pif_desc;
|
||||
pif->if_ext_size = 0;
|
||||
pif->if_ext = NULL;
|
||||
|
||||
InitializeListHead(&pif->altif_list);
|
||||
pif->altif_count = 0;
|
||||
|
||||
pendp_desc = (PUSB_ENDPOINT_DESC) (&((PBYTE) pif_desc)[sizeof(USB_INTERFACE_DESC)]);
|
||||
|
||||
for(i = 0; i < pif->endp_count; i++, pendp_desc++)
|
||||
{
|
||||
dev_mgr_build_usb_endp(pif, &pif->endp[i], pendp_desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PUSB_INTERFACE paltif;
|
||||
PLIST_ENTRY pthis, pnext;
|
||||
|
||||
pif->altif_count++;
|
||||
paltif = usb_alloc_mem(NonPagedPool, sizeof(USB_INTERFACE));
|
||||
RtlZeroMemory(paltif, sizeof(USB_INTERFACE));
|
||||
InsertTailList(&pif->altif_list, &paltif->altif_list);
|
||||
paltif->pif_drv = NULL;
|
||||
paltif->pusb_config = pcfg;
|
||||
paltif->pusb_if_desc = pif_desc;
|
||||
paltif->if_ext_size = 0;
|
||||
paltif->if_ext = NULL;
|
||||
paltif->endp_count = pif_desc->bNumEndpoints > MAX_ENDPS_PER_IF
|
||||
? MAX_ENDPS_PER_IF : pif_desc->bNumEndpoints;
|
||||
|
||||
ListFirst(&pif->altif_list, pthis);
|
||||
|
||||
while (pthis)
|
||||
{
|
||||
//synchronize the altif_count;
|
||||
PUSB_INTERFACE pthis_if;
|
||||
pthis_if = (PUSB_INTERFACE) (((PBYTE) pthis) - offsetof(USB_INTERFACE, altif_list));
|
||||
pthis_if->altif_count = pif->altif_count;
|
||||
ListNext(&pif->altif_list, pthis, pnext);
|
||||
}
|
||||
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
dev_mgr_build_usb_config(PUSB_DEV pdev, PBYTE pbuf, ULONG config_val, LONG config_count)
|
||||
{
|
||||
PUSB_CONFIGURATION pcfg;
|
||||
PUSB_INTERFACE_DESC pif_desc;
|
||||
PUSB_INTERFACE pif;
|
||||
int i;
|
||||
LONG if_count;
|
||||
|
||||
if (pdev == NULL || pbuf == NULL)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
|
||||
pdev->usb_config = usb_alloc_mem(NonPagedPool, sizeof(USB_CONFIGURATION));
|
||||
pcfg = pdev->usb_config;
|
||||
|
||||
if (pdev->usb_config == NULL)
|
||||
return STATUS_NO_MEMORY;
|
||||
|
||||
RtlZeroMemory(pcfg, sizeof(USB_CONFIGURATION));
|
||||
pcfg->pusb_config_desc = usb_find_config_desc_by_val(pbuf, config_val, config_count);
|
||||
|
||||
if (pcfg->pusb_config_desc == NULL)
|
||||
{
|
||||
usb_free_mem(pcfg);
|
||||
pdev->usb_config = NULL;
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
pcfg->if_count = pcfg->pusb_config_desc->bNumInterfaces;
|
||||
pcfg->pusb_dev = pdev;
|
||||
pif_desc = (PUSB_INTERFACE_DESC) & ((PBYTE) pcfg->pusb_config_desc)[sizeof(USB_CONFIGURATION_DESC)];
|
||||
if_count = pcfg->if_count;
|
||||
|
||||
for(i = 0; i < if_count; i++, pif_desc++)
|
||||
{
|
||||
if (pif_desc->bAlternateSetting == 0)
|
||||
{
|
||||
dev_mgr_build_usb_if(pcfg, &pcfg->interf[i], pif_desc, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
i--;
|
||||
pif = &pcfg->interf[i];
|
||||
dev_mgr_build_usb_if(pcfg, pif, pif_desc, TRUE);
|
||||
}
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
dev_mgr_destroy_usb_config(PUSB_CONFIGURATION pcfg)
|
||||
{
|
||||
long i;
|
||||
PLIST_ENTRY pthis;
|
||||
PUSB_INTERFACE pif;
|
||||
|
||||
if (pcfg == NULL)
|
||||
return FALSE;
|
||||
|
||||
for(i = 0; i < pcfg->if_count; i++)
|
||||
{
|
||||
pif = &pcfg->interf[i];
|
||||
|
||||
if (pif->altif_count)
|
||||
{
|
||||
ListFirst(&pif->altif_list, pthis);
|
||||
while (pthis)
|
||||
{
|
||||
PUSB_INTERFACE pthis_if;
|
||||
pthis_if = (PUSB_INTERFACE) (((PBYTE) pthis) - offsetof(USB_INTERFACE, altif_list));
|
||||
RemoveEntryList(pthis);
|
||||
usb_free_mem(pthis_if);
|
||||
if (IsListEmpty(&pif->altif_list) == TRUE)
|
||||
break;
|
||||
|
||||
ListFirst(&pif->altif_list, pthis);
|
||||
}
|
||||
}
|
||||
}
|
||||
usb_free_mem(pcfg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define is_dev_product_match( pdriVER, pdev_DESC ) \
|
||||
( ( pdriVER )->driver_desc.vendor_id == ( pdev_DESC )->idVendor \
|
||||
&& ( pdriVER )->driver_desc.product_id == ( pdev_DESC )->idProduct )
|
||||
|
||||
LONG
|
||||
dev_mgr_score_driver_for_dev(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver, PUSB_DEVICE_DESC pdev_desc)
|
||||
{
|
||||
LONG credit = 0;
|
||||
|
||||
UNREFERENCED_PARAMETER(dev_mgr);
|
||||
|
||||
//assume supports all the sub_class are supported if sub_class is zero
|
||||
if (pdriver->driver_desc.dev_class == pdev_desc->bDeviceClass)
|
||||
{
|
||||
if (pdriver->driver_desc.dev_sub_class == 0 && pdriver->driver_desc.dev_protocol == 0)
|
||||
credit = 3;
|
||||
else if (pdriver->driver_desc.dev_sub_class == pdev_desc->bDeviceSubClass)
|
||||
{
|
||||
if (pdriver->driver_desc.dev_protocol == 0)
|
||||
credit = 6;
|
||||
else if (pdriver->driver_desc.dev_protocol == pdev_desc->bDeviceProtocol)
|
||||
credit = 9;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dev_product_match(pdriver, pdev_desc))
|
||||
credit += 20;
|
||||
|
||||
return credit;
|
||||
}
|
||||
|
||||
LONG
|
||||
dev_mgr_score_driver_for_if(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver, PUSB_INTERFACE_DESC pif_desc)
|
||||
{
|
||||
LONG credit;
|
||||
|
||||
if (pdriver == NULL
|
||||
|| !(pdriver->driver_desc.flags & USB_DRIVER_FLAG_IF_CAPABLE) || pif_desc == NULL || dev_mgr == NULL)
|
||||
return 0;
|
||||
|
||||
if (is_header_match((PBYTE) pif_desc, USB_DT_INTERFACE) == FALSE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
credit = 0;
|
||||
if ((pdriver->driver_desc.if_class == pif_desc->bInterfaceClass))
|
||||
{
|
||||
if (pdriver->driver_desc.if_sub_class == 0 && pdriver->driver_desc.if_protocol == 0)
|
||||
credit = 2;
|
||||
if (pdriver->driver_desc.if_sub_class == pif_desc->bInterfaceSubClass)
|
||||
{
|
||||
if (pdriver->driver_desc.if_protocol == 0)
|
||||
credit = 4;
|
||||
if (pdriver->driver_desc.if_protocol == pif_desc->bInterfaceProtocol)
|
||||
credit = 6;
|
||||
}
|
||||
}
|
||||
else
|
||||
credit = 1;
|
||||
|
||||
return credit;
|
||||
}
|
||||
|
||||
#define is_equal_driver( pd1, pd2, ret ) \
|
||||
{\
|
||||
int i;\
|
||||
ret = TRUE;\
|
||||
PUSB_DRIVER pdr1, pdr2;\
|
||||
pdr1 = ( PUSB_DRIVER )( pd1 );\
|
||||
pdr2 = ( PUSB_DRIVER ) ( pd2 );\
|
||||
for( i = 0; i < 16; i++ )\
|
||||
{\
|
||||
if( pdr1->driver_name[ i ] != pdr2->driver_name[ i ] )\
|
||||
{\
|
||||
ret = FALSE;\
|
||||
break;\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
|
||||
//return value is the hcd id
|
||||
UCHAR
|
||||
dev_mgr_register_hcd(PUSB_DEV_MANAGER dev_mgr, PHCD hcd)
|
||||
{
|
||||
if (dev_mgr == NULL || hcd == NULL)
|
||||
return 0xff;
|
||||
|
||||
if (dev_mgr->hcd_count >= MAX_HCDS)
|
||||
return 0xff;
|
||||
|
||||
dev_mgr->hcd_array[dev_mgr->hcd_count++] = hcd;
|
||||
return dev_mgr->hcd_count - 1;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
dev_mgr_register_irp(PUSB_DEV_MANAGER dev_mgr, PIRP pirp, PURB purb)
|
||||
{
|
||||
if (dev_mgr == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (add_irp_to_list(&dev_mgr->irp_list, pirp, purb))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
TRAP();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//caller must guarantee that when this func is called,
|
||||
//the urb associated must exist.
|
||||
PURB
|
||||
dev_mgr_remove_irp(PUSB_DEV_MANAGER dev_mgr, PIRP pirp)
|
||||
{
|
||||
PURB purb;
|
||||
if (dev_mgr == NULL)
|
||||
return NULL;
|
||||
|
||||
purb = remove_irp_from_list(&dev_mgr->irp_list, pirp, NULL);
|
||||
return purb;
|
||||
}
|
||||
|
||||
VOID
|
||||
dev_mgr_cancel_irp(PDEVICE_OBJECT dev_obj, PIRP pirp)
|
||||
{
|
||||
PUSB_DEV_MANAGER dev_mgr;
|
||||
PDEVEXT_HEADER pdev_ext_hdr;
|
||||
|
||||
pdev_ext_hdr = (PDEVEXT_HEADER) dev_obj->DeviceExtension;
|
||||
dev_mgr = pdev_ext_hdr->dev_mgr;
|
||||
|
||||
if (dev_obj->CurrentIrp == pirp)
|
||||
{
|
||||
IoReleaseCancelSpinLock(pirp->CancelIrql);
|
||||
// we did not IoStartNextPacket, leave it for the urb completion
|
||||
}
|
||||
else
|
||||
{
|
||||
KeRemoveEntryDeviceQueue(&dev_obj->DeviceQueue, &pirp->Tail.Overlay.DeviceQueueEntry);
|
||||
IoReleaseCancelSpinLock(pirp->CancelIrql);
|
||||
|
||||
pirp->IoStatus.Information = 0;
|
||||
pirp->IoStatus.Status = STATUS_CANCELLED;
|
||||
IoCompleteRequest(pirp, IO_NO_INCREMENT);
|
||||
// the device queue is moved on, no need to call IoStartNextPacket
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// remove the irp and call the dev_mgr_cancel_irp
|
||||
// the completion will be done in urb completion
|
||||
//
|
||||
remove_irp_from_list(&dev_mgr->irp_list, pirp, dev_mgr);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// release the hcd
|
||||
VOID
|
||||
dev_mgr_release_hcd(PUSB_DEV_MANAGER dev_mgr)
|
||||
{
|
||||
LONG i;
|
||||
PHCD hcd;
|
||||
for(i = 0; i < dev_mgr->hcd_count; i++)
|
||||
{
|
||||
hcd = dev_mgr->hcd_array[i];
|
||||
hcd->hcd_release(hcd);
|
||||
dev_mgr->hcd_array[i] = 0;
|
||||
}
|
||||
dev_mgr->hcd_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
dev_mgr_start_hcd(PUSB_DEV_MANAGER dev_mgr)
|
||||
{
|
||||
LONG i;
|
||||
PHCD hcd;
|
||||
for(i = 0; i < dev_mgr->hcd_count; i++)
|
||||
{
|
||||
hcd = dev_mgr->hcd_array[i];
|
||||
hcd->hcd_start(hcd);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
hub_connect(PCONNECT_DATA param, DEV_HANDLE dev_handle)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue