uhci.c

来自「winNT技术操作系统,国外开放的原代码和LIUX一样」· C语言 代码 · 共 2,164 行 · 第 1/5 页

C
2,164
字号

    if (status != STATUS_SUCCESS || pdev == NULL)
    {
        RtlFreeUnicodeString(&dev_name);
        return NULL;
    }

    pdev_ext = pdev->DeviceExtension;
    RtlZeroMemory(pdev_ext, sizeof(DEVICE_EXTENSION) + sizeof(UHCI_DEV));

    pdev_ext->dev_ext_hdr.type = NTDEV_TYPE_HCD;
    pdev_ext->dev_ext_hdr.dispatch = uhci_dispatch_irp;
    pdev_ext->dev_ext_hdr.start_io = NULL;      //we do not support startio
    pdev_ext->dev_ext_hdr.dev_mgr = dev_mgr;

    pdev_ext->pdev_obj = pdev;
    pdev_ext->pdrvr_obj = drvr_obj;

    pdev_ext->uhci = (PUHCI_DEV) & (pdev_ext[1]);

    RtlInitString(&another_string, str_symb_name);
    RtlAnsiStringToUnicodeString(&symb_name, &another_string, TRUE);

    IoCreateSymbolicLink(&symb_name, &dev_name);

    uhci_dbg_print(DBGLVL_MAXIMUM,
                   ("uhci_create_device(): dev=0x%x\n, pdev_ext= 0x%x, uhci=0x%x, dev_mgr=0x%x\n", pdev,
                    pdev_ext, pdev_ext->uhci, dev_mgr));

    RtlFreeUnicodeString(&dev_name);
    RtlFreeUnicodeString(&symb_name);

    //register with dev_mgr though it is not initilized
    uhci_init_hcd_interface(pdev_ext->uhci);
    hcd_id = dev_mgr_register_hcd(dev_mgr, &pdev_ext->uhci->hcd_interf);

    pdev_ext->uhci->hcd_interf.hcd_set_id(&pdev_ext->uhci->hcd_interf, hcd_id);
    pdev_ext->uhci->hcd_interf.hcd_set_dev_mgr(&pdev_ext->uhci->hcd_interf, dev_mgr);
    return pdev;
}

BOOLEAN
uhci_delete_device(PDEVICE_OBJECT pdev)
{
    STRING string;
    UNICODE_STRING symb_name;
    PDEVICE_EXTENSION pdev_ext;
    CHAR str_symb_name[64];


    if (pdev == NULL)
        return FALSE;

    pdev_ext = pdev->DeviceExtension;

    sprintf(str_symb_name,
            "%s%d", DOS_DEVICE_NAME, pdev_ext->uhci->hcd_interf.hcd_get_id(&pdev_ext->uhci->hcd_interf));
    RtlInitString(&string, str_symb_name);
    RtlAnsiStringToUnicodeString(&symb_name, &string, TRUE);
    IoDeleteSymbolicLink(&symb_name);
    RtlFreeUnicodeString(&symb_name);

    if (pdev_ext->res_list)
        ExFreePool(pdev_ext->res_list); //      not allocated by usb_alloc_mem

    IoDeleteDevice(pdev);
    uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_delete_device(): device deleted\n"));
    return TRUE;
}

// we can not use endp here for it is within the dev scope, and
// we can not acquire the dev-lock, fortunately we saved some
// info in urb->pipe in uhci_internal_submit_XXX.
BOOLEAN NTAPI
uhci_isr(PKINTERRUPT interrupt, PVOID context)
{
    PUHCI_DEV uhci;
    USHORT status;
    PLIST_ENTRY pthis, pnext;
    PURB purb;

    UNREFERENCED_PARAMETER(interrupt);
    UNREFERENCED_PARAMETER(context);

    uhci_dbg_print(DBGLVL_ULTRA, ("uhci_isr(): context=0x%x\n", context));

    /*
     * Read the interrupt status, and write it back to clear the
     * interrupt cause
     */
    uhci = (PUHCI_DEV) context;
    if (uhci == NULL)
        return FALSE;

    status = READ_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS));
    if (!status)                /* shared interrupt, not mine */
        return FALSE;

    if (status != 1)
    {
        uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr():  current uhci status=0x%x\n", status));
    }
    else
    {
        uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_isr():  congratulations, no error occurs\n"));
    }

    /* clear it */
    WRITE_PORT_USHORT((PUSHORT) (uhci->port_base + USBSTS), status);

    if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD))
    {
        if (status & USBSTS_HSE)
        {
            DbgPrint("uhci_isr(): host system error, PCI problems?\n");
            //for( ; ; );
        }
        if (status & USBSTS_HCPE)
        {
            DbgPrint("uhci_isr(): host controller process error. something bad happened\n");
            //for( ; ; );
            //for( ; ; );
        }
        if ((status & USBSTS_HCH))      //&& !uhci->is_suspended
        {
            DbgPrint("uhci_isr(): host controller halted. very bad\n");
            /* FIXME: Reset the controller, fix the offending TD */
        }
    }

    // don't no how to handle it yet
    //if (status & USBSTS_RD)
    //{
    //uhci_wakeup(uhci);
    //}*/

    //let's remove those force-cancel urbs from the schedule first
    ListFirst(&uhci->urb_list, pthis);
    while (pthis)
    {
        purb = (PURB) pthis;
        if (purb->flags & URB_FLAG_FORCE_CANCEL)
        {
            uhci_remove_urb_from_schedule(uhci, purb);
        }
        ListNext(&uhci->urb_list, pthis, pnext);
        pthis = pnext;
    }

    //clear the interrupt if the urb is force canceled
    uhci->skel_term_td->status &= ~TD_CTRL_IOC;

    //next we need to find if anything fininshed
    ListFirst(&uhci->urb_list, pthis);
    while (pthis)
    {
        purb = (PURB) pthis;
        if (purb->flags & URB_FLAG_IN_SCHEDULE)
        {
            if (uhci_is_xfer_finished(purb))
                uhci_remove_urb_from_schedule(uhci, purb);
        }
        ListNext(&uhci->urb_list, pthis, pnext);
        pthis = pnext;
    }

    KeInsertQueueDpc(&uhci->pdev_ext->uhci_dpc, uhci, 0);
    return TRUE;
}

BOOLEAN NTAPI
uhci_cal_cpu_freq(PVOID context)
{
    UNREFERENCED_PARAMETER(context);

    usb_cal_cpu_freq();
    return TRUE;
}

PDEVICE_OBJECT
uhci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr)
{
    LONG bus, i, j, ret = 0;
    PCI_SLOT_NUMBER slot_num;
    PPCI_COMMON_CONFIG pci_config;
    PDEVICE_OBJECT pdev;
    BYTE buffer[sizeof(PCI_COMMON_CONFIG)];
    LONG count;
    PDEVICE_EXTENSION pdev_ext;

    slot_num.u.AsULONG = 0;
    pci_config = (PPCI_COMMON_CONFIG) buffer;
    count = 0;
    pdev = NULL;

    //scan the bus to find uhci controller
    for(bus = 0; bus < 2; bus++)        /*enum only bus0 and bus1 */
    {
        for(i = 0; i < PCI_MAX_DEVICES; i++)
        {
            slot_num.u.bits.DeviceNumber = i;
            for(j = 0; j < PCI_MAX_FUNCTIONS; j++)
            {
                slot_num.u.bits.FunctionNumber = j;

                ret = HalGetBusData(PCIConfiguration,
                                    bus, slot_num.u.AsULONG, pci_config, PCI_COMMON_HDR_LENGTH);

                if (ret == 0)   /*no this bus */
                    break;

                if (ret == 2)   /*no device on the slot */
                    break;

                if (pci_config->BaseClass == 0x0c && pci_config->SubClass == 0x03)
                {
                    // well, we find our usb host controller, create device
#ifdef _MULTI_UHCI
                    {
                        pdev = uhci_alloc(drvr_obj, reg_path, ((bus << 8) | (i << 3) | j), dev_mgr);
                        count++;
                        if (!pdev)
                            return NULL;
                    }
#else
                    pdev = uhci_alloc(drvr_obj, reg_path, ((bus << 8) | (i << 3) | j), dev_mgr);
                    if (pdev)
                        goto LBL_LOOPOUT;
#endif
                }
            }
            if (ret == 0)
                break;
        }
    }

LBL_LOOPOUT:
    if (pdev)
    {
        pdev_ext = pdev->DeviceExtension;
        if (pdev_ext)
        {
            // acquire higher irql to eliminate pre-empty
            KeSynchronizeExecution(pdev_ext->uhci_int, uhci_cal_cpu_freq, NULL);
        }
    }
    return NULL;
}

PDEVICE_OBJECT
uhci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr)
{
    LONG frd_num, prd_num;
    PDEVICE_OBJECT pdev;
    PDEVICE_EXTENSION pdev_ext;
    ULONG vector, addr_space;
    LONG bus;
    KIRQL irql;
    KAFFINITY affinity;

    DEVICE_DESCRIPTION dev_desc;
    CM_PARTIAL_RESOURCE_DESCRIPTOR *pprd;
    PCI_SLOT_NUMBER slot_num;
    NTSTATUS status;


    pdev = uhci_create_device(drvr_obj, dev_mgr);
    pdev_ext = pdev->DeviceExtension;

    pdev_ext->pci_addr = bus_addr;
    bus = (bus_addr >> 8);

    slot_num.u.AsULONG = 0;
    slot_num.u.bits.DeviceNumber = ((bus_addr & 0xff) >> 3);
    slot_num.u.bits.FunctionNumber = (bus_addr & 0x07);

    if (pdev == NULL)
        return pdev;

    //now create adapter object
    RtlZeroMemory(&dev_desc, sizeof(dev_desc));

    dev_desc.Version = DEVICE_DESCRIPTION_VERSION;
    dev_desc.Master = TRUE;
    dev_desc.ScatterGather = TRUE;
    dev_desc.Dma32BitAddresses = TRUE;
    dev_desc.BusNumber = bus;
    dev_desc.InterfaceType = PCIBus;
    dev_desc.MaximumLength =
        UHCI_MAX_POOL_TDS * sizeof(UHCI_TD) * UHCI_MAX_TD_POOLS
        + sizeof(UHCI_QH) * UHCI_MAX_POOL_QHS + sizeof(ULONG) * UHCI_MAX_FRAMES;

    pdev_ext->map_regs = 2;     // UHCI_MAX_TD_POOLS +
    //+ BYTES_TO_PAGES( ( UHCI_MAX_POOL_TDS * 64 ) * UHCI_MAX_TD_POOLS ) ;

    pdev_ext->padapter = HalGetAdapter(&dev_desc, &pdev_ext->map_regs);

    uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_alloc(): padapter=0x%x\n", pdev_ext->padapter));
    if (pdev_ext->padapter == NULL)
    {
        //fatal error
        uhci_delete_device(pdev);
        return NULL;
    }

    DbgPrint("uhci_alloc(): reg_path=%p, \n \
             uhci_alloc(): PCIBus=0x%x, bus=0x%x, bus_addr=0x%x \n \
             uhci_alloc(): slot_num=0x%x, &res_list=%p \n", reg_path, (DWORD) PCIBus, (DWORD) bus,
             (DWORD) bus_addr, (DWORD) slot_num.u.AsULONG, & pdev_ext->res_list);

    //let's allocate resources for this device
    DbgPrint("uhci_alloc(): about to assign slot res\n");
    if ((status = HalAssignSlotResources(reg_path, NULL,        //no class name yet
                                         drvr_obj, NULL,        //no support of another uhci controller
                                         PCIBus,
                                         bus, slot_num.u.AsULONG, &pdev_ext->res_list)) != STATUS_SUCCESS)
    {
        DbgPrint("uhci_alloc(): error assign slot res, 0x%x\n", status);
        release_adapter(pdev_ext->padapter);
        pdev_ext->padapter = NULL;
        uhci_delete_device(pdev);
        return NULL;
    }

    //parse the resource list
    for(frd_num = 0; frd_num < (LONG) pdev_ext->res_list->Count; frd_num++)
    {
        for(prd_num = 0; prd_num < (LONG) pdev_ext->res_list->List[frd_num].PartialResourceList.Count;
            prd_num++)
        {
            pprd = &pdev_ext->res_list->List[frd_num].PartialResourceList.PartialDescriptors[prd_num];
            if (pprd->Type == CmResourceTypePort)
            {
                RtlCopyMemory(&pdev_ext->res_port, &pprd->u.Port, sizeof(pprd->u.Port));
            }
            else if (pprd->Type == CmResourceTypeInterrupt)
            {
                RtlCopyMemory(&pdev_ext->res_interrupt, &pprd->u.Interrupt, sizeof(pprd->u.Interrupt));
            }
        }
    }

    //for port, translate them to system address
    addr_space = 1;
    if (HalTranslateBusAddress(PCIBus, bus, pdev_ext->res_port.Start, &addr_space,      //io space
                               &pdev_ext->uhci->uhci_reg_base) != (BOOLEAN) TRUE)
    {
        DbgPrint("uhci_alloc(): error, can not translate bus address\n");
        release_adapter(pdev_ext->padapter);
        pdev_ext->padapter = NULL;
        uhci_delete_device(pdev);
        return NULL;
    }

    DbgPrint("uhci_alloc(): address space=0x%x\n, reg_base=0x%x\n",
             addr_space, pdev_ext->uhci->uhci_reg_base.u.LowPart);

    if (addr_space == 0)
    {
        //port has been mapped to memory space  
        pdev_ext->uhci->port_mapped = TRUE;
        pdev_ext->uhci->port_base = (PBYTE) MmMapIoSpace(pdev_ext->uhci->uhci_reg_base,
                                                         pdev_ext->res_port.Length, FALSE);

        //fatal error can not map the registers 
        if (pdev_ext->uhci->port_base == NULL)
        {
            release_adapter(pdev_ext->padapter);
            pdev_ext->padapter = NULL;
            uhci_delete_device(pdev);
            return NULL;
        }
    }
    else
    {
        //io space
        pdev_ext->uhci->port_mapped = FALSE;
        pdev_ext->uhci->port_base = (PBYTE) pdev_ext->uhci->uhci_reg_base.LowPart;
    }

    //before we connect the interrupt, we have to init uhci
    pdev_ext->uhci->fsbr_cnt = 0;
    pdev_ext->uhci->pdev_ext = pdev_ext;

    if (uhci_init_schedule(pdev_ext->uhci, pdev_ext->padapter) == FALSE)
    {
        release_adapter(pdev_ext->padapter);
        pdev_ext->padapter = NULL;
        uhci_delete_device(pdev);
        return NULL;
    }

    InitializeListHead(&pdev_ext->uhci->urb_list);
    KeInitializeSpinLock(&pdev_ext->uhci->pending_endp_list_lock);
    InitializeListHead(&pdev_ext->uhci->pending_endp_list);

    uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_alloc(): pending_endp_list=0x%x\n",
                                    &pdev_ext->uhci->pending_endp_list));

    init_pending_endp_pool(&pdev_ext->uhci->pending_endp_pool);
    KeInitializeTimer(&pdev_ext->uhci->reset_timer);

    vector = HalGetInterruptVector(PCIBus,
                                   bus,
                                   pdev_ext->res_interrupt.level,
                                   pdev_ext->res_interrupt.vector,
                                   &irql,
                                   &affinity);

    //connect the interrupt
    DbgPrint("uhci_alloc(): the int=0x%x\n", vector);
    if (IoConnectInterrupt(&pdev_ext->uhci_int,
                           uhci_isr,
                           pdev_ext->uhci,
                           NULL, //&pdev_ext->uhci->frame_list_lock,
                           vector,
                           irql,
                           irql,
                           LevelSensitive,
                           TRUE,    //share the vector
                           affinity,
                           FALSE)     //No float save
        != STATUS_SUCCESS)
    {
        uhci_release(pdev);
        return NULL;
    }

    KeInitializeDpc(&pdev_ext->uhci_dpc, uhci_dpc_callback, (PVOID) pdev_ext->uhci);

    return pdev;
}

⌨️ 快捷键说明

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