⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ehci.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
    PUSB_DEV pdev, dest_dev;
    PSYNC_PARAM sync_param;
    PLIST_ENTRY pthis, pnext;
    LONG count;

    sync_param = (PSYNC_PARAM) context;
    dest_dev = (PUSB_DEV) sync_param->context;
    ehci = sync_param->ehci;

    if (ehci == NULL || dest_dev == NULL)
    {
        return (UCHAR) (sync_param->ret = FALSE);
    }
    count = 0;
    ListFirst(&ehci->urb_list, pthis);
    while (pthis)
    {
        pdev = dev_from_endp(((PURB) pthis)->pendp);
        if (pdev == dest_dev)
        {
            ((PURB) pthis)->flags |= URB_FLAG_FORCE_CANCEL;
        }
        ListNext(&ehci->urb_list, pthis, pnext);
        pthis = pnext;
        count++;
    }

    if (count)
    {
        // signal an int for further process
        press_doorbell(ehci);
    }
    return (UCHAR) (sync_param->ret = TRUE);
}

BOOLEAN
ehci_remove_device(PEHCI_DEV ehci, PUSB_DEV dev)
{
    PUHCI_PENDING_ENDP ppending_endp;
    PLIST_ENTRY pthis, pnext;
    PURB purb;
    LIST_HEAD temp_list;
    int i, j, k;
    SYNC_PARAM sync_param;

    USE_BASIC_IRQL;

    if (ehci == NULL || dev == NULL)
        return FALSE;

    InitializeListHead(&temp_list);

    //free pending endp that has purb queued from pending endp list
    lock_pending_endp_list(&ehci->pending_endp_list_lock);

    ListFirst(&ehci->pending_endp_list, pthis);

    while (pthis)
    {
        ppending_endp = (PUHCI_PENDING_ENDP) pthis;
        ListNext(&ehci->pending_endp_list, pthis, pnext);
        if (dev_from_endp(ppending_endp->pendp) == dev)
        {
            RemoveEntryList(pthis);
            free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
        }
        pthis = pnext;
    }
    unlock_pending_endp_list(&ehci->pending_endp_list_lock);

    //cancel all the urbs in the purb-list
    sync_param.ehci = ehci;
    sync_param.context = (PVOID) dev;

    KeSynchronizeExecution(ehci->pdev_ext->ehci_int, ehci_sync_cancel_urbs_dev, &sync_param);

    //cancel all the purb in the endp's purb-list
    k = 0;
    lock_dev(dev, FALSE);
    if (dev->usb_config)
    {
        //only for configed dev 
        for(i = 0; i < dev->usb_config->if_count; i++)
        {
            for(j = 0; j < dev->usb_config->interf[i].endp_count; j++)
            {
                ListFirst(&dev->usb_config->interf[i].endp[j].urb_list, pthis);
                while (pthis)
                {
                    ListNext(&dev->usb_config->interf[i].endp[j].urb_list, pthis, pnext);

                    RemoveEntryList(pthis);
                    InsertHeadList(&temp_list, pthis);
                    pthis = pnext;
                    k++;
                }

            }
        }
    }
    ListFirst(&dev->default_endp.urb_list, pthis);

    while (pthis)
    {
        ListNext(&dev->default_endp.urb_list, pthis, pnext);

        RemoveEntryList(pthis);
        InsertHeadList(&temp_list, pthis);
        pthis = pnext;
        k++;
    }
    unlock_dev(dev, FALSE);

    if (IsListEmpty(&temp_list) == FALSE)
    {
        for(i = 0; i < k; i++)
        {
            //complete those urbs with error
            pthis = RemoveHeadList(&temp_list);
            purb = (PURB) pthis;
            purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
            {
                ehci_generic_urb_completion(purb, purb->context);
            }
        }
    }

    lock_dev(dev, FALSE) dev->ref_count -= k;
    unlock_dev(dev, FALSE);

    return TRUE;
}

static BOOLEAN
ehci_insert_urb_schedule(PEHCI_DEV ehci, PURB purb)
// must have dev_lock( ehci_process_pending_endp ) and frame_list_lock acquired
{
    PURB_HS_PIPE_CONTENT pipe_content;

    if (ehci == NULL || purb == NULL)
        return FALSE;

    pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
    switch (pipe_content->trans_type)
    {
        case USB_ENDPOINT_XFER_CONTROL:
            ehci_insert_control_schedule(ehci, purb);
            break;
        case USB_ENDPOINT_XFER_BULK:
            ehci_insert_bulk_schedule(ehci, purb);
            break;
        case USB_ENDPOINT_XFER_INT:
            ehci_insert_int_schedule(ehci, purb);
            break;
        case USB_ENDPOINT_XFER_ISOC:
            ehci_insert_iso_schedule(ehci, purb);
            break;
        default:
            return FALSE;
    }

    purb->flags &= ~URB_FLAG_STATE_MASK;
    purb->flags |= URB_FLAG_STATE_IN_PROCESS | URB_FLAG_IN_SCHEDULE;
    InsertTailList(&ehci->urb_list, (PLIST_ENTRY) purb);

    return TRUE;
}

static BOOLEAN
ehci_insert_tds_qh(PEHCI_DEV ehci, PEHCI_QH pqh, PEHCI_QTD td_chain)
{
    if (pqh == NULL || td_chain == NULL)
        return FALSE;

    UNREFERENCED_PARAMETER(ehci);

    ehci_copy_overlay((PEHCI_QH_CONTENT) pqh, (PEHCI_QTD_CONTENT) td_chain);
    InsertTailList(&td_chain->elem_head_link->elem_link, &pqh->elem_head_link->elem_link);
    return TRUE;
}

static BOOLEAN
ehci_insert_qh_urb(PURB purb, PEHCI_QH pqh)
{
    PLIST_ENTRY pthis, pnext;
    if (pqh == NULL || purb == NULL)
        return FALSE;

    InsertTailList(&pqh->elem_head_link->elem_link, &purb->trasac_list);
    ListFirst(&purb->trasac_list, pthis) while (pthis)
    {
        // note: fstn may in this chain
        struct_ptr(pthis, EHCI_ELEM_LINKS, elem_link)->purb = purb;
        ListNext(&purb->trasac_list, pthis, pnext);
        pthis = pnext;
    }
    return TRUE;
}

#define calc_td_count( pURB, start_aDDR, td_coUNT ) \
{\
	LONG i, j, k;\
	td_coUNT = 0;\
	k = ( ( pURB )->bytes_to_transfer + max_packet_size - 1 ) / max_packet_size;\
	if( k != 0 )\
	{\
		LONG packets_per_td, packets_per_page;\
		packets_per_td = EHCI_QTD_MAX_TRANS_SIZE / max_packet_size;\
		packets_per_page = PAGE_SIZE / max_packet_size;\
		i = ( ( LONG )&( pURB )->data_buffer[ ( start_aDDR ) ] ) & ( PAGE_SIZE - 1 );\
		if( i )\
		{\
			i = PAGE_SIZE - i;\
			j = i & ( max_packet_size - 1 );\
			k -= ( EHCI_QTD_MAX_TRANS_SIZE - PAGE_SIZE + i - j ) / max_packet_size;\
			if( k < 0 )\
				td_coUNT = 1;\
			else\
			{\
				if( j )\
					i = packets_per_td - packets_per_page;\
				else\
					i = packets_per_td;\
				td_coUNT = 1 + ( k + i - 1 ) / i; \
			}\
		}\
		else\
		{\
			td_coUNT = ( k + packets_per_td - 1 ) / packets_per_td;\
		}\
	}\
}

static BOOLEAN
ehci_fill_td_buf_ptr(PURB purb, LONG start_addr,        // start idx into purb->data_buffer
                     PLIST_ENTRY td_list, LONG td_count, ULONG toggle)
// fill the tds' bytes_to_transfer and hw_buf, return next toggle value: true 1, false 0
{
    LONG i, j, k, data_load;
    LONG packets_per_td, packets_per_page, bytes_to_transfer, max_packet_size;
    PLIST_ENTRY pthis, pnext;
    PEHCI_QTD_CONTENT ptdc;
    PEHCI_QTD ptd;
    PVOID ptr;

    if (purb == NULL || td_list == NULL || td_count == 0)
        return toggle;

    max_packet_size = 1 << ((PURB_HS_PIPE_CONTENT) & purb->pipe)->max_packet_size;
    packets_per_td = EHCI_QTD_MAX_TRANS_SIZE / max_packet_size;
    packets_per_page = PAGE_SIZE / max_packet_size;

    pthis = td_list;
    bytes_to_transfer = purb->bytes_to_transfer;

    i = ((LONG) & (purb)->data_buffer[(start_addr)]) & (PAGE_SIZE - 1);
    if (i)
    {
        i = PAGE_SIZE - i;
        j = i & (max_packet_size - 1);
    }
    else
    {
        i = j = 0;
    }

    while (bytes_to_transfer)
    {
        ptd = qtd_from_list_entry(pthis);
        ptd->hw_buf[0] = MmGetPhysicalAddress(&purb->data_buffer[start_addr]).LowPart;
        ptdc = (PEHCI_QTD_CONTENT) ptd;

        if (i != 0)
        {
            data_load = (LONG) (EHCI_QTD_MAX_TRANS_SIZE - PAGE_SIZE + i - j) < bytes_to_transfer
                ? (LONG) (EHCI_QTD_MAX_TRANS_SIZE - PAGE_SIZE + i - j) : bytes_to_transfer;

            ptdc->bytes_to_transfer = (USHORT) data_load;
            ptd->bytes_to_transfer = (USHORT) data_load;

            // subtract the header part
            data_load -= (i < data_load ? i : data_load);

            for(k = 1; data_load > 0; k++)
            {
                ptr = &purb->data_buffer[start_addr + i + (k - 1) * PAGE_SIZE];
                ptr = (PVOID) (((ULONG) ptr) & ~(PAGE_SIZE - 1));
                ptd->hw_buf[k] = MmGetPhysicalAddress(ptr).LowPart;
                data_load -= PAGE_SIZE < data_load ? PAGE_SIZE : data_load;
            }
        }
        else
        {
            // aligned on page boundary
            data_load = EHCI_QTD_MAX_TRANS_SIZE < bytes_to_transfer
                ? EHCI_QTD_MAX_TRANS_SIZE : bytes_to_transfer;

            ptdc->bytes_to_transfer = (USHORT) data_load;
            ptd->bytes_to_transfer = (USHORT) data_load;

            data_load -= (PAGE_SIZE < data_load ? PAGE_SIZE : data_load);

            for(k = 1; data_load > 0; k++)
            {
                ptr = &purb->data_buffer[start_addr + k * PAGE_SIZE];
                ptr = (PVOID) (((ULONG) ptr) & ~(PAGE_SIZE - 1));
                ptd->hw_buf[k] = MmGetPhysicalAddress(ptr).LowPart;
                data_load -= PAGE_SIZE < data_load ? PAGE_SIZE : data_load;
            }
        }
        ptdc->data_toggle = toggle;
        if (((ptdc->bytes_to_transfer + max_packet_size - 1) / max_packet_size) & 1)
        {
            //only odd num of transactions has effect
            toggle ^= 1;
        }
        start_addr += ptdc->bytes_to_transfer;
        bytes_to_transfer -= ptdc->bytes_to_transfer;
        ListNext(td_list, pthis, pnext);
        pthis = pnext;
        i = j;
    }
    return toggle;
}

static NTSTATUS
ehci_internal_submit_bulk(PEHCI_DEV ehci, PURB purb)
//
// assume that the purb has its rest_bytes and bytes_to_transfer set
// and bytes_transfered is zeroed.
// dev_lock must be acquired outside
// purb comes from dev's endpoint purb-list. it is already removed from
// the endpoint purb-list.
//
{

    LONG max_packet_size, td_count, offset, bytes_to_transfer;
    PBYTE start_addr;
    PEHCI_QTD ptd;
    PEHCI_QH pqh;
    LIST_ENTRY td_list, *pthis, *pnext;
    BOOLEAN old_toggle, toggle, ret;
    UCHAR pid;
    LONG i, j;
    PURB_HS_PIPE_CONTENT pipe_content;
    PEHCI_QTD_CONTENT ptdc;
    PEHCI_QH_CONTENT pqhc;
    PEHCI_ELEM_LINKS pelnk;

    if (ehci == NULL || purb == NULL)
        return STATUS_INVALID_PARAMETER;

    max_packet_size = endp_max_packet_size(purb->pendp);
    if (purb->bytes_to_transfer == 0)
    {
        return STATUS_INVALID_PARAMETER;
    }

    start_addr = &purb->data_buffer[purb->data_length - purb->rest_bytes];
    calc_td_count(purb, purb->data_length - purb->rest_bytes, td_count);

    elem_pool_lock(qtd_pool, TRUE);
    pelnk = elem_pool_alloc_elems(qtd_pool, td_count);
    elem_pool_unlock(qtd_pool, TRUE);

    if (pelnk == NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }
    ptd = (PEHCI_QTD) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);

    InitializeListHead(&td_list);
    InsertTailList(&ptd->elem_head_link->elem_link, &td_list);

    ListFirst(&td_list, pthis);
    ListNext(&td_list, pthis, pnext);

    offset = 0;

    old_toggle = toggle = (purb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE) ? TRUE : FALSE;
    bytes_to_transfer = purb->bytes_to_transfer;
    ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_internal_submit_bulk():dev toggle=%d\n", toggle));

    for(i = 1; i < 16; i++)
    {
        if ((max_packet_size >> i) == 0)
            break;
    }
    i--;
    i &= 0xf;

    purb->pipe = 0;
    pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
    pipe_content->max_packet_size = i;
    pipe_content->endp_addr = endp_num(purb->pendp);
    pipe_content->dev_addr = dev_from_endp(purb->pendp)->dev_addr;
    pipe_content->trans_dir = endp_dir(purb->pendp);
    pipe_content->trans_type = USB_ENDPOINT_XFER_BULK;
    pipe_content->data_toggle = toggle;
    pipe_content->speed_high = (dev_from_endp(purb->pendp)->flags & USB_DEV_FLAG_HIGH_SPEED) ? 1 : 0;
    pipe_content->speed_low = (dev_from_endp(purb->pendp)->flags & USB_DEV_FLAG_LOW_SPEED) ? 1 : 0;

    pid = (((ULONG) purb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN) ? QTD_PID_IN : QTD_PID_OUT);

    i = ((ULONG) start_addr) & (PAGE_SIZE - 1); // header part within first page
    if (i)
    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -