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

📄 usbs_sa11x0.c

📁 Sa11的USB驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
//// 1) the host transmits a special setup token, indicating the start//    of a control operation and possibly cancelling any existing control//    operation that may be in progress. USB peripherals cannot NAK this//    even if they are busy.//// 2) the setup operation is followed by an eight-byte packet from the host//    that describes the specific control operation. This fits into the//    SA11X0's eight-byte control fifo. There will be an endpoint 0//    interrupt with the out-packet-ready bit set. If the setup token//    was sent while a previous control operation was also in progress//    then the setup-end bit will be set as well.//// 3) the eight-byte packet is described in section 9.3 of the USB spec.//    The first byte holds three fields, with the top bit indicating the//    direction of subsequent data transfer. There are also two bytes//    specifying the size of the subsequent transfer. Obviously the//    packet also contains information such as the request type.////    If the specified size is zero then the endpoint will remain in//    its idle state. Otherwise the endpoint will switch to either//    IN or OUT state, depending on the direction of subsequent//    transfers.// // 4) some standard control operations can be handled by the code//    here. Set-address involves poking the address register and//    a change of state. Set-feature and clear-feature on the//    data endpoints can be used in conjunction with endpoint-halt.//    Get-status on the data endpoints tests the halt condition.//    It is also possible for the hardware-specific code to//    implement set-feature, clear-feature and get-status//    for the device as a whole since the SA11x0 always has to//    be self-powered and is incapable of initiating a remote//    wakeup.////    Other standard control operations will be handled by the//    application-specific installed handler, if any, or by the//    default handler usbs_handle_standard_control(). Class-specific//    and vendor-specific functions require appropriate handlers to be//    installed as well, If a particular request is not recognized//    then a stall condition should be raised. This will not prevent//    subsequent control operations, just the current one.////    Data transfers on endpoint 0 involve at most eight bytes at//    a time. More data will only be accepted if the out-packet-ready//    bit has been cleared via the serviced-opr bit, with the//    hardware nak'ing OUT requests. To send data back to the host//    the FIFO should be filled and then the in-packet-ready bit//    should be set.//// It looks like processing all control packets at DSR level should be// sufficient. During the data phase the hardware will NAK IN and// OUT requests if the fifo is still empty/full, so timing is not// an issue. Timing after receipt of the initial control message// may be more important, e.g. the 50ms upper limit on processing// the set-address control message, but this should still be ok.// This decision may have to be re-examined in the light of// experience.// Init may get called during system startup or following a reset.// During startup no work is needed since the hardware will// have been reset and everything should be fine. After a reset// the hardware will also be ok but there may be state information// in ep0 that needs to be reset.static voidusbs_sa11x0_ep0_init(void){    if ((EP0_STATE_IDLE != ep0.ep_state) &&        ((usbs_control_return (*)(usbs_control_endpoint*, int)) 0 != ep0.common.complete_fn)) {        (*ep0.common.complete_fn)(&ep0.common, -EPIPE);    }    ep0.common.state            = USBS_STATE_POWERED;    memset(ep0.common.control_buffer, 0, 8);    ep0.common.buffer           = (unsigned char*) 0;    ep0.common.buffer_size      = 0;    ep0.common.fill_buffer_fn   = (void (*)(usbs_control_endpoint*)) 0;    ep0.common.fill_data        = (void*) 0;    ep0.common.fill_index       = 0;    ep0.common.complete_fn      = (usbs_control_return (*)(usbs_control_endpoint*, int)) 0;    ep0.ep_state                = EP0_STATE_IDLE;    ep0.length                  = 0;    ep0.transmitted             = 0;}// The start function is called by higher-level code when things have// been set up, i.e. the enumeration data is available, appropriate// handlers have been installed for the different types of control// messages, and communication with the host is allowed to start. The// next event that should happen is a reset operation from the host,// so all other interrupts should be blocked. However it is likely// that the hardware will detect a suspend state before the reset// arrives, and hence the reset will act as a resume as well as a// reset.static voidusbs_sa11x0_ep0_start(usbs_control_endpoint* endpoint){    CYG_ASSERT( endpoint == &ep0.common, "USB startup involves the wrong endpoint");        // Activate the hardware. Write a 0 to the enable/disable bit 0.    // Bit 1 is read-only. The other bits are set to 1 to disable    // the corresponding interrupt source.    usbs_sa11x0_poke(USBS_CONTROL, CONTROL_ALL_INTR, CONTROL_ALL_INTR, 0);    // If there is additional platform-specific initialization to    // perform, do it now. This macro can come from the platform HAL.#ifdef SA11X0_USB_PLATFORM_INIT    SA11X0_USB_PLATFORM_INIT;#endif            // Clear any pending interrupts. There should not be any, but just    // in case. Note: passing 0x00FF as the should_be_clear argument    // is a race condition, an external event can happen at any time,    // so we may loop unnecessarily and lose an interrupt. However    // the initial reset should last for 10ms.    usbs_sa11x0_poke(USBS_STATUS, 0x00FF, 0x00, 0x00FF);    // The only interrupt really of interest right now is reset, but    // it is likely to be preceded by a resume.     usbs_sa11x0_poke(USBS_CONTROL,                     CONTROL_INTR_ENABLE(CONTROL_RESET_INTR | CONTROL_RESUME_INTR),                     0,                     CONTROL_INTR_CLEAR(CONTROL_RESET_INTR | CONTROL_RESUME_INTR));}// Filling the fifo with a reply to the host. This can be called// immediately at the end of a control message, to prepare for// the next IN token. It will also get called after each subsequent// IN operation when the fifo has been emptied.//// Experiments have indicated serious problems with the control fifo:// some writes to the fifo just get lost completely. The failure rate// is sufficiently high that more often than not the host will be// unable to read all the enumeration data. However, the write-count// register appears to give a valid indication of the current fifo// contents. This means the code can retry stuffing a particular byte// into the fifo until the write-count goes up.static voidusbs_sa11x0_ep0_fill_fifo(void){    cyg_bool ok     = true;    int filled      = 0;    int max;    int fifo_count  = *EP0_WRITE_COUNT;    int bits_to_set = 0;        // The host can interrupt the current control message at any time    // with a new one. In practice this is unlikely, things could get    // rather confused on the host side. However if a control message    // has been received then the fifo should obviously not be filled.    // A new control message is indicated by the SETUP_END bit.    //    // The hardware design means that there is a race condition: the    // new control message can come in at any time, even in the middle    // of filling the fifo. Checking the SETUP_END more often would    // reduce the probability of things getting messed up, but not    // eliminate it.    //    // There is a check for SETUP_END at the start of the DSR, so    // the setting of this bit should have resulted in another ISR    // and another DSR being scheduled. Hence there is no need for    // special action here.    if (0 != (*EP0_CONTROL & EP0_SETUP_END)) {        DBG(("EP0_fill_fifo(), interrupted by SETUP_END\n"));        return;    }    // There should never be any data in the fifo. Any such data could    // be the remnant of a previous transfer to the host, but that    // should all have gone out already. Alternatively it could be    // incoming data, but that means a new control message.    if (0 != fifo_count) {        DBG(("EP0_fill_fifo(), fifo already contains %d bytes", fifo_count));        return;    }    // The IN_READY bit should never be set on entry. It can only get    // set by a previous call to fill_fifo(), and the data should    // have gone out before we get back here.    if (0 != (*EP0_CONTROL & EP0_IN_READY)) {        DBG(("EP0 fill_fifo(), in-packet-ready bit already set, state %x\n", *EP0_CONTROL));        return;    }    // Now put up to another eight bytes into the fifo.    max = ((ep0.length - ep0.transmitted) > EP0_FIFO_SIZE) ? EP0_FIFO_SIZE : (ep0.length - ep0.transmitted);    while (ok && (filled < max)) {        if (0 != ep0.common.buffer_size) {            int         datum;            int         retries, checks;            cyg_bool    written;            datum       = *ep0.common.buffer++;            ep0.common.buffer_size--;            written     = false;                        for (retries = 0; ok && !written && (retries < MAX_RETRIES); retries++) {                if (filled != *EP0_WRITE_COUNT) {                    DBG(("EP0 fill_fifo, inconsistency, written %d but write count %d\n", filled, *EP0_WRITE_COUNT));                    ok = false;                }                *EP0_DATA = datum;                // The write-count may take a few cycles to settle down.                for (checks = 0; !written && (checks < MAX_CHECKS); checks++) {                    if (filled < *EP0_WRITE_COUNT) {                        filled++;                        written = true;                        // DBG(("Transferred %d byte (%x) after %d checks, %d retries\n", filled - 1, datum, checks, retries));                    }                }            }        } else if ((void (*)(usbs_control_endpoint*))0 != ep0.common.fill_buffer_fn) {            (*ep0.common.fill_buffer_fn)(&ep0.common);        } else {            break;        }    }    // At this point either it has proved impossible to fill the fifo,    // e.g. because of a new control message, or up to another eight    // bytes have been sent.     if (!ok) {        if (0 == (EP0_SETUP_END & *EP0_CONTROL)) {            // There is something seriously wrong.            DBG(("ep0_fill_fifo(), failed, only filled %d bytes, status %x\n", filled, *EP0_CONTROL));            usbs_sa11x0_poke(EP0_CONTROL, EP0_FORCE_STALL, EP0_FORCE_STALL, 0);        }        return;    }    // The following conditions are possible:    // 1) amount transferred == amount requested, transfer complete.    // 2) amount transferred < amount requested, this fill involved    //    <eight bytes, transfer complete by definition of the protocol.    // 3) amount transferred < amount requested but exactly eight    //    bytes were sent this time. It will be necessary to send    //    another packet of zero bytes to complete the transfer.    ep0.transmitted += filled;    if ((ep0.transmitted == ep0.length) || (filled < EP0_FIFO_SIZE)) {        ep0.ep_state    = EP0_STATE_IDLE;        if ((usbs_control_return (*)(usbs_control_endpoint*, int))0 != ep0.common.complete_fn) {            (void) (*ep0.common.complete_fn)(&ep0.common, 0);        }        ep0.common.buffer               = (unsigned char*) 0;        ep0.common.buffer_size          = 0;        ep0.common.fill_buffer_fn       = (void (*)(usbs_control_endpoint*)) 0;        // This informs the hardware that the control message has been        // handled.        bits_to_set = EP0_DATA_END;    }        // This allows another IN operation to empty the fifo.    bits_to_set |= EP0_IN_READY;    usbs_sa11x0_poke(EP0_CONTROL, bits_to_set, bits_to_set, 0);}// Another utility function to empty the fifo. This involves similar// hardware problems to writing, it is possible to read a byte without// changing the fifo state so that next time the same byte would be// read again. Again there is a possible race condition if another// control message arrives while emptying the fifo.static intusbs_sa11x0_ep0_empty_fifo(unsigned char* buf){    int         count   = *EP0_WRITE_COUNT & 0x00FF;    int         emptied = 0;    cyg_bool    ok      = true;    CYG_ASSERT( (count >= 0) & (count <= 8), "EP0 write count must be in range");    while (ok && (emptied < count)) {        int      retries, checks;        cyg_bool read   = false;        for (retries = 0; !read && (retries < MAX_RETRIES); retries++) {            if ((count - emptied) != *EP0_WRITE_COUNT) {                DBG(("EP0_empty_fifo, inconsistency, read %d bytes of %d, but fifo count %d\n", emptied, count, *EP0_WRITE_COUNT));                ok = false;            } else {

⌨️ 快捷键说明

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