diff options
author | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
---|---|---|
committer | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
commit | c6da2cfeb05178a11c6d062a06f8078150ee492f (patch) | |
tree | f3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/usb/host/shost/shost_transferchecker_control.c | |
parent | c6d7c4dbff353eac7919342ae6b3299a378160a6 (diff) | |
download | kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2 |
samsung update 1
Diffstat (limited to 'drivers/usb/host/shost/shost_transferchecker_control.c')
-rw-r--r-- | drivers/usb/host/shost/shost_transferchecker_control.c | 777 |
1 files changed, 777 insertions, 0 deletions
diff --git a/drivers/usb/host/shost/shost_transferchecker_control.c b/drivers/usb/host/shost/shost_transferchecker_control.c new file mode 100644 index 0000000..8d0cfbc --- /dev/null +++ b/drivers/usb/host/shost/shost_transferchecker_control.c @@ -0,0 +1,777 @@ +/**************************************************************************** + * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved + * + * [File Name] : ControlTransferChecker.c + * [Description] : The Source file implements the external + * and internal functions of ControlTransferChecker. + * [Author] : Yang Soon Yeal { syatom.yang@samsung.com } + * [Department] : System LSI Division/System SW Lab + * [Created Date]: 2009/02/10 + * [Revision History] + * (1) 2008/06/13 by Yang Soon Yeal { syatom.yang@samsung.com } + * - Created this file and implements functions of ControlTransferChecker + * (2) 2008/06/18 by Yang Soon Yeal { syatom.yang@samsung.com } + * - Completed to implement ControlTransferChecker.c v1.0 + * + ****************************************************************************/ +/**************************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ****************************************************************************/ + + + +/******************************************************************************/ +/*! + * @name u8 process_xfercompl_on_control(struct td *result_td, + * struct hc_info *hcinfo) + * + * + * @brief this function deals with the xfercompl event + * the procedure of this function is as following + * 1. clears all bits of the channel' HCINT + * by using clear_ch_intr() of S3CIsr. + * 2. masks some bit of HCINTMSK + * 3. updates the result_td fields + * err_cnt/u8/standard_dev_req_info. + * 4. updates the result_td->parent_ed_p->ed_status. + * control_data_tgl. + * 5. calculates the tranferred size + * by calling calc_transferred_size() on DATA_STAGE. + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return USB_ERR_SUCCESS + */ +/******************************************************************************/ +static u8 process_xfercompl_on_control(struct td *result_td, struct hc_info *hcinfo) +{ + u8 ret_val = 0; + + result_td->err_cnt = 0; + + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ALL); + + /* Mask ack Interrupt.. */ + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + + result_td->parent_ed_p->ed_status.is_ping_enable = false; + + switch (result_td->standard_dev_req_info.conrol_transfer_stage) { + + case SETUP_STAGE: + if (result_td->standard_dev_req_info.is_data_stage) + result_td->standard_dev_req_info. + conrol_transfer_stage = DATA_STAGE; + else + result_td->standard_dev_req_info. + conrol_transfer_stage = STATUS_STAGE; + + ret_val = RE_TRANSMIT; + + break; + + case DATA_STAGE: + + result_td->transferred_szie += + calc_transferred_size(true, result_td, hcinfo); + + /* at IN Transfer, short transfer is accepted. */ + if (result_td->transferred_szie == result_td->buf_size) { + result_td->standard_dev_req_info. + conrol_transfer_stage = STATUS_STAGE; + result_td->error_code = USB_ERR_STATUS_COMPLETE; + + } else { + if (result_td->parent_ed_p->ed_desc.is_ep_in && + hcinfo->hc_size.b.xfersize) { + + if (result_td->transfer_flag & + USB_TRANS_FLAG_NOT_SHORT) { + + result_td->error_code = + USB_ERR_STATUS_SHORTREAD; + result_td->standard_dev_req_info. + conrol_transfer_stage = + STATUS_STAGE; + + } else { + result_td->error_code = + USB_ERR_STATUS_COMPLETE; + result_td->standard_dev_req_info. + conrol_transfer_stage = + STATUS_STAGE; + } + + } else { + /* the Data Stage is not completed. + So we need to continue Data Stage. */ + result_td->standard_dev_req_info. + conrol_transfer_stage = DATA_STAGE; + update_data_toggle(result_td, + hcinfo->hc_size.b.pid); + } + } + + if (hcinfo->hc_int.b.nyet) { + /* at OUT Transfer, we must re-transmit. */ + if (result_td->parent_ed_p->ed_desc.is_ep_in == false) { + + if (result_td->parent_ed_p->ed_desc. + dev_speed == HIGH_SPEED_OTG) + result_td->parent_ed_p->ed_status. + is_ping_enable = true; + else + result_td->parent_ed_p->ed_status. + is_ping_enable = false; + } + } + ret_val = RE_TRANSMIT; + break; + + case STATUS_STAGE: + result_td->standard_dev_req_info. + conrol_transfer_stage = COMPLETE_STAGE; + + if (hcinfo->hc_int.b.nyet) { + /* at OUT Transfer, we must re-transmit. */ + if (result_td->parent_ed_p->ed_desc.is_ep_in == false) { + + if (result_td->parent_ed_p->ed_desc. + dev_speed == HIGH_SPEED_OTG) + result_td->parent_ed_p->ed_status. + is_ping_enable = true; + else + result_td->parent_ed_p->ed_status. + is_ping_enable = false; + } + } + + ret_val = DE_ALLOCATE; + break; + + default: + break; + } + + return ret_val; +} + +/******************************************************************************/ +/*! + * @name u8 process_ahb_on_control(ruct td *result_td, + * struct hc_info *hcinfo) + * + * + * @brief this function deals with theAHB Errorl event + * this function stop the channel to be executed + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return DE_ALLOCATE + */ +/******************************************************************************/ + +/* TODO: not used. remove */ +#if 0 +static u8 process_ahb_on_control(struct td *result_td, + struct hc_info *hcinfo) +{ + result_td->err_cnt = 0; + result_td->error_code = USB_ERR_STATUS_AHBERR; + + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_AHBErr); + + /* Mask ack Interrupt.. */ + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + + /* we just calculate the size of the transferred data + on Data Stage of Control Transfer. */ + if (result_td->standard_dev_req_info. + conrol_transfer_stage == DATA_STAGE) + result_td->transferred_szie += + calc_transferred_size(false, result_td, hcinfo); + + return DE_ALLOCATE; + +} +#endif + +/******************************************************************************/ +/*! + * @name u8 process_stall_on_control(struct td *result_td, + * struct hc_info *hcinfo) + * + * + * @brief this function deals with theStall event + * but USB2.0 Spec don't permit the Stall + * on Setup Stage of Control Transfer. + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return DE_ALLOCATE + */ +/******************************************************************************/ +static u8 process_stall_on_control(struct td *result_td, + struct hc_info *hcinfo) +{ + result_td->err_cnt = 0; + result_td->error_code = USB_ERR_STATUS_STALL; + + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL); + + /* Mask ack Interrupt.. */ + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + + result_td->parent_ed_p->ed_status.is_ping_enable = false; + + /* we just calculate the size of the transferred data + on Data Stage of Control Transfer. */ + if (result_td->standard_dev_req_info. + conrol_transfer_stage == DATA_STAGE) + result_td->transferred_szie += + calc_transferred_size(false, result_td, hcinfo); + + return DE_ALLOCATE; +} + +/******************************************************************************/ +/*! + * @name u8 process_nak_on_control(ruct td *result_td, + * struct hc_info *hcinfo) + * + * + * @brief this function deals with the nak event + * nak is occured at OUT/IN Transaction of Data/Status Stage, + * and is not occured at Setup Stage. + * If nak is occured at IN Transaction, + * this function processes this interrupt as following. + * 1. resets the result_td->err_cnt. + * 2. masks ack/nak/DaaTglErr bit of HCINTMSK. + * 3. clears the nak bit of HCINT + * 4. be careful, nak of IN Transaction don't require re-transmit. + * + * If nak is occured at OUT Transaction, + * this function processes this interrupt as following. + * 1. all procedures of IN Transaction are executed. + * 2. calculates the size of the transferred data. + * 3. if the speed of USB Device is High-Speed, sets the ping protocol. + * 4. update the Toggle + * at OUT Transaction, this function check whether the speed of + * USB Device is High-Speed or not. + * if USB Device is High-Speed, then + * this function sets the ping protocol. + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return RE_SCHEDULE + */ +/******************************************************************************/ +static u8 process_nak_on_control(struct td *result_td, + struct hc_info *hcinfo) +{ + result_td->err_cnt = 0; + + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + + /* at OUT Transfer, we must re-transmit. */ + if (result_td->parent_ed_p->ed_desc.is_ep_in == false) { + result_td->transferred_szie += + calc_transferred_size(false, result_td, hcinfo); + + update_data_toggle(result_td, hcinfo->hc_size.b.pid); + } + + if (result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG) { + + if (result_td->standard_dev_req_info. + conrol_transfer_stage == DATA_STAGE) { + if (result_td->parent_ed_p->ed_desc.is_ep_in == false) + result_td->parent_ed_p->ed_status. + is_ping_enable = true; + } + + else if (result_td->standard_dev_req_info. + conrol_transfer_stage == STATUS_STAGE) { + + if (result_td->parent_ed_p->ed_desc.is_ep_in == true) + result_td->parent_ed_p->ed_status. + is_ping_enable = true; + + } else + result_td->parent_ed_p->ed_status. + is_ping_enable = false; + } + + return RE_SCHEDULE; +} + +/******************************************************************************/ +/*! + * @name u8 process_ack_on_control(ruct td *result_td, + * struct hc_info *hcinfo) + * + * + * @brief this function deals with the ack event + * ack of IN/OUT Transaction don't need any retransmit. + * this function just resets result_td->err_cnt + * and masks ack/nak/DataTgl of HCINTMSK. + * finally, this function clears ack bit of HCINT. + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return NO_ACTION + */ +/******************************************************************************/ +static u8 process_ack_on_control(struct td *result_td, + struct hc_info *hcinfo) +{ + result_td->err_cnt = 0; + + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + + result_td->parent_ed_p->ed_status.is_ping_enable = false; + + return NO_ACTION; + +} + +/******************************************************************************/ +/*! + * @name u8 process_nyet_on_control(struct td *result_td, + * struct hc_info *hcinfo) + * + * @brief this function deals with the nyet event + * nyet is occured at OUT Transaction of Data/Status Stage, + * and is not occured at Setup Stage. + * If nyet is occured at OUT Transaction, + * this function processes this interrupt as following. + * 1. resets the result_td->err_cnt. + * 2. masks ack/nak/datatglerr bit of HCINTMSK. + * 3. clears the nyet bit of HCINT + * 4. calculates the size of the transferred data. + * 5. if the speed of USB Device is High-Speed, sets the ping protocol. + * 6. update the Data Toggle. + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return RE_SCHEDULE + */ +/******************************************************************************/ +static u8 process_nyet_on_control(struct td *result_td, + struct hc_info *hcinfo) +{ + result_td->err_cnt = 0; + + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NYET); + + result_td->transferred_szie += + calc_transferred_size(false, result_td, hcinfo); + + if (result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG) { + if (result_td->standard_dev_req_info. + conrol_transfer_stage == DATA_STAGE) { + + if (result_td->parent_ed_p->ed_desc.is_ep_in == false) + result_td->parent_ed_p->ed_status. + is_ping_enable = true; + } + + else if (result_td->standard_dev_req_info. + conrol_transfer_stage == STATUS_STAGE) { + + if (result_td->parent_ed_p->ed_desc.is_ep_in == true) + result_td->parent_ed_p->ed_status. + is_ping_enable = true; + + } else + result_td->parent_ed_p->ed_status. + is_ping_enable = false; + } + + update_data_toggle(result_td, hcinfo->hc_size.b.pid); + + return RE_SCHEDULE; +} + +/******************************************************************************/ +/*! + * @name u8 process_xacterr_on_control(ruct td *result_td, + * struct hc_info *hcinfo) + * + * + * @brief this function deals with the xacterr event + * xacterr is occured at OUT/IN Transaction of Data/Status Stage, + * and is not occured at Setup Stage. + * if Timeout/CRC error/false EOP is occured, then xacterr is occured. + * the procedure to process xacterr is as following. + * 1. increses the result_td->err_cnt + * 2. check whether the result_td->err_cnt is equal to 3. + * 3. unmasks ack/nak/datatglerr bit of HCINTMSK. + * 4. clears the xacterr bit of HCINT + * 5. calculates the size of the transferred data. + * 6. if the speed of USB Device is High-Speed, sets the ping protocol. + * 7. update the Data Toggle. + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return RE_TRANSMIT -if the Error Counter is less than RETRANSMIT_THRESHOLD + * DE_ALLOCATE -if the Error Counter is equal to RETRANSMIT_THRESHOLD + */ +/******************************************************************************/ +static u8 process_xacterr_on_control(struct td *result_td, + struct hc_info *hcinfo) +{ + u8 ret_val = 0; + + if (result_td->err_cnt < RETRANSMIT_THRESHOLD) { + + result_td->cur_stransfer.hc_reg.hc_int_msk.d32 |= + (CH_STATUS_ACK + CH_STATUS_NAK + CH_STATUS_DataTglErr); + + ret_val = RE_TRANSMIT; + + unmask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + unmask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + unmask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + result_td->err_cnt++ ; + + } else { + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + ret_val = DE_ALLOCATE; + result_td->err_cnt = 0 ; + result_td->error_code = USB_ERR_STATUS_XACTERR; + } + + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + + if (result_td->standard_dev_req_info. + conrol_transfer_stage == DATA_STAGE) + result_td->transferred_szie += + calc_transferred_size(false, result_td, hcinfo); + + if (result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG) { + + if (result_td->standard_dev_req_info. + conrol_transfer_stage == DATA_STAGE) { + if (result_td->parent_ed_p->ed_desc.is_ep_in == false) + result_td->parent_ed_p->ed_status. + is_ping_enable = true; + } + + else if (result_td->standard_dev_req_info. + conrol_transfer_stage == STATUS_STAGE) { + + if (result_td->parent_ed_p->ed_desc.is_ep_in == true) + result_td->parent_ed_p->ed_status. + is_ping_enable = true; + + } else + result_td->parent_ed_p->ed_status.is_ping_enable = + false; + } + + update_data_toggle(result_td, hcinfo->hc_size.b.pid); + + return ret_val; + +} + +/******************************************************************************/ +/*! + * @name void process_bblerr_on_control(truct td *result_td, + * struct hc_info *hcinfo) + * + * + * @brief this function deals with the Babble event + * babble error can be just occured at IN Transaction. + * So if the direction of transfer is + * OUT, this function return Error Code. + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return DE_ALLOCATE + * NO_ACTION -if the direction is OUT + */ +/******************************************************************************/ +static u8 process_bblerr_on_control(struct td *result_td, + struct hc_info *hcinfo) +{ + + if (!result_td->parent_ed_p->ed_desc.is_ep_in) + return NO_ACTION; + + result_td->err_cnt = 0; + result_td->error_code = USB_ERR_STATUS_BBLERR; + + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL); + + /* Mask ack Interrupt.. */ + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + + result_td->parent_ed_p->ed_status.is_ping_enable = false; + + /* we just calculate the size of the transferred data + on Data Stage of Control Transfer. */ + if (result_td->standard_dev_req_info. + conrol_transfer_stage == DATA_STAGE) + result_td->transferred_szie += + calc_transferred_size(false, result_td, hcinfo); + + return DE_ALLOCATE; +} + +/******************************************************************************/ +/*! + * @name u8 process_datatgl_on_control(struct td *result_td, + * struct hc_info *hcinfo) + * + * + * @brief this function deals with the datatglerr event + * the datatglerr event is occured at IN Transfer. + * this function just resets result_td->err_cnt + * and masks ack/nak/DataTgl of HCINTMSK. + * finally, this function clears datatglerr bit of HCINT. + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return NO_ACTION + */ +/******************************************************************************/ +static u8 process_datatgl_on_control(struct td *result_td, + struct hc_info *hcinfo) +{ + result_td->err_cnt = 0; + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + + return NO_ACTION; + +} + + +/******************************************************************************/ +/*! + * @name u8 process_chhltd_on_control(truct td *result_td, + * struct hc_info *hcinfo) + * + * + * @brief this function processes Channel Halt event + * firstly, this function checks the reason of the Channel Halt, + * and according to the reason, + * calls the sub-functions to process the result. + * + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return RE_TRANSMIT -if need to retransmit the result_td. + * RE_SCHEDULE -if need to reschedule the result_td. + * DE_ALLOCATE -if USB Transfer is completed. + */ +/******************************************************************************/ +static u8 process_chhltd_on_control(struct td *result_td, + struct hc_info *hcinfo) +{ + if (hcinfo->hc_int.b.xfercompl) + return process_xfercompl_on_control(result_td, hcinfo); + + else if (hcinfo->hc_int.b.stall) + return process_stall_on_control(result_td, hcinfo); + + else if (hcinfo->hc_int.b.bblerr) + return process_bblerr_on_control(result_td, hcinfo); + + else if (hcinfo->hc_int.b.xacterr) + return process_xacterr_on_control(result_td, hcinfo); + + else if (hcinfo->hc_int.b.nak) + return process_nak_on_control(result_td, hcinfo); + + else if (hcinfo->hc_int.b.nyet) + return process_nyet_on_control(result_td, hcinfo); + + else { + + /* Occure Error State.....*/ + clear_ch_intr(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ALL); + + /* Mask ack Interrupt.. */ + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_ACK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_NAK); + mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, + CH_STATUS_DataTglErr); + result_td->err_cnt++; + + if (result_td->err_cnt == 3) { + + result_td->error_code = USB_ERR_STATUS_XACTERR; + result_td->err_cnt = 0; + return DE_ALLOCATE; + } + return RE_TRANSMIT; + } + return USB_ERR_SUCCESS; +} + + +/******************************************************************************/ +/*! + * @name u8 process_control_transfer(struct td *result_td, + * struct hc_info *hcinfo) + * + * @brief this function processes the result of the Control Transfer. + * firstly, this function checks the result the Control Transfer. + * and according to the result, calls the sub-functions + * to process the result. + * + * + * @param [IN] result_td + * -indicates the pointer of the struct td to be mapped with the uChNum. + * [IN] ubChNum + * -indicates the number of the channel to be interrupted. + * [IN] hcinfo + * -indicates the interrupt information of the Channel to be interrupted + * + * @return RE_TRANSMIT -if need to retransmit the result_td. + * RE_SCHEDULE -if need to reschedule the result_td. + * DE_ALLOCATE -if USB Transfer is completed. + */ +/******************************************************************************/ +static u8 process_control_transfer(struct td *result_td, + struct hc_info *hcinfo) +{ + hcintn_t hcintr_info; + u8 ret_val = 0; + + /* we just deal with the interrupts to be unmasked. */ + hcintr_info.d32 = hcinfo->hc_int.d32 & + result_td->cur_stransfer.hc_reg.hc_int_msk.d32; + + if (result_td->parent_ed_p->ed_desc.is_ep_in) { + if (hcintr_info.b.chhltd) + ret_val = process_chhltd_on_control(result_td, hcinfo); + + else if (hcintr_info.b.ack) + ret_val = process_ack_on_control(result_td, hcinfo); + + else if (hcintr_info.b.nak) + ret_val = process_nak_on_control(result_td, hcinfo); + + else if (hcintr_info.b.datatglerr) + ret_val = process_datatgl_on_control(result_td, hcinfo); + + } else { + + if (hcintr_info.b.chhltd) + ret_val = process_chhltd_on_control(result_td, hcinfo); + + else if (hcintr_info.b.ack) + ret_val = process_ack_on_control(result_td, hcinfo); + } + + return ret_val; +} + |