?? hub.c
字號(hào):
purb = NULL;
}
return status;
}
void
hub_int_completion(PURB purb, PVOID pcontext)
{
PUSB_DEV pdev;
PHUB2_EXTENSION hub_ext;
ULONG port_idx;
PUSB_CTRL_SETUP_PACKET psetup;
NTSTATUS status;
LONG i;
PHCD hcd;
USE_BASIC_NON_PENDING_IRQL;
if (purb == NULL)
return;
if (pcontext == NULL)
{
usb_free_mem(purb);
return;
}
usb_dbg_print(DBGLVL_ULTRA, ("hub_int_completion(): entering...\n"));
pdev = purb->pdev;
hub_ext = pcontext;
lock_dev(pdev, TRUE);
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
{
unlock_dev(pdev, TRUE);
usb_free_mem(purb);
return;
}
hcd = pdev->hcd;
if (purb->status == STATUS_SUCCESS)
{
for(i = 1; i <= hub_ext->port_count; i++)
{
if (hub_ext->int_data_buf[i >> 3] & (1 << i))
{
break;
}
}
if (i > hub_ext->port_count)
{
//no status change, re-initialize the int request
unlock_dev(pdev, TRUE);
usb_free_mem(purb);
hub_start_int_request(pdev);
return;
}
port_idx = (ULONG)i;
//re-use the urb to get port status
purb->pendp = &pdev->default_endp;
purb->data_buffer = (PUCHAR) & hub_ext->port_status;
purb->data_length = sizeof(USB_PORT_STATUS);
purb->pdev = pdev;
purb->context = hub_ext;
purb->pdev = pdev;
purb->completion = hub_get_port_status_completion;
purb->reference = port_idx;
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
psetup->bmRequestType = 0xa3; //host-device class other recepient
psetup->bRequest = USB_REQ_GET_STATUS;
psetup->wValue = 0;
psetup->wIndex = (USHORT) port_idx;
psetup->wLength = 4;
purb->pirp = NULL;
unlock_dev(pdev, TRUE);
status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
if (usb_error(status))
{
usb_free_mem(purb);
purb = NULL;
}
else if (status == STATUS_SUCCESS)
{
// this is for root hub
hcd->hcd_generic_urb_completion(purb, purb->context);
}
return;
}
else
{
unlock_dev(pdev, TRUE);
if (usb_halted(purb->status))
{
//let's reset pipe
usb_reset_pipe(pdev, purb->pendp, hub_reset_pipe_completion, NULL);
}
//unexpected error
usb_free_mem(purb);
purb = NULL;
}
return;
}
VOID
hub_get_port_status_completion(PURB purb, PVOID context)
{
PUSB_DEV pdev;
PUSB_ENDPOINT pendp;
BYTE port_idx;
PHUB2_EXTENSION hub_ext;
PUSB_CTRL_SETUP_PACKET psetup;
NTSTATUS status;
PHCD hcd;
USE_BASIC_NON_PENDING_IRQL;
if (purb == NULL || context == NULL)
return;
usb_dbg_print(DBGLVL_MAXIMUM, ("hub_get_port_feature_completion(): entering...\n"));
pdev = purb->pdev;
pendp = purb->pendp;
lock_dev(pdev, TRUE);
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
{
unlock_dev(pdev, TRUE);
usb_free_mem(purb);
return;
}
hcd = pdev->hcd;
if (usb_error(purb->status))
{
unlock_dev(pdev, TRUE);
purb->status = 0;
//simply retry the request refer to item 55 in document
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
if (status != STATUS_PENDING)
{
if (status == STATUS_SUCCESS)
{
hcd->hcd_generic_urb_completion(purb, purb->context);
}
else
{
//
// must be fatal error
// FIXME: better to pass it to the completion for further
// processing?
//
usb_free_mem(purb);
}
}
return;
}
hub_ext = hub_ext_from_dev(pdev);
port_idx = (BYTE) purb->reference;
usb_dbg_print(DBGLVL_MAXIMUM, ("hub_get_port_stataus_completion(): port_idx=0x%x, hcd =0x%x, \
pdev=0x%x, purb=0x%x, hub_ext=0x%x, portsc=0x%x \n", port_idx, pdev->hcd, pdev,
purb, hub_ext, *((PULONG) purb->data_buffer)));
psq_enqueue(&hub_ext->port_status_queue[port_idx], *((PULONG) purb->data_buffer));
//reuse the urb to clear the feature
RtlZeroMemory(purb, sizeof(URB));
purb->data_buffer = NULL;
purb->data_length = 0;
purb->pendp = &pdev->default_endp;
purb->pdev = pdev;
purb->context = (PVOID) & hub_ext->port_status;
purb->pdev = pdev;
purb->completion = hub_clear_port_feature_completion;
purb->reference = port_idx;
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
psetup->bmRequestType = 0x23; //host-device class port recepient
psetup->bRequest = USB_REQ_CLEAR_FEATURE;
psetup->wIndex = port_idx;
psetup->wLength = 0;
purb->pirp = NULL;
if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_CONNECTION)
{
psetup->wValue = USB_PORT_FEAT_C_CONNECTION;
}
else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_ENABLE)
{
psetup->wValue = USB_PORT_FEAT_C_ENABLE;
}
else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_SUSPEND)
{
psetup->wValue = USB_PORT_FEAT_C_SUSPEND;
}
else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_OVERCURRENT)
{
psetup->wValue = USB_PORT_FEAT_C_OVER_CURRENT;
}
else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_RESET)
{
psetup->wValue = USB_PORT_FEAT_C_RESET;
}
unlock_dev(pdev, TRUE);
status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
// if( status != STATUS_SUCCESS )
if (status != STATUS_PENDING)
{
hcd->hcd_generic_urb_completion(purb, purb->context);
}
/*else if( usb_error( status ) )
{
usb_free_mem( purb );
return;
} */
return;
}
VOID
hub_clear_port_feature_completion(PURB purb, PVOID context)
{
BYTE port_idx;
LONG i;
BOOLEAN event_post, brh;
ULONG pc;
PHCD hcd;
NTSTATUS status;
PUSB_DEV pdev;
PHUB2_EXTENSION hub_ext = NULL;
PUSB_DEV_MANAGER dev_mgr;
PUSB_CTRL_SETUP_PACKET psetup;
USE_BASIC_NON_PENDING_IRQL;
if (purb == NULL)
return;
if (context == NULL)
{
usb_free_mem(purb);
return;
}
usb_dbg_print(DBGLVL_MAXIMUM, ("hub_clear_port_feature_completion(): entering...\n"));
pdev = purb->pdev;
port_idx = (BYTE) purb->reference;
lock_dev(pdev, TRUE);
dev_mgr = dev_mgr_from_dev(pdev);
hcd = pdev->hcd;
brh = (BOOLEAN) (dev_class(pdev) == USB_DEV_CLASS_ROOT_HUB);
if (usb_error(purb->status))
{
unlock_dev(pdev, TRUE);
purb->status = 0;
// retry the request
status = hcd->hcd_submit_urb(hcd, purb->pdev, purb->pendp, purb);
if (status != STATUS_PENDING)
{
if (status == STATUS_SUCCESS)
{
hcd->hcd_generic_urb_completion(purb, purb->context);
}
else
{
//
// FIXME: should we pass the error to the completion directly
// instead of forstall it here?
//
// do not think the device is workable, no requests to it any more.
// including the int polling
//
// usb_free_mem( purb );
//
goto LBL_SCAN_PORT_STAT;
}
}
return;
}
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
{
unlock_dev(pdev, TRUE);
usb_free_mem(purb);
return;
}
pc = ((PUSB_PORT_STATUS) context)->wPortChange;
if (pc)
{
// the bits are tested in ascending order
if (pc & USB_PORT_STAT_C_CONNECTION)
{
pc &= ~USB_PORT_STAT_C_CONNECTION;
}
else if (pc & USB_PORT_STAT_C_ENABLE)
{
pc &= ~USB_PORT_STAT_C_ENABLE;
}
else if (pc & USB_PORT_STAT_C_SUSPEND)
{
pc &= ~USB_PORT_STAT_C_SUSPEND;
}
else if (pc & USB_PORT_STAT_C_OVERCURRENT)
{
pc &= ~USB_PORT_STAT_C_OVERCURRENT;
}
else if (pc & USB_PORT_STAT_C_RESET)
{
pc &= ~USB_PORT_STAT_C_RESET;
}
}
((PUSB_PORT_STATUS) context)->wPortChange = (USHORT) pc;
hub_ext = hub_ext_from_dev(pdev);
if (pc)
{
//some other status change on the port still active
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_CONNECTION)
{
psetup->wValue = USB_PORT_FEAT_C_CONNECTION;
}
else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_ENABLE)
{
psetup->wValue = USB_PORT_FEAT_C_ENABLE;
}
else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_SUSPEND)
{
psetup->wValue = USB_PORT_FEAT_C_SUSPEND;
}
else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_OVERCURRENT)
{
psetup->wValue = USB_PORT_FEAT_C_OVER_CURRENT;
}
else if (hub_ext->port_status.wPortChange & USB_PORT_STAT_C_RESET)
{
psetup->wValue = USB_PORT_FEAT_C_RESET;
}
unlock_dev(pdev, TRUE);
status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
if (status != STATUS_PENDING)
{
if (status == STATUS_SUCCESS)
{
usb_dbg_print(DBGLVL_MAXIMUM,
("hub_clear_port_status_completion(): port_idx=0x%x, hcd=0x%x, \
pdev=0x%x, purb=0x%x, hub_ext=0x%x, wPortChange=0x%x \n",
port_idx, pdev->hcd, pdev, purb, hub_ext, pc));
hcd->hcd_generic_urb_completion(purb, purb->context);
}
else
{
usb_dbg_print(DBGLVL_MAXIMUM, (" hub_clear_port_feature_completion(): \
error=0x%x\n", status));
// usb_free_mem( purb );
goto LBL_SCAN_PORT_STAT;
}
}
return;
}
for(i = 1; i <= hub_ext->port_count; i++)
{
if (hub_ext->int_data_buf[i >> 3] & (1 << i))
{
break;
}
}
//clear the port-change map, we have get port i's status.
hub_ext->int_data_buf[i >> 3] &= ~(1 << i);
//rescan to find some other port that has status change
for(i = 1; i <= hub_ext->port_count; i++)
{
if (hub_ext->int_data_buf[i >> 3] & (1 << i))
{
break;
}
}
if (i <= hub_ext->port_count)
{
//still has port-change pending, get the port status change
port_idx = (UCHAR) i;
//re-use the urb
purb->data_buffer = (PUCHAR) & hub_ext->port_status;
purb->data_length = sizeof(USB_PORT_STATUS);
purb->pendp = &pdev->default_endp;
purb->pdev = pdev;
purb->context = hub_ext;
purb->pdev = pdev;
purb->completion = hub_get_port_status_completion;
purb->reference = port_idx;
psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
psetup->bmRequestType = 0xa3; //host-device class other recepient
psetup->bRequest = USB_REQ_GET_STATUS;
psetup->wValue = 0;
psetup->wIndex = port_idx;
psetup->wLength = 4;
purb->pirp = NULL;
unlock_dev(pdev, TRUE);
status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
if (status != STATUS_PENDING)
{
if (status == STATUS_SUCCESS)
{
hcd->hcd_generic_urb_completion(purb, purb->context);
}
else
{ //must be fatal error
// usb_free_mem( purb );
goto LBL_SCAN_PORT_STAT;
}
}
return;
}
unlock_dev(pdev, TRUE);
LBL_SCAN_PORT_STAT:
//all status changes are cleared
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -