📄 hub.c
字号:
/**
* hub.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"
//----------------------------------------------------------
//event pool routines
#define crash_machine() \
{ ( ( PUSB_DEV ) 0 )->flags = 0x12345; }
#define hub_if_from_dev( pdEV, pIF ) \
{\
int i;\
for( i = 0; i < pdEV->usb_config->if_count; i ++ )\
{\
if( pdEV->usb_config->interf[ i ].pusb_if_desc->bInterfaceClass\
== USB_CLASS_HUB )\
{\
break;\
}\
}\
\
if( i < pdEV->usb_config->if_count )\
pIF = &pdev->usb_config->interf[ i ];\
else\
pIF = NULL;\
\
}
extern ULONG cpu_clock_freq;
BOOLEAN hub_check_reset_port_status(PUSB_DEV pdev, LONG port_idx);
VOID hub_reexamine_port_status_queue(PUSB_DEV hub_dev, ULONG port_idx, BOOLEAN from_dpc);
void hub_int_completion(PURB purb, PVOID pcontext);
VOID hub_get_port_status_completion(PURB purb, PVOID context);
VOID hub_clear_port_feature_completion(PURB purb, PVOID context);
VOID hub_event_examine_status_que(PUSB_DEV pdev, ULONG event, ULONG context, //hub_ext
ULONG param //port_idx
);
VOID hub_timer_wait_dev_stable(PUSB_DEV pdev,
PVOID context //port-index
);
VOID hub_event_dev_stable(PUSB_DEV pdev,
ULONG event,
ULONG context, //hub_ext
ULONG param //port_idx
);
VOID hub_post_esq_event(PUSB_DEV pdev, BYTE port_idx, PROCESS_EVENT pe);
void hub_set_cfg_completion(PURB purb, PVOID pcontext);
void hub_get_hub_desc_completion(PURB purb, PVOID pcontext);
NTSTATUS hub_start_int_request(PUSB_DEV pdev);
BOOLEAN hub_connect(PDEV_CONNECT_DATA init_param, DEV_HANDLE dev_handle);
BOOLEAN hub_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
BOOLEAN hub_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
NTSTATUS hub_disable_port_request(PUSB_DEV pdev, UCHAR port_idx);
VOID hub_start_reset_port_completion(PURB purb, PVOID context);
BOOLEAN
init_event_pool(PUSB_EVENT_POOL pool)
{
int i;
if (pool == NULL)
return FALSE;
if ((pool->event_array = usb_alloc_mem(NonPagedPool, sizeof(USB_EVENT) * MAX_EVENTS)) == NULL)
return FALSE;
InitializeListHead(&pool->free_que);
KeInitializeSpinLock(&pool->pool_lock);
pool->total_count = MAX_EVENTS;
pool->free_count = 0;
for(i = 0; i < MAX_EVENTS; i++)
{
free_event(pool, &pool->event_array[i]);
}
return TRUE;
}
BOOLEAN
free_event(PUSB_EVENT_POOL pool, PUSB_EVENT pevent)
{
if (pool == NULL || pevent == NULL)
{
return FALSE;
}
RtlZeroMemory(pevent, sizeof(USB_EVENT));
InsertTailList(&pool->free_que, (PLIST_ENTRY) pevent);
pool->free_count++;
usb_dbg_print(DBGLVL_MAXIMUM + 1,
("free_event(): alloced=0x%x, addr=0x%x\n", MAX_EVENTS - pool->free_count, pevent));
return TRUE;
}
//null if failed
PUSB_EVENT
alloc_event(PUSB_EVENT_POOL pool, LONG count)
{
PUSB_EVENT NewEvent;
if (pool == NULL || count != 1)
return NULL;
if (pool->free_count == 0)
return NULL;
NewEvent = (PUSB_EVENT) RemoveHeadList(&pool->free_que);
pool->free_count--;
usb_dbg_print(DBGLVL_MAXIMUM + 1,
("alloc_event(): alloced=0x%x, addr=0x%x\n", MAX_EVENTS - pool->free_count, NewEvent));
return NewEvent;
}
BOOLEAN
destroy_event_pool(PUSB_EVENT_POOL pool)
{
if (pool == NULL)
return FALSE;
InitializeListHead(&pool->free_que);
pool->free_count = pool->total_count = 0;
usb_free_mem(pool->event_array);
pool->event_array = NULL;
return TRUE;
}
VOID
event_list_default_process_event(PUSB_DEV pdev, ULONG event, ULONG context, ULONG param)
{
UNREFERENCED_PARAMETER(param);
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(event);
UNREFERENCED_PARAMETER(pdev);
}
//----------------------------------------------------------
//timer_svc pool routines
BOOLEAN
init_timer_svc_pool(PTIMER_SVC_POOL pool)
{
int i;
if (pool == NULL)
return FALSE;
pool->timer_svc_array = usb_alloc_mem(NonPagedPool, sizeof(TIMER_SVC) * MAX_TIMER_SVCS);
InitializeListHead(&pool->free_que);
pool->free_count = 0;
pool->total_count = MAX_TIMER_SVCS;
KeInitializeSpinLock(&pool->pool_lock);
for(i = 0; i < MAX_TIMER_SVCS; i++)
{
free_timer_svc(pool, &pool->timer_svc_array[i]);
}
return TRUE;
}
BOOLEAN
free_timer_svc(PTIMER_SVC_POOL pool, PTIMER_SVC ptimer)
{
if (pool == NULL || ptimer == NULL)
return FALSE;
RtlZeroMemory(ptimer, sizeof(TIMER_SVC));
InsertTailList(&pool->free_que, (PLIST_ENTRY) & ptimer->timer_svc_link);
pool->free_count++;
return TRUE;
}
//null if failed
PTIMER_SVC
alloc_timer_svc(PTIMER_SVC_POOL pool, LONG count)
{
PTIMER_SVC NewTimer;
if (pool == NULL || count != 1)
return NULL;
if (pool->free_count <= 0)
return NULL;
NewTimer = (PTIMER_SVC) RemoveHeadList(&pool->free_que);
pool->free_count--;
return NewTimer;
}
BOOLEAN
destroy_timer_svc_pool(PTIMER_SVC_POOL pool)
{
if (pool == NULL)
return FALSE;
usb_free_mem(pool->timer_svc_array);
pool->timer_svc_array = NULL;
InitializeListHead(&pool->free_que);
pool->free_count = 0;
pool->total_count = 0;
return TRUE;
}
VOID
event_list_default_process_queue(PLIST_HEAD event_list,
PUSB_EVENT_POOL event_pool, PUSB_EVENT usb_event, PUSB_EVENT out_event)
{
//remove the first event from the event list, and copy it to
//out_event
if (event_list == NULL || event_pool == NULL || usb_event == NULL || out_event == NULL)
return;
RemoveEntryList(&usb_event->event_link);
RtlCopyMemory(out_event, usb_event, sizeof(USB_EVENT));
free_event(event_pool, usb_event);
return;
}
BOOLEAN
psq_enqueue(PPORT_STATUS_QUEUE psq, ULONG status)
{
if (psq == NULL)
return FALSE;
if (psq_is_full(psq))
return FALSE;
psq->port_status[psq->status_count].wPortChange = HIWORD(status);
psq->port_status[psq->status_count].wPortStatus = LOWORD(status);
psq->status_count++;
usb_dbg_print(DBGLVL_MAXIMUM, ("psq_enqueue(): last status=0x%x, status count=0x%x, port_flag=0x%x\n",
status, psq->status_count, psq->port_flags));
return TRUE;
}
VOID
psq_init(PPORT_STATUS_QUEUE psq)
{
RtlZeroMemory(psq, sizeof(PORT_STATUS_QUEUE));
psq->port_flags = STATE_IDLE | USB_PORT_FLAG_DISABLE;
}
//return 0xffffffff if no element
ULONG
psq_outqueue(PPORT_STATUS_QUEUE psq)
{
ULONG status;
if (psq == NULL)
return 0;
if (psq_is_empty(psq))
return 0;
status = ((PULONG) & psq->port_status)[0];
psq->port_status[0] = psq->port_status[1];
psq->port_status[1] = psq->port_status[2];
psq->port_status[2] = psq->port_status[3];
psq->status_count--;
return status;
}
BOOLEAN
psq_push(PPORT_STATUS_QUEUE psq, ULONG status)
{
if (psq == NULL)
return FALSE;
status = ((PULONG) & psq->port_status)[0];
psq->port_status[3] = psq->port_status[2];
psq->port_status[2] = psq->port_status[1];
psq->port_status[1] = psq->port_status[0];
((PULONG) & psq->port_status)[0] = status;
psq->status_count++;
psq->status_count = ((4 > psq->status_count) ? psq->status_count : 4);
return TRUE;
}
BOOLEAN
hub_driver_init(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
{
UNREFERENCED_PARAMETER(dev_mgr);
//init driver structure, no PNP table functions
pdriver->driver_desc.flags = USB_DRIVER_FLAG_DEV_CAPABLE;
pdriver->driver_desc.vendor_id = 0xffff; // USB Vendor ID
pdriver->driver_desc.product_id = 0xffff; // USB Product ID.
pdriver->driver_desc.release_num = 0xffff; // Release Number of Device
pdriver->driver_desc.config_val = 0; // Configuration Value
pdriver->driver_desc.if_num = 0; // Interface Number
pdriver->driver_desc.if_class = USB_CLASS_HUB; // Interface Class
pdriver->driver_desc.if_sub_class = 0; // Interface SubClass
pdriver->driver_desc.if_protocol = 0; // Interface Protocol
pdriver->driver_desc.driver_name = "USB hub"; // Driver name for Name Registry
pdriver->driver_desc.dev_class = USB_CLASS_HUB;
pdriver->driver_desc.dev_sub_class = 0; // Device Subclass
pdriver->driver_desc.dev_protocol = 0; // Protocol Info.
//pdriver->driver_init = hub_driver_init; // initialized in dev_mgr_init_driver
//pdriver->driver_destroy = hub_driver_destroy;
pdriver->driver_ext = 0;
pdriver->driver_ext_size = 0;
pdriver->disp_tbl.version = 1;
pdriver->disp_tbl.dev_connect = hub_connect;
pdriver->disp_tbl.dev_disconnect = hub_disconnect;
pdriver->disp_tbl.dev_stop = hub_stop;
pdriver->disp_tbl.dev_reserved = NULL;
return TRUE;
}
BOOLEAN
hub_driver_destroy(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
{
UNREFERENCED_PARAMETER(dev_mgr);
pdriver->driver_ext = NULL;
return TRUE;
}
void
hub_reset_pipe_completion(PURB purb, //only for reference, can not be released
PVOID context)
{
PUSB_DEV pdev;
PUSB_ENDPOINT pendp;
USE_BASIC_NON_PENDING_IRQL;
UNREFERENCED_PARAMETER(context);
if (purb == NULL)
{
return;
}
pdev = purb->pdev;
pendp = purb->pendp;
lock_dev(pdev, TRUE);
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
{
unlock_dev(pdev, TRUE);
return;
}
if (usb_error(purb->status))
{
//simply retry it
unlock_dev(pdev, TRUE);
//usb_free_mem( purb );
return;
}
unlock_dev(pdev, TRUE);
pdev = purb->pdev;
hub_start_int_request(pdev);
return;
}
NTSTATUS
hub_start_int_request(PUSB_DEV pdev)
{
PURB purb;
PUSB_INTERFACE pif;
PHUB2_EXTENSION hub_ext;
NTSTATUS status;
PHCD hcd;
USE_BASIC_NON_PENDING_IRQL;
if (pdev == NULL)
return STATUS_INVALID_PARAMETER;
lock_dev(pdev, FALSE);
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
{
unlock_dev(pdev, FALSE);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
RtlZeroMemory(purb, sizeof(URB));
if (purb == NULL)
{
unlock_dev(pdev, FALSE);
return STATUS_NO_MEMORY;
}
purb->flags = 0;
purb->status = STATUS_SUCCESS;
hub_ext = hub_ext_from_dev(pdev);
purb->data_buffer = hub_ext->int_data_buf;
purb->data_length = (hub_ext->port_count + 7) / 8;
hub_if_from_dev(pdev, pif);
usb_dbg_print(DBGLVL_ULTRA, ("hub_start_int_request(): pdev=0x%x, pif=0x%x\n", pdev, pif));
purb->pendp = &pif->endp[0];
purb->pdev = pdev;
purb->completion = hub_int_completion;
purb->context = hub_ext;
purb->pirp = NULL;
purb->reference = 0;
hcd = pdev->hcd;
unlock_dev(pdev, FALSE);
status = hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb);
if (status != STATUS_PENDING)
{
usb_free_mem(purb);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -