reactos/drivers/usb/nt4compat/usbdriver/devmgr.c
Amine Khaldi c424146e2c Create a branch for cmake bringup.
svn path=/branches/cmake-bringup/; revision=48236
2010-07-24 18:52:44 +00:00

1564 lines
43 KiB
C

/**
* devmgr.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
*/
#include "usbdriver.h"
#define realloc_buf( pdEV, puRB ) \
{\
PBYTE data_buf;\
int i;\
data_buf = usb_alloc_mem( NonPagedPool, ( pdEV )->desc_buf_size += 1024 );\
if (!data_buf)\
{\
goto LBL_OUT;\
}\
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];
USB_DEV_MANAGER g_dev_mgr;
//----------------------------------------------------------
BOOLEAN
dev_mgr_set_if_driver(PUSB_DEV_MANAGER dev_mgr,
DEV_HANDLE if_handle,
PUSB_DRIVER pdriver,
PUSB_DEV pdev //if pdev != NULL, we use pdev instead if_handle, and must have dev_lock acquired.
)
{
ULONG i;
USE_BASIC_NON_PENDING_IRQL;
if (dev_mgr == NULL || if_handle == 0 || pdriver == NULL)
return FALSE;
i = if_idx_from_handle(if_handle);
if (pdev != NULL)
{
if (dev_state(pdev) < USB_DEV_STATE_BEFORE_ZOMB)
{
pdev->usb_config->interf[i].pif_drv = pdriver;
return TRUE;
}
return FALSE;
}
if (usb_query_and_lock_dev(dev_mgr, if_handle, &pdev) != STATUS_SUCCESS)
return FALSE;
lock_dev(pdev, TRUE);
if (dev_state(pdev) != USB_DEV_STATE_ZOMB)
{
pdev->usb_config->interf[i].pif_drv = pdriver;
}
unlock_dev(pdev, TRUE);
usb_unlock_dev(pdev);
return TRUE;
}
BOOLEAN
dev_mgr_set_driver(PUSB_DEV_MANAGER dev_mgr,
DEV_HANDLE dev_handle,
PUSB_DRIVER pdriver,
PUSB_DEV pdev //if pdev != NULL, we use pdev instead if_handle
)
{
USE_BASIC_NON_PENDING_IRQL;
if (dev_mgr == NULL || dev_handle == 0 || pdriver == NULL)
return FALSE;
if (pdev != NULL)
{
if (dev_state(pdev) < USB_DEV_STATE_BEFORE_ZOMB)
{
pdev->dev_driver = pdriver;
return TRUE;
}
return FALSE;
}
if (usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev) != STATUS_SUCCESS)
return FALSE;
lock_dev(pdev, FALSE);
if (dev_state(pdev) < USB_DEV_STATE_BEFORE_ZOMB)
{
pdev->dev_driver = pdriver;
}
unlock_dev(pdev, FALSE);
usb_unlock_dev(pdev);
return TRUE;
}
BOOLEAN
dev_mgr_post_event(PUSB_DEV_MANAGER dev_mgr, PUSB_EVENT event)
{
KIRQL old_irql;
if (dev_mgr == NULL || event == NULL)
return FALSE;
KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);
InsertTailList(&dev_mgr->event_list, &event->event_link);
KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE);
return TRUE;
}
VOID
dev_mgr_driver_entry_init(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdrvr)
{
// Device Info
RtlZeroMemory(pdrvr, sizeof(USB_DRIVER) * DEVMGR_MAX_DRIVERS);
pdrvr[RH_DRIVER_IDX].driver_init = rh_driver_init; // in fact, this routine will init the rh device rather that the driver struct.
pdrvr[RH_DRIVER_IDX].driver_destroy = rh_driver_destroy; // we do not need rh to destroy currently, since that may means fatal hardware failure
pdrvr[HUB_DRIVER_IDX].driver_init = hub_driver_init; //no need, since dev_mgr is also a hub driver
pdrvr[HUB_DRIVER_IDX].driver_destroy = hub_driver_destroy;
pdrvr[UMSS_DRIVER_IDX].driver_init = umss_if_driver_init;
pdrvr[UMSS_DRIVER_IDX].driver_destroy = umss_if_driver_destroy;
pdrvr[COMP_DRIVER_IDX].driver_init = compdev_driver_init;
pdrvr[COMP_DRIVER_IDX].driver_destroy = compdev_driver_destroy;
pdrvr[GEN_DRIVER_IDX].driver_init = gendrv_driver_init;
pdrvr[GEN_DRIVER_IDX].driver_destroy = gendrv_driver_destroy;
pdrvr[GEN_IF_DRIVER_IDX].driver_init = gendrv_if_driver_init;
pdrvr[GEN_IF_DRIVER_IDX].driver_destroy = gendrv_if_driver_destroy;
pdrvr[MOUSE_DRIVER_IDX].driver_init = mouse_driver_init;
pdrvr[MOUSE_DRIVER_IDX].driver_destroy = mouse_driver_destroy;
pdrvr[KEYBOARD_DRIVER_IDX].driver_init = kbd_driver_init;
pdrvr[KEYBOARD_DRIVER_IDX].driver_destroy = kbd_driver_destroy;
}
BOOLEAN
dev_mgr_strobe(PUSB_DEV_MANAGER dev_mgr)
{
PUSB_EVENT pevent;
HANDLE thread_handle;
if (dev_mgr == NULL)
return FALSE;
if (dev_mgr->hcd_count == 0)
return FALSE;
dev_mgr->term_flag = FALSE;
if (dev_mgr->hcd_count == 0)
return FALSE;
KeInitializeSpinLock(&dev_mgr->event_list_lock);
InitializeListHead(&dev_mgr->event_list);
init_event_pool(&dev_mgr->event_pool);
pevent = alloc_event(&dev_mgr->event_pool, 1);
if (pevent == NULL)
{
destroy_event_pool(&dev_mgr->event_pool);
return FALSE;
}
pevent->flags = USB_EVENT_FLAG_ACTIVE;
pevent->event = USB_EVENT_INIT_DEV_MGR;
pevent->process_queue = event_list_default_process_queue;
pevent->process_event = (PROCESS_EVENT)dev_mgr_event_init;
pevent->context = (ULONG) dev_mgr;
KeInitializeEvent(&dev_mgr->wake_up_event, SynchronizationEvent, FALSE);
KeInitializeEvent(&dev_mgr->drivers_inited, NotificationEvent, FALSE);
InsertTailList(&dev_mgr->event_list, &pevent->event_link);
if (PsCreateSystemThread(&thread_handle, 0, NULL, NULL, NULL, dev_mgr_thread, dev_mgr) != STATUS_SUCCESS)
{
destroy_event_pool(&dev_mgr->event_pool);
return FALSE;
}
ObReferenceObjectByHandle(thread_handle,
THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID *) & dev_mgr->pthread, NULL);
ZwClose(thread_handle);
return TRUE;
}
BOOLEAN
dev_mgr_event_init(PUSB_DEV pdev, //always null. we do not use this param
ULONG event, ULONG context, ULONG param)
{
LARGE_INTEGER due_time;
PUSB_DEV_MANAGER dev_mgr;
LONG i;
usb_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_event_init(): dev_mgr=0x%x, event=0x%x\n", context, event));
dev_mgr = (PUSB_DEV_MANAGER) context;
if (dev_mgr == NULL)
return FALSE;
if (event != USB_EVENT_INIT_DEV_MGR)
return FALSE;
//dev_mgr->root_hub = NULL;
KeInitializeTimer(&dev_mgr->dev_mgr_timer);
KeInitializeDpc(&dev_mgr->dev_mgr_timer_dpc, dev_mgr_timer_dpc_callback, (PVOID) dev_mgr);
KeInitializeSpinLock(&dev_mgr->timer_svc_list_lock);
InitializeListHead(&dev_mgr->timer_svc_list);
init_timer_svc_pool(&dev_mgr->timer_svc_pool);
dev_mgr->timer_click = 0;
init_irp_list(&dev_mgr->irp_list);
KeInitializeSpinLock(&dev_mgr->dev_list_lock);
InitializeListHead(&dev_mgr->dev_list);
dev_mgr->hub_count = 0;
InitializeListHead(&dev_mgr->hub_list);
dev_mgr->conn_count = 0;
dev_mgr->driver_list = g_driver_list;
dev_mgr_driver_entry_init(dev_mgr, dev_mgr->driver_list);
for(i = 0; i < DEVMGR_MAX_DRIVERS; i++)
{
if (dev_mgr->driver_list[i].driver_init == NULL)
continue;
if (dev_mgr->driver_list[i].driver_init(dev_mgr, &dev_mgr->driver_list[i]) == FALSE)
break;
}
if (i == DEVMGR_MAX_DRIVERS)
{
due_time.QuadPart = -(DEV_MGR_TIMER_INTERVAL_NS - 10);
KeSetTimerEx(&dev_mgr->dev_mgr_timer,
due_time, DEV_MGR_TIMER_INTERVAL_MS, &dev_mgr->dev_mgr_timer_dpc);
/* Signal we're done initing */
KeSetEvent(&dev_mgr->drivers_inited, 0, FALSE);
return TRUE;
}
i--;
for(; i >= 0; i--)
{
if (dev_mgr->driver_list[i].driver_destroy)
dev_mgr->driver_list[i].driver_destroy(dev_mgr, &dev_mgr->driver_list[i]);
}
KeCancelTimer(&dev_mgr->dev_mgr_timer);
KeRemoveQueueDpc(&dev_mgr->dev_mgr_timer_dpc);
KeSetEvent(&dev_mgr->drivers_inited, 0, FALSE);
return FALSE;
}
VOID
dev_mgr_destroy(PUSB_DEV_MANAGER dev_mgr)
{
LONG i;
// oops...
KeCancelTimer(&dev_mgr->dev_mgr_timer);
KeRemoveQueueDpc(&dev_mgr->dev_mgr_timer_dpc);
for(i = DEVMGR_MAX_DRIVERS - 1; i >= 0; i--)
dev_mgr->driver_list[i].driver_destroy(dev_mgr, &dev_mgr->driver_list[i]);
destroy_irp_list(&dev_mgr->irp_list);
destroy_timer_svc_pool(&dev_mgr->timer_svc_pool);
destroy_event_pool(&dev_mgr->event_pool);
}
VOID
NTAPI
dev_mgr_thread(PVOID context)
{
PUSB_DEV_MANAGER dev_mgr;
PUSB_EVENT pevent;
PLIST_ENTRY pthis, pnext;
USB_EVENT usb_event;
LARGE_INTEGER time_out;
NTSTATUS status;
BOOLEAN dev_mgr_inited;
KIRQL old_irql;
LONG i;
dev_mgr = (PUSB_DEV_MANAGER) context;
dev_mgr_inited = FALSE;
usb_cal_cpu_freq();
time_out.u.LowPart = (10 * 1000 * 1000) * 100 - 1; //1 minutes
time_out.u.HighPart = 0;
time_out.QuadPart = -time_out.QuadPart;
//usb_dbg_print( DBGLVL_MAXIMUM + 1, ( "dev_mgr_thread(): current uhci status=0x%x\n", uhci_status( dev_mgr->pdev_ext->uhci ) ) );
while (dev_mgr->term_flag == FALSE)
{
KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);
if (IsListEmpty(&dev_mgr->event_list) == TRUE)
{
KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
status = KeWaitForSingleObject(&dev_mgr->wake_up_event, Executive, KernelMode, TRUE, &time_out);
continue;
}
/*
usb_dbg_print( DBGLVL_MAXIMUM, ( "dev_mgr_thread(): current element in event list is 0x%x\n", \
dbg_count_list( &dev_mgr->event_list ) ) ); */
dev_mgr_inited = TRUE; //since we have post one event, if this statement is executed, dev_mgr_event_init must be called sometime later or earlier
ListFirst(&dev_mgr->event_list, pthis);
pevent = struct_ptr(pthis, USB_EVENT, event_link);
while (pevent && ((pevent->flags & USB_EVENT_FLAG_ACTIVE) == 0))
{
//skip inactive ones
ListNext(&dev_mgr->event_list, &pevent->event_link, pnext);
pevent = struct_ptr(pnext, USB_EVENT, event_link);
}
if (pevent != NULL)
{
if (pevent->process_queue == NULL)
pevent->process_queue = event_list_default_process_queue;
pevent->process_queue(&dev_mgr->event_list, &dev_mgr->event_pool, pevent, &usb_event);
}
else
{
//no active event
KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
status = KeWaitForSingleObject(&dev_mgr->wake_up_event, Executive, KernelMode, TRUE, &time_out // 10 minutes
);
usb_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_thread(): wake up, reason=0x%x\n", status));
continue;
}
KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
if (usb_event.process_event)
{
usb_event.process_event(usb_event.pdev, usb_event.event, usb_event.context, usb_event.param);
}
else
{
event_list_default_process_event(usb_event.pdev,
usb_event.event, usb_event.context, usb_event.param);
}
}
if (dev_mgr_inited)
{
for(i = 0; i < dev_mgr->hcd_count; i++)
dev_mgr_disconnect_dev(dev_mgr->hcd_array[i]->hcd_get_root_hub(dev_mgr->hcd_array[i]));
dev_mgr_destroy(dev_mgr);
}
PsTerminateSystemThread(0);
}
VOID
NTAPI
dev_mgr_timer_dpc_callback(PKDPC Dpc, PVOID context, PVOID SystemArgument1, PVOID SystemArgument2)
{
PUSB_DEV_MANAGER dev_mgr;
LIST_HEAD templist;
PLIST_ENTRY pthis, pnext;
static ULONG ticks = 0;
ticks++;
dev_mgr = (PUSB_DEV_MANAGER) context;
if (dev_mgr == NULL)
return;
dev_mgr->timer_click++;
InitializeListHead(&templist);
KeAcquireSpinLockAtDpcLevel(&dev_mgr->timer_svc_list_lock);
if (IsListEmpty(&dev_mgr->timer_svc_list) == TRUE)
{
KeReleaseSpinLockFromDpcLevel(&dev_mgr->timer_svc_list_lock);
return;
}
ListFirst(&dev_mgr->timer_svc_list, pthis);
while (pthis)
{
((PTIMER_SVC) pthis)->counter++;
ListNext(&dev_mgr->timer_svc_list, pthis, pnext);
if (((PTIMER_SVC) pthis)->counter >= ((PTIMER_SVC) pthis)->threshold)
{
RemoveEntryList(pthis);
InsertTailList(&templist, pthis);
}
pthis = pnext;
}
KeReleaseSpinLockFromDpcLevel(&dev_mgr->timer_svc_list_lock);
while (IsListEmpty(&templist) == FALSE)
{
pthis = RemoveHeadList(&templist);
((PTIMER_SVC) pthis)->func(((PTIMER_SVC) pthis)->pdev, (PVOID) ((PTIMER_SVC) pthis)->context);
KeAcquireSpinLockAtDpcLevel(&dev_mgr->timer_svc_list_lock);
free_timer_svc(&dev_mgr->timer_svc_pool, (PTIMER_SVC) pthis);
KeReleaseSpinLockFromDpcLevel(&dev_mgr->timer_svc_list_lock);
}
}
BOOLEAN
dev_mgr_request_timer_svc(PUSB_DEV_MANAGER dev_mgr,
PUSB_DEV pdev, ULONG context, ULONG due_time, TIMER_SVC_HANDLER handler)
{
PTIMER_SVC timer_svc;
KIRQL old_irql;
if (dev_mgr == NULL || pdev == NULL || due_time == 0 || handler == NULL)
return FALSE;
KeAcquireSpinLock(&dev_mgr->timer_svc_list_lock, &old_irql);
timer_svc = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
if (timer_svc == NULL)
{
KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
return FALSE;
}
timer_svc->pdev = pdev;
timer_svc->threshold = due_time;
timer_svc->func = handler;
timer_svc->counter = 0;
InsertTailList(&dev_mgr->timer_svc_list, &timer_svc->timer_svc_link);
KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
return TRUE;
}
BYTE
dev_mgr_alloc_addr(PUSB_DEV_MANAGER dev_mgr, PHCD hcd)
{
// alloc a usb addr for the device within 1-128
if (dev_mgr == NULL || hcd == NULL)
return 0xff;
return hcd->hcd_alloc_addr(hcd);
}
BOOLEAN
dev_mgr_free_addr(PUSB_DEV_MANAGER dev_mgr, PUSB_DEV pdev, BYTE addr)
{
PHCD hcd;
if (addr & 0x80)
return FALSE;
if (dev_mgr == NULL || pdev == NULL)
return FALSE;
hcd = pdev->hcd;
if (hcd == NULL)
return FALSE;
hcd->hcd_free_addr(hcd, addr);
return TRUE;
}
PUSB_DEV
dev_mgr_alloc_device(PUSB_DEV_MANAGER dev_mgr, PHCD hcd)
{
BYTE addr;
PUSB_DEV pdev;
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 || data_buf == 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:
if (purb)
{
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;
PDEV_CONNECT_DATA pcd = (PDEV_CONNECT_DATA) Parameter;
PUSB_DEV_MANAGER dev_mgr;
DEV_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(&param, 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;
DEV_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;
PBYTE pbuf;
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;
pbuf = &((PBYTE) pif_desc)[sizeof(USB_INTERFACE_DESC)];
i = 0;
while (i < pif->endp_count)
{
pendp_desc = (PUSB_ENDPOINT_DESC)pbuf;
// check if it's an endpoint descriptor
if (pendp_desc->bDescriptorType == USB_DT_ENDPOINT)
{
// add it
dev_mgr_build_usb_endp(pif, &pif->endp[i], pendp_desc);
i++;
}
// skip to the next one
pbuf += pendp_desc->bLength;
}
}
else
{
PUSB_INTERFACE paltif;
PLIST_ENTRY pthis, pnext;
pif->altif_count++;
paltif = usb_alloc_mem(NonPagedPool, sizeof(USB_INTERFACE));
if (!paltif) return FALSE;
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);
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
{
pif = &pcfg->interf[i-1];
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;
}
VOID
dev_mgr_deregister_hcd(PUSB_DEV_MANAGER dev_mgr, UCHAR hcd_id)
{
UCHAR i;
if (dev_mgr == NULL || hcd_id >= MAX_HCDS - 1)
return;
for (i = hcd_id; i < dev_mgr->hcd_count - 1; i++)
dev_mgr->hcd_array[i] = dev_mgr->hcd_array[i + 1];
dev_mgr->hcd_count--;
}
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;
}