高通msm8x60 boot(lk)的usb处理解析流程

来源:互联网 发布:公安部上牌数据 编辑:程序博客网 时间:2024/05/17 07:57
 高通msm8x60 boot(lk)的usb处理解析流程 2012-11-22 12:40:36

分类: LINUX

//分析高通平台裸机的usb处理流程
APP_START(aboot)
    .init = aboot_init,//启动入口
    APP_END

void aboot_init(const struct app_descriptor *app)
{
    unsigned usb_init = 0;
     ........  

fastboot:  

    if(!usb_init)
        udc_init(&surf_udc_device);//初始化udc控制器

    fastboot_register("boot", cmd_boot);
    ...........
    sz = target_get_max_flash_size();
    fastboot_init(target_get_scratch_address(), sz);
    udc_start();//使能udc
    target_battery_charging_enable(1, 0);
}

//设备描述符信息,临时记录
static struct udc_device surf_udc_device = {
    .vendor_id    = 0x18d1,
    .product_id    = 0xD00D,
    .version_id    = 0x0100,
    .manufacturer    = "Google",
    .product    = "Android",
    .serialno    = PRODUCT_NAME 
};

int udc_init(struct udc_device *dev) 
{
    ............

    epts = memalign(4096, 4096);//分配一页的传输内存空间,并且一页对齐

    dprintf(INFO, "USB init ept @ %p\n", epts);
    memset(epts, 0, 32 * sizeof(struct ept_queue_head));//重置每个端点的内存空间

    ...........
       
    /*RESET 控制器*/
    writel(0x00080002, USB_USBCMD);

    ...........

    //The USB_OTG_HS_ASYNCLISTADDR register is the next asynchronous list address register.
    //This 32-bit register contains the address of the next asynchronous queue head to be executed by
    //the host.
    writel((unsigned) epts, USB_ENDPOINTLISTADDR);//把传输内存告诉硬件控制器

        /* 设置usb的模式为设备控制器模式*/
    writel(0x02, USB_USBMODE);

    //Setting a bit (1) will cause the associated endpoint to clear any
    //primed buffers. If a packet is in progress for one of the
    //associated endpoints, that transfer will continue until
    //completion. The hardware will clear this register after the
    //endpoint flush operation is successful.

    writel(0xffffffff, USB_ENDPTFLUSH);

    ................

    //分配ep0的in、out端点,并赋值给全局变量,该函数的实现在下面分析(1)
    ep0out = _udc_endpoint_alloc(0, 0, 64);
    ep0in = _udc_endpoint_alloc(0, 1, 64);

    //分配ep0的传输结构体,并赋值给全局变量,该函数的实现在下面分析(2)
    ep0req = udc_request_alloc();
    
    //分配ep0传输用 buffer
    ep0req->buf = malloc(4096);

    {
        //分配一个描述符,并注册
        struct udc_descriptor *desc = udc_descriptor_alloc(TYPE_STRING, 0, 4);

        //0x0409 is US English
        desc->data[2] = 0x09;
        desc->data[3] = 0x04;

        //注册该描述符,挂到全局链表上
        udc_descriptor_register(desc);
            /****************************************************************/
            //注册描述符的实现如下
            static struct udc_descriptor *desc_list = 0;//描述符全局链表

            void udc_descriptor_register(struct udc_descriptor *desc)
            {
                desc->next = desc_list;
                desc_list = desc;
            }
            /***************************************************************/
    }
    
    the_device = dev;//保存上面的surf_udc_device到全局变量
    return 0;
}

//分配端点实现分析

//全局变量指针
struct udc_endpoint *ept_list = 0;
struct ept_queue_head *epts = 0;

//端点结构体定义
/*******************************************************************************************/
struct udc_endpoint
{
    struct udc_endpoint *next;//链接到全局链表ept_list的端点
    unsigned bit;//表明是第几个端点1..32
    struct ept_queue_head *head;//挂接item的head链表
    struct usb_request *req;//usb传输用的请求
    unsigned char num;//端点号
    unsigned char in;//端点的传输方向
    unsigned short maxpkt;//最大传输包大小
};

struct usb_request {
    struct udc_request req;
    struct ept_queue_item *item;//挂到端点head链表的item
};

/* USB Device Controller Transfer Request */
struct udc_request {
    void *buf;
    unsigned length;
    void (*complete)(struct udc_request *req, unsigned actual, int status);
    void *context;
};

//ept_queue_head结构体:
struct ept_queue_head 
{
    unsigned config;//挂载端点的配置
    unsigned current; /* read-only */

    unsigned next;//该变量挂接item
    unsigned info;
    unsigned page0;
    unsigned page1;
    unsigned page2;
    unsigned page3;
    unsigned page4;
    unsigned reserved_0;
    
    unsigned char setup_data[8];
    
    unsigned reserved_1;
    unsigned reserved_2;
    unsigned reserved_3;
    unsigned reserved_4;
};

//item结构体
struct ept_queue_item
{
    unsigned next;
    unsigned info;//挂载item配置
    unsigned page0;
    unsigned page1;
    unsigned page2;
    unsigned page3;
    unsigned page4;
    unsigned reserved;
};
/*******************************************************************************************/

struct udc_endpoint *_udc_endpoint_alloc(unsigned num, unsigned in, unsigned max_pkt)//上接上面的(1)
{
    struct udc_endpoint *ept;
    unsigned cfg;

    ept = malloc(sizeof(*ept));//分配一个端点
 
    ept->maxpkt = max_pkt;//最大传输包大小
    ept->num = num;//端点号
    ept->in = !!in;//端点的传输方向
    ept->req = 0;

    //配置用到的宏
    //#define CONFIG_MAX_PKT(n)     ((n) << 16)
    //#define CONFIG_ZLT            (1 << 29)    /* stop on zero-len xfer */
    //#define CONFIG_IOS            (1 << 15)    /* IRQ on setup */
    cfg = CONFIG_MAX_PKT(max_pkt) | CONFIG_ZLT;//初始化配置,最终会挂到head下的config上

    if(ept->in) {//根据端点方向和端点号,置端点的bit位,记录端点号1...32
        ept->bit = EPT_TX(ept->num);
    } else {
        ept->bit = EPT_RX(ept->num);
        if(num == 0) 
            cfg |= CONFIG_IOS;//继续初始化配置
    }

    ept->head = epts + (num * 2) + (ept->in);//为该端点的head找到合适的空间,空间排列为out1,in1,out2,in2
    ept->head->config = cfg;//把上面初始化好的配置挂到head的config下

    //把该端点挂到全局链表上
    ept->next = ept_list;
    ept_list = ept;
    
    DBG("ept%d %s @%p/%p max=%d bit=%x\n", num, in ? "in":"out", ept, ept->head, max_pkt, ept->bit);

    return ept;
}

struct udc_request *udc_request_alloc(void)//上接上面的(2)
{
    struct usb_request *req;
    req = malloc(sizeof(*req));//分配一个req
    req->req.buf = 0;//初始化为null
    req->req.length = 0;//长度初始化为0
    req->item = memalign(32, 32);//为item分配空间

    return &req->req;//返回req
}

//上面两个函数分配后赋值如下
static struct udc_endpoint *ep0in, *ep0out;
static struct udc_request *ep0req;

//描述符的类型
#define TYPE_DEVICE          1
#define TYPE_CONFIGURATION   2
#define TYPE_STRING          3
#define TYPE_INTERFACE       4
#define TYPE_ENDPOINT        5

//描述符结构体
struct udc_descriptor {
    struct udc_descriptor *next;
    unsigned short tag; /* ((TYPE << 8) | NUM) */
    unsigned short len; /* total length */
    unsigned char data[0];//存放真正的usb描述符
};

//描述符分配函数的实现,type为描述符的类型 ,num为描述符的id编号,len为描述符的长度
struct udc_descriptor *udc_descriptor_alloc(unsigned type, unsigned num, unsigned len)
{
    struct udc_descriptor *desc;
    if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
        return 0;

    if(!(desc = malloc(sizeof(struct udc_descriptor) + len)))//分配一个描述符
        return 0;

    //初始化描述符
    desc->next = 0;
    desc->tag = (type << 8) | num;//描述符的种类和索引,对应spec
    desc->len = len;//描述符的长度
    desc->data[0] = len;
    desc->data[1] = type;

    return desc;
}

/*************************************************************************************************************/
//usb gadget的初始化
//结构体定义
struct udc_gadget {
    void (*notify)(struct udc_gadget *gadget, unsigned event);
    void *context;

    unsigned char ifc_class;
    unsigned char ifc_subclass;
    unsigned char ifc_protocol;
    unsigned char ifc_endpoints;
    const char *ifc_string;
    unsigned flags;

    struct udc_endpoint **ept;
};

static struct udc_endpoint *fastboot_endpoints[2];

static struct udc_gadget fastboot_gadget = {
    .notify    = fastboot_notify,
    .ifc_class    = 0xff,
    .ifc_subclass    = 0x42,
    .ifc_protocol    = 0x03,
    .ifc_endpoints= 2,
    .ifc_string    = "fastboot",
    .ept        = fastboot_endpoints,//该gadget所用的端点
};


static void *download_base;
static unsigned download_max;
static unsigned download_size;

int fastboot_init(void *base, unsigned size)
{
    thread_t *thr;
    dprintf(INFO, "fastboot_init()\n");

    download_base = base;//从pc端得到系统数据要放的区域的起始位置
    download_max = size;//该区域的大小

    ...............

    //分配bulk in/bulk out端点,其实现的在下面进行分析(3)
    in = udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512);
    if (!in)
        goto fail_alloc_in;
    out = udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512);
    if (!out)
        goto fail_alloc_out;

    //挂到端点数组上
    fastboot_endpoints[0] = in;
    fastboot_endpoints[1] = out;

    req = udc_request_alloc();//分配udc_req请求结构体
    if (!req)
        goto fail_alloc_req;

    if (udc_register_gadget(&fastboot_gadget))//注册gadget,实现分析在下面的(4)
        goto fail_udc_register;

    .....................

    fastboot_register("download:", cmd_download);//fastboot的下载命令注册

    ....................

    thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);//创建命令处理线程
    thread_resume(thr);//运行该线程
    return 0;
}

//bulk端点分配
static unsigned ept_alloc_table = EPT_TX(0) | EPT_RX(0);//端点分配表
struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt)//上接上面的(3)
{
    struct udc_endpoint *ept;
    unsigned n;
    unsigned in;

    if (type == UDC_TYPE_BULK_IN) {
        in = 1;
    } else if (type == UDC_TYPE_BULK_OUT) {
        in = 0;
    } else {
        return 0;
    }

    for (n = 1; n < 16; n++) {//找到一个没有使用的端点
        unsigned bit = in ? EPT_TX(n) : EPT_RX(n);
        if (ept_alloc_table & bit)
            continue;
        ept = _udc_endpoint_alloc(n, in, maxpkt);//分配该端点
        if (ept)
            ept_alloc_table |= bit;//标识该端点已被分配
        return ept;
    }
    return 0;
}

int udc_register_gadget(struct udc_gadget *gadget)//上接上面的(4)
{
    if (the_gadget) {
        dprintf(CRITICAL, "only one gadget supported\n");
        return -1;
    }
    the_gadget = gadget;
    return 0;
}
/*************************************************************************************/
//线程处理函数
static int fastboot_handler(void *arg)
{
    for (;;) {
        event_wait(&usb_online);
        fastboot_command_loop();//处理命令循环
    }
    return 0;
}

static void fastboot_command_loop(void)
{
    struct fastboot_cmd *cmd;
    int r;
    dprintf(INFO,"fastboot: processing commands\n");

again:
    while (fastboot_state != STATE_ERROR) {
        r = usb_read(buffer, 64);//读取pc端发来的命令,并放到buffer中,具体实现分析接下面(5).static unsigned char buffer[4096];
        if (r < 0) break;
        buffer[r] = 0;//buffer结尾赋值为0
        dprintf(INFO,"fastboot: %s\n", buffer);

        for (cmd = cmdlist; cmd; cmd = cmd->next) {//循环遍历注册的cmd
            if (memcmp(buffer, cmd->prefix, cmd->prefix_len))//比较是否和pc端发过来的命令一样?
                continue;
            fastboot_state = STATE_COMMAND;//比较成功
            cmd->handle((const char*) buffer + cmd->prefix_len, (void*) download_base, download_size);//调用该命令的处理函数
            if (fastboot_state == STATE_COMMAND)
                fastboot_fail("unknown reason");
            goto again;
        }

        fastboot_fail("unknown command");
            
    }
    fastboot_state = STATE_OFFLINE;
    dprintf(INFO,"fastboot: oops!\n");
}

//首先分析,读取pc端发过来的数据过程
static int usb_read(void *_buf, unsigned len)//上接上面(5)
{
    int r;
    unsigned xfer;
    unsigned char *buf = _buf;
    int count = 0

    while (len > 0) {
        xfer = (len > 4096) ? 4096 : len;//传输的长度大小是否大于一页?
        req->buf = buf;//请求的buf
        req->length = xfer;//请求的大小
        req->complete = req_complete;//传输完成后的回调函数
            /***************************************************************************************/
            //回调函数的实现如下
            static void req_complete(struct udc_request *req, unsigned actual, int status)
            {
                txn_status = status;//传输的状态
                req->length = actual;//实际读到的长度
                event_signal(&txn_done, 0);//唤醒
            }
            /**************************************************************************************/

        r = udc_request_queue(out, req);//具体实现在下面(6)
        if (r < 0) {
            dprintf(INFO, "usb_read() queue failed\n");
            goto oops;
        }
        event_wait(&txn_done);//等待完成

        if (txn_status < 0) {
            dprintf(INFO, "usb_read() transaction failed\n");
            goto oops;
        }

        count += req->length;//实际读到的长度
        buf += req->length;
        len -= req->length;//剩余数据的大小

        /* short transfer? */
        if (req->length != xfer) break;
    }

    return count;
}

int udc_request_queue(struct udc_endpoint *ept, struct udc_request *_req)//上接上面的(6)
{
    struct usb_request *req = (struct usb_request *) _req;
    struct ept_queue_item *item = req->item;
    unsigned phys = (unsigned) req->req.buf;//传输的地址
    
    item->next = TERMINATE;
    item->info = INFO_BYTES(req->req.length) | INFO_IOC | INFO_ACTIVE;
    item->page0 = phys;
    item->page1 = (phys & 0xfffff000) + 0x1000;

    enter_critical_section();
    ept->head->next = (unsigned) item;//把该item挂到next下
    ept->head->info = 0;
    ept->req = req;

    DBG("ept%d %s queue req=%p\n", ept->num, ept->in ? "in" : "out", req);

    writel(ept->bit, USB_ENDPTPRIME);//开始进行数据处理
    exit_critical_section();
    return 0;
}

//启动udc控制器
int udc_start(void)
{
    struct udc_descriptor *desc;
    unsigned char *data;
    unsigned size;

    dprintf(ALWAYS, "udc_start()\n");

    if (!the_device) {
        dprintf(CRITICAL, "udc cannot start before init\n");
        return -1;
    }
    if (!the_gadget) {
        dprintf(CRITICAL, "udc has no gadget registered\n");
        return -1;
    }

    /* 创建设备描述符 */
    desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18);//分配设备描述符
    data = desc->data;
    data[2] = 0x00; /* usb spec minor rev */
    data[3] = 0x02; /* usb spec major rev */
    data[4] = 0x00; /* class */
    data[5] = 0x00; /* subclass */
    data[6] = 0x00; /* protocol */
    data[7] = 0x40; /* max packet size on ept 0 */
    memcpy(data + 8, &the_device->vendor_id, sizeof(short));
    memcpy(data + 10, &the_device->product_id, sizeof(short));
    memcpy(data + 12, &the_device->version_id, sizeof(short));
    data[14] = udc_string_desc_alloc(the_device->manufacturer);
    data[15] = udc_string_desc_alloc(the_device->product);
    data[16] = udc_string_desc_alloc(the_device->serialno);
    data[17] = 1; /* number of configurations */
    udc_descriptor_register(desc);//注册描述符

    /* 创建配置描述符 */
    size = 9 + udc_ifc_desc_size(the_gadget);//9是配置描述符的大小
    desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size);
    data = desc->data;
    data[0] = 0x09;//大小要重新配置为9
    data[2] = size;//配置描述符的总大小
    data[3] = size >> 8;
    data[4] = 0x01; /* number of interfaces,一个接口 */
    data[5] = 0x01; /* configuration value ,该配置的值*/
    data[6] = 0x00; /* configuration string */
    data[7] = 0x80; /* attributes */
    data[8] = 0x80; /* max power (250ma) -- todo fix this */
    udc_ifc_desc_fill(the_gadget, data + 9);//填充接口和端点描述符
    udc_descriptor_register(desc);//注册该描述符

    register_int_handler(INT_USB_HS, udc_interrupt, (void*) 0);//注册中断处理函数
    writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR);//使能对应的中断掩码
    unmask_interrupt(INT_USB_HS);//使能总的中断

        /* go to RUN mode (D+ pullup enable) */
    writel(0x00080001, USB_USBCMD);//启动控制器,该寄存器的最后一位控制停止,启动

    return 0;
}

//针对上面的函数进行分析
static struct udc_descriptor *desc_list = 0;
static unsigned next_string_id = 1;

void udc_descriptor_register(struct udc_descriptor *desc)
{
    desc->next = desc_list;
    desc_list = desc;
}

unsigned udc_string_desc_alloc(const char *str)
{
    unsigned len;
    struct udc_descriptor *desc;
    unsigned char *data;

    if (next_string_id > 255)//id大于255,则失败
        return 0;

    if (!str)//字符串为0,失败
        return 0;

    len = strlen(str);//取出字符串的长度
    desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
    if (!desc)
        return 0;
    next_string_id++;

    /* expand ascii string to utf16 */
    data = desc->data + 2;
    while (len-- > 0) {
        *data++ = *str++;
        *data++ = 0;
    }

    udc_descriptor_register(desc);//注册该描述符挂到全局链表上
    return desc->tag & 0xff;
}

//创建配置描述符的分析
static unsigned udc_ifc_desc_size(struct udc_gadget *g)
{
    return 9 + g->ifc_endpoints * 7;//gadget的是两个端点,每个端点需要7个字节,9是接口描述符的大小
}

//填充接口描述符
static void udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data)
{
    unsigned n;

    data[0] = 0x09;
    data[1] = TYPE_INTERFACE;
    data[2] = 0x00; /* ifc number ,接口号*/
    data[3] = 0x00; /* alt number ,可选设置*/
    data[4] = g->ifc_endpoints;//取出gadget的描述符
    data[5] = g->ifc_class;
    data[6] = g->ifc_subclass;
    data[7] = g->ifc_protocol;
    data[8] = udc_string_desc_alloc(g->ifc_string);

    data += 9;
    for (n = 0; n < g->ifc_endpoints; n++) {
        udc_ept_desc_fill(g->ept[n], data);
        data += 7;
    }
}

//填充端点描述符
static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data)
{
    data[0] = 7;
    data[1] = TYPE_ENDPOINT;
    data[2] = ept->num | (ept->in ? 0x80 : 0x00);
    data[3] = 0x02; /* bulk -- the only kind we support */
    data[4] = ept->maxpkt;
    data[5] = ept->maxpkt >> 8;
    data[6] = ept->in ? 0x00 : 0x01;
}
//usb中的中断处理
enum handler_return udc_interrupt(void *arg)
{
    struct udc_endpoint *ept;
    unsigned ret = INT_NO_RESCHEDULE;
    unsigned n = readl(USB_USBSTS);
    writel(n, USB_USBSTS);
    
    n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);

    if (n == 0)
        return ret;

    if (n & STS_URI) {//reset处理
        writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
        writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
        writel(0xffffffff, USB_ENDPTFLUSH);
        writel(0, USB_ENDPTCTRL(1));
        DBG1("-- reset --\n");
        usb_online = 0;
        usb_config_value = 0;
        the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);

        /* error out any pending reqs */
        for (ept = ept_list; ept; ept = ept->next) {
            /* ensure that ept_complete considers
             * this to be an error state
             */
            if (ept->req) {
                ept->req->item->info = INFO_HALTED;
                handle_ept_complete(ept);//处理完成后调用函数
            }
        }
        usb_status(0, usb_highspeed);
    }
    if (n & STS_SLI) {
        DBG1("-- suspend --\n");
    }
    if (n & STS_PCI) {
        DBG1("-- portchange --\n");
        unsigned spd = (readl(USB_PORTSC) >> 26) & 3;//从端口寄存器中取出速度
        if(spd == 2) {
            usb_highspeed = 1;
        } else {
            usb_highspeed = 0;
        }
    }
    if (n & STS_UEI) {
        dprintf(INFO, "<UEI %x>\n", readl(USB_ENDPTCOMPLETE));
    }

    if ((n & STS_UI) || (n & STS_UEI)) {
        /*Set-up endpoint status
        For every set-up transaction that is received, a corresponding
        bit in this register is set (1). The software must clear or
        acknowledge the setup transfer by setting (1) a respective bit
        after it has read the setup data from the queue head. 接收状态寄存器0-15
        */
        n = readl(USB_ENDPTSETUPSTAT);
        if (n & EPT_RX(0)) {//0端点接收到数据
            handle_setup(ep0out);//处理枚举过程
            ret = INT_RESCHEDULE;
        }

        /*Description Endpoint receive complete event
        Each bit indicates that a received event (OUT/SETUP)
        occurred and the software should read the corresponding
        endpoint queue to determine the transfer status. If the
        corresponding IOC bit is set (1) in the transfer descriptor, then
        this bit will be set (1) simultaneously with the USBINT. Writing a
        one will clear the corresponding bit in this registe,接收,发送完成状态寄存器
        */
        n = readl(USB_ENDPTCOMPLETE);//接受到一个完成事件
        if (n != 0) {
            writel(n, USB_ENDPTCOMPLETE);//清除该事件
        }

        for (ept = ept_list; ept; ept = ept->next){
            if (n & ept->bit) {//判断第多少位产生的
                handle_ept_complete(ept);//调用相应endpoint的完成函数
                ret = INT_RESCHEDULE;
            }
        }
    }
    return ret;
}

static void handle_ept_complete(struct udc_endpoint *ept)
{
    struct ept_queue_item *item;
    unsigned actual;
    int status;
    struct usb_request *req;
    
    DBG("ept%d %s complete req=%p\n",
            ept->num, ept->in ? "in" : "out", ept->req);
    
    req = ept->req;
    if(req) {
        ept->req = 0;
        item = req->item;//返回的item
        while (readl(&(item->info)) & INFO_ACTIVE) ;//等待active位清零
        
        if(item->info & 0xff) {//如果最低八位不为0,则有错误出现
            actual = 0;
            status = -1;
            dprintf(INFO, "EP%d/%s FAIL nfo=%x pg0=%x\n",
                ept->num, ept->in ? "in" : "out", item->info, item->page0);
        } else {//否则计算实际传输的长度
            actual = req->req.length - ((item->info >> 16) & 0x7fff);//取出没有传输的长度
            status = 0;//状态为0
        }
        if(req->req.complete)//调用该端点req的回调函数
            req->req.complete(&req->req, actual, status);
    }
}

//下面看处理枚举的过程
//标准设备请求的setup_packet结构体定义
struct setup_packet {
    unsigned char type;
    unsigned char request;
    unsigned short value;
    unsigned short index;
    unsigned short length;
} __attribute__ ((packed));

//type
请求特征:
D7: 传输方向;0=主机至设备,1=设备至主机
D6..5: 种类;0=标准,1=类,2=厂商,3=保留
D4..0: 接受者;0=设备,1=接口,2=端点,3=其他,4..31=保留

//request
GET_STATUS
GET_CONFIGURATION 
GET_DESCRIPTOR
SET_CONFIGURATION
SET_ADDRESS
SET_INTERFACE
SET_FEATURE
CLEAR_FEATURE

static void handle_setup(struct udc_endpoint *ept)
{
    struct setup_packet s;
    
    memcpy(&s, ept->head->setup_data, sizeof(s));//把该端点的枚举命令给拷贝出来
    writel(ept->bit, USB_ENDPTSETUPSTAT);//清除该状态位

    switch (SETUP(s.type,s.request)) {
    case SETUP(DEVICE_READ, GET_STATUS): {
        unsigned zero = 0;
        if (s.length == 2) {
            setup_tx(&zero, 2);
                /*********************************************/
                static void ep0in_complete(struct udc_request *req, unsigned actual, int status)
                {
                    DBG("ep0in_complete %p %d %d\n", req, actual, status);
                    if(status == 0) {
                        req->length = 0;
                        req->complete = 0;
                        udc_request_queue(ep0out, req);//发一个0长度的包表示结束
                    }
                }

                static void setup_tx(void *buf, unsigned len)
                {
                    DBG("setup_tx %p %d\n", buf, len);
                    memcpy(ep0req->buf, buf, len);//返回状态值为0
                    ep0req->complete = ep0in_complete;
                    ep0req->length = len;
                    udc_request_queue(ep0in, ep0req);
                }
                /**************************************************/
            return;
        }
        break;
    }
    case SETUP(DEVICE_READ, GET_DESCRIPTOR): {//获取描述符,所有的描述符都在该函数中处理
        struct udc_descriptor *desc;
        /* usb_highspeed? */
        for (desc = desc_list; desc; desc = desc->next) {
            if (desc->tag == s.value) {//种类和索引
                unsigned len = desc->len;
                if (len > s.length) len = s.length;//如果请求的长度大于描述符的长度,则用描述符的长度赋值给请求的长度
                setup_tx(desc->data, len);//发送该描述符到pc端
                return;
            }
        }
        break;
    }
    case SETUP(DEVICE_READ, GET_CONFIGURATION)://返回当前设备配置值,如果为0表示还没配置
        /* disabling this causes data transaction failures on OSX. Why? */
        if ((s.value == 0) && (s.index == 0) && (s.length == 1)) {
            setup_tx(&usb_config_value, 1);//初始值为static unsigned char usb_config_value = 0;
            return;
        }
        break;
    case SETUP(DEVICE_WRITE, SET_CONFIGURATION)://设置配置值
        if (s.value == 1) {//设置配置1
            struct udc_endpoint *ept;
            /* enable endpoints */
            for (ept = ept_list; ept; ept = ept->next){//使能除0端点外的所有端点
                if (ept->num == 0) 
                    continue;
                endpoint_enable(ept, s.value);//使能端点
            }
            usb_config_value = 1;//设置值为1
            the_gadget->notify(the_gadget, UDC_EVENT_ONLINE);//通知在线
        } else {
            writel(0, USB_ENDPTCTRL(1));
            usb_config_value = 0;
            the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
        }
        setup_ack();
        usb_online = s.value ? 1 : 0;
        usb_status(s.value ? 1 : 0, usb_highspeed);
        return;
    case SETUP(DEVICE_WRITE, SET_ADDRESS)://设置地址
        /* write address delayed (will take effect
        ** after the next IN txn)
        */
        writel((s.value << 25) | (1 << 24), USB_DEVICEADDR);
        setup_ack();//返回0数据包
        return;
    case SETUP(INTERFACE_WRITE, SET_INTERFACE):
        /* if we ack this everything hangs */
        /* per spec, STALL is valid if there is not alt func */
        goto stall;
    case SETUP(DEVICE_WRITE, SET_FEATURE):
        setup_ack();
        /* TODO: Use s.value and fix byte ordering */
        set_test_mode(s.index);
        return;
    case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE): {
        struct udc_endpoint *ept;
        unsigned num = s.index & 15;
        unsigned in = !!(s.index & 0x80);
        
        if ((s.value == 0) && (s.length == 0)) {
            DBG("clr feat %d %d\n", num, in);
            for (ept = ept_list; ept; ept = ept->next) {
                if ((ept->num == num) && (ept->in == in)) {
                    endpoint_enable(ept, 1);
                    setup_ack();
                    return;
                }
            }
        }
        break;
    }
    }

    dprintf(INFO, "STALL %s %d %d %d %d %d\n",
        reqname(s.request),
        s.type, s.request, s.value, s.index, s.length);

stall:
    writel((1<<16) | (1 << 0), USB_ENDPTCTRL(ept->num));    
}

static void endpoint_enable(struct udc_endpoint *ept, unsigned yes)
{
    unsigned n = readl(USB_ENDPTCTRL(ept->num));

    if(yes) {
        if(ept->in) {
            n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);//配置为传输,使能端点,reset toggle,bulk传输
        } else {
            n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
        }

        if(ept->num != 0) {
            /* XXX should be more dynamic... */
            if(usb_highspeed) {//port detec的时候判断的速度
                ept->head->config = CONFIG_MAX_PKT(512) | CONFIG_ZLT;
            } else {
                ept->head->config = CONFIG_MAX_PKT(64) | CONFIG_ZLT;
            }
        }
    }
    writel(n, USB_ENDPTCTRL(ept->num));//把配置的数据写入寄存器
}

原创粉丝点击