📄 devmgr.c
字号:
if ((addr = dev_mgr_alloc_addr(dev_mgr, hcd)) == 0xff)
return NULL;
pdev = usb_alloc_mem(NonPagedPool, sizeof(USB_DEV));
if (pdev == NULL)
return NULL;
RtlZeroMemory(pdev, sizeof(USB_DEV));
KeInitializeSpinLock(&pdev->dev_lock);
dev_mgr->conn_count++;
pdev->flags = USB_DEV_STATE_RESET; //class | cur_state | low speed
pdev->ref_count = 0;
pdev->dev_addr = addr;
pdev->hcd = hcd;
pdev->dev_id = dev_mgr->conn_count; //will be used to compose dev_handle
InitializeListHead(&pdev->default_endp.urb_list);
pdev->default_endp.pusb_if = (PUSB_INTERFACE) pdev;
pdev->default_endp.flags = USB_ENDP_FLAG_DEFAULT_ENDP; //toggle | busy-count | stall | default-endp
return pdev;
}
VOID
dev_mgr_free_device(PUSB_DEV_MANAGER dev_mgr, PUSB_DEV pdev)
{
if (pdev == NULL || dev_mgr == NULL)
return;
dev_mgr_free_addr(dev_mgr, pdev, pdev->dev_addr);
if (pdev->usb_config && pdev != pdev->hcd->hcd_get_root_hub(pdev->hcd))
{
//root hub has its config and desc buf allocated together,
//so no usb_config allocated seperately
dev_mgr_destroy_usb_config(pdev->usb_config);
pdev->usb_config = NULL;
}
if (pdev->desc_buf)
{
usb_free_mem(pdev->desc_buf);
pdev->desc_buf = NULL;
}
usb_free_mem(pdev);
pdev = NULL;
return;
}
//called when a disconnect is detected on the port
VOID
dev_mgr_disconnect_dev(PUSB_DEV pdev)
{
PLIST_ENTRY pthis, pnext;
PHUB2_EXTENSION phub_ext = NULL;
PUSB_CONFIGURATION pconfig;
PUSB_DEV_MANAGER dev_mgr;
PHCD hcd;
BOOLEAN is_hub, found;
ULONG dev_id;
int i;
USE_NON_PENDING_IRQL;
if (pdev == NULL)
return;
found = FALSE;
usb_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_disconnect_dev(): entering, pdev=0x%x\n", pdev));
lock_dev(pdev, FALSE);
pdev->flags &= ~USB_DEV_STATE_MASK;
pdev->flags |= USB_DEV_STATE_BEFORE_ZOMB;
dev_mgr = dev_mgr_from_dev(pdev);
unlock_dev(pdev, FALSE);
// notify dev_driver that the dev stops function before any operations
if (pdev->dev_driver && pdev->dev_driver->disp_tbl.dev_stop)
pdev->dev_driver->disp_tbl.dev_stop(dev_mgr, dev_handle_from_dev(pdev));
//safe to use the dev pointer in this function.
lock_dev(pdev, FALSE);
pdev->flags &= ~USB_DEV_STATE_MASK;
pdev->flags |= USB_DEV_STATE_ZOMB;
hcd = pdev->hcd;
dev_id = pdev->dev_id;
unlock_dev(pdev, FALSE);
if (dev_mgr == NULL)
return;
hcd->hcd_remove_device(hcd, pdev);
//disconnect its children
if ((pdev->flags & USB_DEV_CLASS_MASK) == USB_DEV_CLASS_HUB ||
(pdev->flags & USB_DEV_CLASS_MASK) == USB_DEV_CLASS_ROOT_HUB)
{
phub_ext = hub_ext_from_dev(pdev);
if (phub_ext)
{
for(i = 1; i <= phub_ext->port_count; i++)
{
if (phub_ext->child_dev[i])
{
dev_mgr_disconnect_dev(phub_ext->child_dev[i]);
phub_ext->child_dev[i] = NULL;
}
}
}
}
pconfig = pdev->usb_config;
//remove event belong to the dev
is_hub = ((pdev->flags & USB_DEV_CLASS_MASK) == USB_DEV_CLASS_HUB);
if (phub_ext && is_hub)
{
for(i = 1; i <= phub_ext->port_count; i++)
{
found = hub_remove_reset_event(pdev, i, FALSE);
if (found)
break;
}
}
//free event of the dev from the event list
KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);
ListFirst(&dev_mgr->event_list, pthis);
while (pthis)
{
ListNext(&dev_mgr->event_list, pthis, pnext);
if (((PUSB_EVENT) pthis)->pdev == pdev)
{
PLIST_ENTRY p1;
RemoveEntryList(pthis);
if ((((PUSB_EVENT) pthis)->flags & USB_EVENT_FLAG_QUE_TYPE) != USB_EVENT_FLAG_NOQUE)
{
//has a queue, re-insert the queue
if ((p1 = (PLIST_ENTRY) ((PUSB_EVENT) pthis)->pnext))
{
InsertHeadList(&dev_mgr->event_list, p1);
free_event(&dev_mgr->event_pool, struct_ptr(pthis, USB_EVENT, event_link));
pthis = p1;
//note: this queue will be examined again in the next loop
//to find the matched dev in the queue
continue;
}
}
free_event(&dev_mgr->event_pool, struct_ptr(pthis, USB_EVENT, event_link));
}
else if (((((PUSB_EVENT) pthis)->flags & USB_EVENT_FLAG_QUE_TYPE)
!= USB_EVENT_FLAG_NOQUE) && ((PUSB_EVENT) pthis)->pnext)
{
//has a queue, examine the queue
PUSB_EVENT p1, p2;
p1 = (PUSB_EVENT) pthis;
p2 = p1->pnext;
while (p2)
{
if (p2->pdev == pdev)
{
p1->pnext = p2->pnext;
p2->pnext = NULL;
free_event(&dev_mgr->event_pool, p2);
p2 = p1->pnext;
}
else
{
p1 = p2;
p2 = p2->pnext;
}
}
}
pthis = pnext;
}
KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
// found indicates the reset event on one of the dev's port in process
if (found)
hub_start_next_reset_port(dev_mgr_from_dev(pdev), FALSE);
// remove timer-svc belonging to the dev
KeAcquireSpinLock(&dev_mgr->timer_svc_list_lock, &old_irql);
ListFirst(&dev_mgr->timer_svc_list, pthis);
i = 0;
while (pthis)
{
ListNext(&dev_mgr->timer_svc_list, pthis, pnext);
if (((PUSB_EVENT) pthis)->pdev == pdev)
{
RemoveEntryList(pthis);
free_timer_svc(&dev_mgr->timer_svc_pool, struct_ptr(pthis, TIMER_SVC, timer_svc_link));
i++;
}
pthis = pnext;
}
KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
// release the refcount
if (i)
{
lock_dev(pdev, FALSE);
pdev->ref_count -= i;
unlock_dev(pdev, FALSE);
}
// wait for all the reference count be released
for(;;)
{
LARGE_INTEGER interval;
lock_dev(pdev, FALSE);
if (pdev->ref_count == 0)
{
unlock_dev(pdev, FALSE);
break;
}
unlock_dev(pdev, FALSE);
// Wait two ms.
interval.QuadPart = -20000;
KeDelayExecutionThread(KernelMode, FALSE, &interval);
}
if (pdev->dev_driver && pdev->dev_driver->disp_tbl.dev_disconnect)
pdev->dev_driver->disp_tbl.dev_disconnect(dev_mgr, dev_handle_from_dev(pdev));
// we put it here to let handle valid before disconnect
KeAcquireSpinLock(&dev_mgr->dev_list_lock, &old_irql);
ListFirst(&dev_mgr->dev_list, pthis);
while (pthis)
{
if (((PUSB_DEV) pthis) == pdev)
{
RemoveEntryList(pthis);
break;
}
ListNext(&dev_mgr->dev_list, pthis, pnext);
pthis = pnext;
}
KeReleaseSpinLock(&dev_mgr->dev_list_lock, old_irql);
if (pdev != pdev->hcd->hcd_get_root_hub(pdev->hcd))
{
dev_mgr_free_device(dev_mgr, pdev);
}
else
{
//rh_destroy( pdev );
//TRAP();
//destroy it in dev_mgr_destroy
}
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)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -