USB_STATUS usb_class_mass_pass_on_usb ( /* [IN] Interface handle */ USB_MASS_CLASS_INTF_STRUCT_PTR intf_ptr ) { /* Body */ COMMAND_OBJECT_PTR cmd_ptr = NULL; TR_INIT_PARAM_STRUCT tr_init; USB_STATUS status = USB_OK; uint_8 tmp; #ifdef _HOST_DEBUG_ DEBUG_LOG_TRACE("usb_class_mass_pass_on_usb"); #endif /* Nothing can be done if there is nothing pending */ usb_class_mass_get_pending_request(intf_ptr, &cmd_ptr); if (cmd_ptr == NULL) { USB_unlock(); #ifdef _HOST_DEBUG_ DEBUG_LOG_TRACE("usb_class_mass_pass_on_usb, no matching request"); #endif return (USB_STATUS)USB_MASS_NO_MATCHING_REQUEST; } /* Endif */ /* Determine the appropriate action based on the phase */ switch (cmd_ptr->STATUS) { case STATUS_QUEUED_IN_DRIVER: /* means that CBW needs to be sent.*/ usb_hostdev_tr_init(&tr_init, usb_class_mass_call_back_cbw, (pointer)intf_ptr); tr_init.TX_BUFFER = (uchar_ptr)cmd_ptr->CBW_PTR; tr_init.TX_LENGTH = sizeof(CBW_STRUCT); status = _usb_host_send_data(intf_ptr->G.host_handle, intf_ptr->BULK_OUT_PIPE, &tr_init); break; case STATUS_FINISHED_CBW_ON_USB: /* Determine next phase (DATA or STATUS), length and direction */ if (LONG_LE_TO_HOST(*(uint_32_ptr)cmd_ptr->CBW_PTR->DCBWDATATRANSFERLENGTH) > 0) { /* Commen TR setup for IN or OUT direction */ usb_hostdev_tr_init(&tr_init,usb_class_mass_call_back_dphase, (pointer)intf_ptr); tmp = (uint_8)((cmd_ptr->CBW_PTR->BMCBWFLAGS) & MASK_NON_DIRECTION_BITS); switch(tmp) { case DIRECTION_OUT: /* Make a TR with DATA Phase call back.*/ tr_init.TX_BUFFER = (uchar_ptr)cmd_ptr->DATA_BUFFER; tr_init.TX_LENGTH = cmd_ptr->BUFFER_LEN; status = _usb_host_send_data(intf_ptr->G.host_handle, intf_ptr->BULK_OUT_PIPE, &tr_init); break; case DIRECTION_IN: /* Make a TR with DATA call back.*/ tr_init.RX_BUFFER = (uchar_ptr)cmd_ptr->DATA_BUFFER; tr_init.RX_LENGTH = cmd_ptr->BUFFER_LEN; status = _usb_host_recv_data(intf_ptr->G.host_handle, intf_ptr->BULK_IN_PIPE, &tr_init); break; default: break; } /* Endswitch */ break; } /* Endif */ /* ** else case: ** No data transfer is expected of the request. Fall through to ** STATUS phase */ case STATUS_FINISHED_DPHASE_ON_USB: /* Make a TR and send it with STATUS call back */ usb_hostdev_tr_init(&tr_init,usb_class_mass_call_back_csw, (pointer)intf_ptr); tr_init.RX_BUFFER = (uchar_ptr)cmd_ptr->CSW_PTR; tr_init.RX_LENGTH = sizeof(CSW_STRUCT); status = _usb_host_recv_data(intf_ptr->G.host_handle, intf_ptr->BULK_IN_PIPE, &tr_init); break; case STATUS_FINISHED_CSW_ON_USB: /* No action */ case STATUS_FAILED_IN_CSW: /* Should never happen */ default: break; } /* Endswitch */ #ifdef _HOST_DEBUG_ DEBUG_LOG_TRACE("usb_class_mass_pass_on_usb, SUCCESSFUL"); #endif return USB_log_error(__FILE__,__LINE__,status); } /* Endbody */
/*FUNCTION*---------------------------------------------------------------- * * Function Name : usb_host_hub_device_sm * Returned Value : None * Comments : * called when a hub changes state; sm = state machine *END*--------------------------------------------------------------------*/ static void usb_host_hub_device_sm ( /* [IN] structure with USB pipe information on the interface */ PIPE_STRUCT_PTR pipe, /* [IN] parameters */ pointer param, /* [IN] buffer of data from IN stage */ pointer buffer, /* [IN] length of data from IN stage */ uint_32 len, /* [IN] status of transaction */ USB_STATUS status ) { /* Body */ register HUB_DEVICE_STRUCT_PTR hub_instance = (HUB_DEVICE_STRUCT_PTR) param; _mqx_int i; switch (hub_instance->STATE) { case HUB_GET_DESCRIPTOR_TINY_PROCESS: /* here we get number of ports from USB data */ hub_instance->HUB_PORT_NR = ((HUB_DESCRIPTOR_STRUCT_PTR) buffer)->BNRPORTS; hub_instance->STATE = HUB_GET_DESCRIPTOR_PROCESS; usb_class_hub_get_descriptor((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, 7 + hub_instance->HUB_PORT_NR / 8 + 1); break; case HUB_GET_DESCRIPTOR_PROCESS: { /* here, we get information from the hub and fill info in hub_instance */ HUB_DESCRIPTOR_STRUCT_PTR hub_desc = (HUB_DESCRIPTOR_STRUCT_PTR) buffer; hub_instance->HUB_PORTS = USB_mem_alloc_zero(hub_instance->HUB_PORT_NR * sizeof(HUB_PORT_STRUCT)); for (i = 0; i < hub_instance->HUB_PORT_NR; i++) { /* get REMOVABLE bit from the desriptor for appropriate installed port */ (hub_instance->HUB_PORTS + i)->APP_STATUS = hub_desc->DEVICEREMOVABLE[(i + 1) / 8] & (0x01 << ((i + 1) % 8)) ? HUB_PORT_REMOVABLE : 0; } } /* pass fluently to HUB_SET_PORT_FEATURE_PROCESS */ hub_instance->STATE = HUB_SET_PORT_FEATURE_PROCESS; hub_instance->port_iterator = 0; case HUB_SET_PORT_FEATURE_PROCESS: // if (hub_instance->port_iterator) /* register, that the port is now powered */ // hub_instance->HUB_PORTS[hub_instance->port_iterator - 1].POWERED = 1; if (hub_instance->port_iterator < hub_instance->HUB_PORT_NR) { usb_class_hub_set_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, ++hub_instance->port_iterator, PORT_POWER); break; } /* EndIf */ /* else */ /* pass fluently to HUB_CLEAR_PORT_FEATURE_PROCESS */ hub_instance->STATE = HUB_CLEAR_PORT_FEATURE_PROCESS; hub_instance->port_iterator = 0; case HUB_CLEAR_PORT_FEATURE_PROCESS: if (hub_instance->port_iterator < hub_instance->HUB_PORT_NR) { usb_class_hub_clear_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, ++hub_instance->port_iterator, C_PORT_CONNECTION); break; } /* EndIf */ /* else */ /* pass fluently to HUB_GET_PORT_STATUS_PROCESS */ hub_instance->STATE = HUB_GET_PORT_STATUS_PROCESS; hub_instance->port_iterator = 0; case HUB_GET_PORT_STATUS_PROCESS: if (hub_instance->port_iterator) /* register the current status of the port, do the conversion LSB -> MSB */ (hub_instance->HUB_PORTS + hub_instance->port_iterator - 1)->STATUS = SHORT_LE_TO_HOST(*(uint_16*)buffer); if (hub_instance->port_iterator < hub_instance->HUB_PORT_NR) { usb_class_hub_get_port_status((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, ++hub_instance->port_iterator, 4); break; } /* EndIf */ /* else */ /* test if device is attached since startup */ for (i = 0; i < hub_instance->HUB_PORT_NR; i++) if ((hub_instance->HUB_PORTS + i)->STATUS & (1 << PORT_CONNECTION)) { /* if some device is attached since startup, then start session */ hub_instance->port_iterator = i; hub_instance->STATE = HUB_NONE; (hub_instance->HUB_PORTS + i)->APP_STATUS |= HUB_PORT_ATTACHED; usb_class_hub_set_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, PORT_RESET); break; } usb_class_hub_wait_for_interrupt((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_int_callback, (pointer) hub_instance, hub_instance->HUB_PORT_NR / 8 + 1); break; case HUB_RESET_DEVICE_PORT_PROCESS: hub_instance->STATE = HUB_NONE; usb_class_hub_set_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, PORT_RESET); usb_class_hub_wait_for_interrupt((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_int_callback, (pointer) hub_instance, hub_instance->HUB_PORT_NR / 8 + 1); break; case HUB_ADDRESS_DEVICE_PORT_PROCESS: /* compute speed */ if ((hub_instance->HUB_PORTS + hub_instance->port_iterator)->STATUS & (1 << PORT_HIGH_SPEED)) i = USB_SPEED_HIGH; else if ((hub_instance->HUB_PORTS + hub_instance->port_iterator)->STATUS & (1 << PORT_LOW_SPEED)) i = USB_SPEED_LOW; else i = USB_SPEED_FULL; /* FIXME: accessing intf_handle directly without validation to get its host handle is not good method */ usb_dev_list_attach_device( ((USB_HUB_CLASS_INTF_STRUCT_PTR) hub_instance->CCS.class_intf_handle)->G.host_handle, i, /* port speed */ pipe->DEVICE_ADDRESS, /* hub address */ hub_instance->port_iterator + 1 /* hub port */ ); /* test if there is still device which was not reset */ for (i = 0; i < hub_instance->HUB_PORT_NR; i++) if (((hub_instance->HUB_PORTS + i)->STATUS & (1 << PORT_CONNECTION)) && !((hub_instance->HUB_PORTS + i)->APP_STATUS & HUB_PORT_ATTACHED)) { /* if some device is attached since startup, then start session */ hub_instance->port_iterator = i; hub_instance->STATE = HUB_NONE; (hub_instance->HUB_PORTS + i)->APP_STATUS |= HUB_PORT_ATTACHED; usb_class_hub_set_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, PORT_RESET); break; } usb_class_hub_wait_for_interrupt((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_int_callback, (pointer) hub_instance, hub_instance->HUB_PORT_NR / 8 + 1); break; case HUB_DETACH_DEVICE_PORT_PROCESS: /* FIXME: accessing intf_handle directly without validation to get its host handle is not good method */ usb_dev_list_detach_device( ((USB_HUB_CLASS_INTF_STRUCT_PTR) hub_instance->CCS.class_intf_handle)->G.host_handle, pipe->DEVICE_ADDRESS, /* hub address */ hub_instance->port_iterator + 1 /* hub port */ ); /* reset the app status */ (hub_instance->HUB_PORTS + hub_instance->port_iterator)->APP_STATUS = 0x00; /* test if there is still device which was not reset */ for (i = 0; i < hub_instance->HUB_PORT_NR; i++) if (((hub_instance->HUB_PORTS + i)->STATUS & (1 << PORT_CONNECTION)) && !((hub_instance->HUB_PORTS + i)->APP_STATUS & HUB_PORT_ATTACHED)) { /* if some device is attached since startup, then start session */ hub_instance->port_iterator = i; hub_instance->STATE = HUB_NONE; (hub_instance->HUB_PORTS + i)->APP_STATUS |= HUB_PORT_ATTACHED; usb_class_hub_set_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, PORT_RESET); break; } usb_class_hub_wait_for_interrupt((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_int_callback, (pointer) hub_instance, hub_instance->HUB_PORT_NR / 8 + 1); break; case HUB_GET_PORT_STATUS_ASYNC: { uint_32 stat = LONG_LE_TO_HOST(*(uint_32*)buffer); /* register the current status of the port */ (hub_instance->HUB_PORTS + hub_instance->port_iterator)->STATUS = stat; /* let's see what happened */ if ((1 << C_PORT_CONNECTION) & stat) { /* get if a device on port was attached or detached */ if ((hub_instance->HUB_PORTS + hub_instance->port_iterator)->APP_STATUS & HUB_PORT_ATTACHED) { hub_instance->STATE = HUB_DETACH_DEVICE_PORT_PROCESS; usb_class_hub_clear_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, C_PORT_CONNECTION); } else { hub_instance->STATE = HUB_RESET_DEVICE_PORT_PROCESS; usb_class_hub_clear_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, C_PORT_CONNECTION); } break; } else if ((1 << C_PORT_RESET) & stat) { hub_instance->STATE = HUB_ADDRESS_DEVICE_PORT_PROCESS; (hub_instance->HUB_PORTS + hub_instance->port_iterator)->APP_STATUS |= HUB_PORT_ATTACHED; usb_class_hub_clear_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, C_PORT_RESET); break; } else if ((1 << C_PORT_ENABLE) & stat) { /* unexpected event (error), just ignore the port */ hub_instance->STATE = HUB_DETACH_DEVICE_PORT_PROCESS; usb_class_hub_clear_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, C_PORT_ENABLE); break; } else if ((1 << C_PORT_OVER_CURRENT) & stat) { /* unexpected event (error), just ignore the port */ hub_instance->STATE = HUB_NONE; usb_class_hub_clear_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, C_PORT_OVER_CURRENT); usb_class_hub_wait_for_interrupt((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_int_callback, (pointer) hub_instance, hub_instance->HUB_PORT_NR / 8 + 1); break; } else if ((1 << C_PORT_POWER) & stat) { /* unexpected event (error), just ignore the port */ hub_instance->STATE = HUB_NONE; usb_class_hub_clear_port_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, hub_instance->port_iterator + 1, C_PORT_POWER); usb_class_hub_wait_for_interrupt((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_int_callback, (pointer) hub_instance, hub_instance->HUB_PORT_NR / 8 + 1); break; } /* FIXME: handle more events */ break; } case HUB_GET_STATUS_ASYNC: { HUB_STATUS_STRUCT_PTR hub_stat = (HUB_STATUS_STRUCT_PTR) buffer; uint_32 change = SHORT_LE_TO_HOST(hub_stat->WHUBCHANGE); if ((1 << C_HUB_LOCAL_POWER) & change) { hub_instance->STATE = HUB_NONE; usb_class_hub_clear_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, C_HUB_LOCAL_POWER); usb_class_hub_wait_for_interrupt((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_int_callback, (pointer) hub_instance, hub_instance->HUB_PORT_NR / 8 + 1); } else if ((1 << C_HUB_OVER_CURRENT) & change) { hub_instance->STATE = HUB_NONE; usb_class_hub_clear_feature((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_device_sm, (pointer) hub_instance, C_HUB_OVER_CURRENT); usb_class_hub_wait_for_interrupt((CLASS_CALL_STRUCT_PTR) &hub_instance->CCS, (tr_callback) usb_host_hub_int_callback, (pointer) hub_instance, hub_instance->HUB_PORT_NR / 8 + 1); } break; } } /* EndSwitch */ return; } /* EndBody */
void usb_class_mass_call_back_csw ( /* [IN] Pipe on which CBW call was made */ _usb_pipe_handle pipe_handle, /* [IN] Pointer to the class instance */ pointer user_parm, /* [IN] Pointer to data buffer */ uchar_ptr buffer, /* [IN] Length of data transfered */ uint_32 length_data_transfered, /* [IN] Status of the transfer */ uint_32 status ) { /* Body */ USB_MASS_CLASS_INTF_STRUCT_PTR plocal_intf = NULL; COMMAND_OBJECT_PTR cmd_ptr = NULL; CSW_STRUCT_PTR pCsw = NULL; uint_32 tmp1, tmp2, tmp3; boolean proc_next = FALSE; USB_STATUS return_code; #ifdef _HOST_DEBUG_ DEBUG_LOG_TRACE("usb_class_mass_call_back_csw"); #endif if (user_parm) { /* Get the pointer to the pending request */ plocal_intf = (USB_MASS_CLASS_INTF_STRUCT_PTR) user_parm; usb_class_mass_get_pending_request(plocal_intf, &cmd_ptr); } /* Endif */ if (!cmd_ptr) { #ifdef _HOST_DEBUG_ DEBUG_LOG_TRACE("usb_class_mass_call_back_csw, bad param"); #endif return; } /* Endif */ /* Finish transaction and queue next command */ if (status == USB_OK) { pCsw = (CSW_STRUCT_PTR) cmd_ptr->CSW_PTR; tmp1 = LONG_LE_TO_HOST(*(uint_32_ptr)pCsw->DCSWTAG); tmp2 = LONG_LE_TO_HOST(*(uint_32_ptr)cmd_ptr->CBW_PTR->DCBWTAG); tmp3 = LONG_LE_TO_HOST(*(uint_32_ptr)pCsw->DCSWSIGNATURE); /* Size must be verified, as well as the signature and the tags */ if ((length_data_transfered != sizeof(CSW_STRUCT)) || (tmp3 != CSW_SIGNATURE) || (tmp1 != tmp2)) { if (cmd_ptr->RETRY_COUNT < MAX_RETRIAL_ATTEMPTS) { cmd_ptr->RETRY_COUNT++; cmd_ptr->STATUS = STATUS_FINISHED_DPHASE_ON_USB; cmd_ptr->PREV_STATUS = cmd_ptr->STATUS; /* preserve the status */ status = usb_class_mass_reset_recovery_on_usb(plocal_intf); } else { status = STATUS_CANCELLED; /* cannot keep repeating */ } /* Endif */ if ((status != USB_OK) && (status != USBERR_TRANSFER_IN_PROGRESS) && (status != USB_STATUS_TRANSFER_QUEUED)) { proc_next = TRUE; } /* Endif */ } else { /* Check value of status field in CSW */ switch (pCsw->BCSWSTATUS) { case CSW_STATUS_GOOD: /* Command succeed. Notify application and cleanup */ cmd_ptr->STATUS = STATUS_COMPLETED; proc_next = TRUE; break; case CSW_STATUS_FAILED: /* Command failed. Notify application and cleanup */ cmd_ptr->STATUS = STATUS_FAILED_IN_CSW; proc_next = TRUE; break; default: break; } /* Endswitch */ } /* Endif */ } else if (status == USBERR_ENDPOINT_STALLED) { if (cmd_ptr->RETRY_COUNT < MAX_RETRIAL_ATTEMPTS) { cmd_ptr->RETRY_COUNT++; cmd_ptr->STATUS = STATUS_FINISHED_DPHASE_ON_USB; cmd_ptr->PREV_STATUS = cmd_ptr->STATUS; /* preserve the status */ return_code = usb_class_mass_clear_bulk_pipe_on_usb(plocal_intf); if (return_code != USB_OK && return_code != USB_STATUS_TRANSFER_QUEUED) { status = USBERR_TRANSFER_IN_PROGRESS; } } else { status = STATUS_CANCELLED; /* cannot keep repeating */ } /* Endif */ if ((status != USB_OK) && (status != USBERR_TRANSFER_IN_PROGRESS)) { /* Command didn't succeed. Notify application and cleanup */ cmd_ptr->STATUS = STATUS_CANCELLED; proc_next = TRUE; } /* Endbody */ } else { /* Command didn't succeed. Notify application and cleanup */ cmd_ptr->STATUS = STATUS_CANCELLED; proc_next = TRUE; } /* Endif */ /* Should we cleanup and process the next command? */ if (proc_next) { cmd_ptr->CALLBACK(status, plocal_intf, cmd_ptr, cmd_ptr->TR_BUF_LEN); usb_class_mass_deleteq(plocal_intf); /* Send next command, if any */ if (!USB_CLASS_MASS_IS_Q_EMPTY(plocal_intf)) { status = usb_class_mass_pass_on_usb( plocal_intf); } /* Endbody */ } /* Endif */ #ifdef _HOST_DEBUG_ DEBUG_LOG_TRACE("usb_class_mass_call_back_csw, SUCCESSFUL"); #endif } /* Endbody */