1 /****************************************************************************
2 * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
4 * [File Name] : IntTransferChecker.c
5 * [Description] : The Source file implements the external and internal functions of IntTransferChecker
6 * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
7 * [Department] : System LSI Division/System SW Lab
8 * [Created Date]: 2008/06/19
10 * (1) 2008/06/18 by Yang Soon Yeal { syatom.yang@samsung.com }
11 * - Created this file and implements functions of IntTransferChecker
13 ****************************************************************************/
14 /****************************************************************************
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 ****************************************************************************/
31 #include "s3c-otg-transferchecker-interrupt.h"
33 /******************************************************************************/
35 * @name u8 process_intr_transfer(td_t *result_td,
36 * hc_info_t *HCRegData)
39 * @brief this function processes the result of the Interrupt Transfer.
40 * firstly, this function checks the result of the Interrupt Transfer.
41 * and according to the result, calls the sub-functions to process the result.
44 * @param [IN] result_td -indicates the pointer of the td_t whose channel is interruped.
45 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
47 * @return RE_TRANSMIT -if need to retransmit the result_td.
48 * RE_SCHEDULE -if need to reschedule the result_td.
49 * DE_ALLOCATE -if USB Transfer is completed.
50 * NO_ACTION -if we don't need any action,
52 /******************************************************************************/
53 u8 process_intr_transfer(td_t *result_td, hc_info_t *hc_reg_data)
55 hcintn_t hc_intr_info;
58 //we just deal with the interrupts to be unmasked.
59 hc_intr_info.d32 = hc_reg_data->hc_int.d32&result_td->cur_stransfer.hc_reg.hc_int_msk.d32;
61 if(result_td->parent_ed_p->ed_desc.is_ep_in) {
62 if(hc_intr_info.b.chhltd) {
63 ret_val = process_chhltd_on_intr(result_td, hc_reg_data);
66 else if (hc_intr_info.b.ack) {
67 ret_val = process_ack_on_intr(result_td, hc_reg_data);
71 if(hc_intr_info.b.chhltd) {
72 ret_val = process_chhltd_on_intr(result_td, hc_reg_data);
75 else if(hc_intr_info.b.ack) {
76 ret_val = process_ack_on_intr( result_td, hc_reg_data);
83 /******************************************************************************/
85 * @name u8 process_chhltd_on_intr(td_t *result_td,
86 * hc_info_t *HCRegData)
89 * @brief this function processes Channel Halt event according to Synopsys OTG Spec.
90 * firstly, this function checks the reason of the Channel Halt, and according to the reason,
91 * calls the sub-functions to process the result.
94 * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
95 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
97 * @return RE_TRANSMIT -if need to retransmit the result_td.
98 * RE_SCHEDULE -if need to reschedule the result_td.
99 * DE_ALLOCATE -if USB Transfer is completed.
101 /******************************************************************************/
102 u8 process_chhltd_on_intr(td_t *result_td,
103 hc_info_t *hc_reg_data)
105 if(result_td->parent_ed_p->ed_desc.is_ep_in)
107 if(hc_reg_data->hc_int.b.xfercompl)
109 return process_xfercompl_on_intr( result_td, hc_reg_data);
111 else if(hc_reg_data->hc_int.b.stall)
113 return process_stall_on_intr(result_td, hc_reg_data);
115 else if(hc_reg_data->hc_int.b.bblerr)
117 return process_bblerr_on_intr(result_td, hc_reg_data);
119 else if (hc_reg_data->hc_int.b.nak)
121 return process_nak_on_intr(result_td, hc_reg_data);
123 else if(hc_reg_data->hc_int.b.datatglerr)
125 return process_datatgl_on_intr(result_td, hc_reg_data);
127 else if(hc_reg_data->hc_int.b.frmovrun)
129 return process_frmovrrun_on_intr(result_td,hc_reg_data);
131 else if(hc_reg_data->hc_int.b.xacterr)
133 return process_xacterr_on_intr(result_td, hc_reg_data);
137 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
139 //Mask ack Interrupt..
140 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
141 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
142 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
148 if(hc_reg_data->hc_int.b.xfercompl)
150 return process_xfercompl_on_intr( result_td, hc_reg_data);
152 else if(hc_reg_data->hc_int.b.stall)
154 return process_stall_on_intr(result_td, hc_reg_data);
156 else if (hc_reg_data->hc_int.b.nak)
158 return process_nak_on_intr(result_td, hc_reg_data);
160 else if(hc_reg_data->hc_int.b.frmovrun)
162 return process_frmovrrun_on_intr(result_td,hc_reg_data);
164 else if(hc_reg_data->hc_int.b.xacterr)
166 return process_xacterr_on_intr(result_td, hc_reg_data);
170 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
172 //Mask ack Interrupt..
173 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
174 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
175 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
177 result_td->err_cnt++;
178 if(result_td->err_cnt == 3)
180 result_td->error_code = USB_ERR_STATUS_XACTERR;
181 result_td->err_cnt = 0;
193 /******************************************************************************/
195 * @name u8 process_xfercompl_on_intr( td_t *result_td,
196 * hc_info_t *hc_reg_data)
199 * @brief this function deals with the xfercompl event according to Synopsys OTG Spec.
200 * the procedure of this function is as following
201 * 1. clears all bits of the channel' HCINT by using clear_ch_intr() of S3CIsr.
202 * 2. masks ack/nak(?)/datatglerr(?) bit of HCINTMSK
203 * 3. Resets the err_cnt of result_td.
204 * 4. updates the result_td->parent_ed_p->ed_status.
206 * 5. calculates the tranferred size by calling calc_transferred_size() on DATA_STAGE.
208 * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
209 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
211 * @return DE_ALLOCATE -if USB Transfer is completed.
212 * RE_TRANSMIT -if need to retransmit the result_td.
214 /******************************************************************************/
215 u8 process_xfercompl_on_intr( td_t *result_td,
216 hc_info_t *hc_reg_data)
220 result_td->err_cnt =0;
222 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
224 //Mask ack Interrupt..
225 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
226 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
227 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
229 result_td->transferred_szie += calc_transferred_size(true,result_td, hc_reg_data);
231 if(result_td->transferred_szie==result_td->buf_size)
232 {//at IN Transfer, short transfer is accepted.
233 result_td->error_code = USB_ERR_STATUS_COMPLETE;
234 ret_val = DE_ALLOCATE;
238 // this routine will not be executed on Interrupt Transfer.
239 // So, we should decide to remove this routine or not.
240 if(result_td->parent_ed_p->ed_desc.is_ep_in&& hc_reg_data->hc_size.b.xfersize)
242 if(result_td->transfer_flag&USB_TRANS_FLAG_NOT_SHORT)
244 result_td->error_code = USB_ERR_STATUS_SHORTREAD;
248 result_td->error_code = USB_ERR_STATUS_COMPLETE;
250 ret_val = DE_ALLOCATE;
253 { // the Data Stage is not completed. So we need to continue Data Stage.
254 update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
255 ret_val = RE_TRANSMIT;
259 update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
265 /******************************************************************************/
267 * @name u8 process_ahb_on_intr(td_t *result_td,
268 * hc_info_t *hc_reg_data)
271 * @brief this function deals with theAHB Errorl event according to Synopsys OTG Spec.
272 * this function stop the channel to be executed
275 * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
276 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
278 * @return DE_ALLOCATE
280 /******************************************************************************/
281 u8 process_ahb_on_intr(td_t *result_td,
282 hc_info_t *hc_reg_data)
284 result_td->err_cnt = 0;
285 result_td->error_code = USB_ERR_STATUS_AHBERR;
287 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_AHBErr);
289 //Mask ack Interrupt..
290 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
291 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
292 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
294 // we just calculate the size of the transferred data on Data Stage of Int Transfer.
295 result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
296 result_td->parent_ed_p->ed_status.is_ping_enable =false;
302 /******************************************************************************/
304 * @name u8 process_stall_on_intr(td_t *result_td,
305 * hc_info_t *hc_reg_data)
308 * @brief this function deals with the Stall event according to Synopsys OTG Spec.
309 * when Stall is occured at Int Transfer, we should reset the PID as DATA0
311 * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
312 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
314 * @return DE_ALLOCATE
316 /******************************************************************************/
317 u8 process_stall_on_intr(td_t *result_td,
318 hc_info_t *hc_reg_data)
320 result_td->err_cnt = 0;
321 result_td->error_code = USB_ERR_STATUS_STALL;
323 //this channel is stalled, So we don't process another interrupts.
324 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
326 //Mask ack Interrupt..
327 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
328 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
329 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
331 result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
333 update_datatgl(DATA0, result_td);
338 /******************************************************************************/
340 * @name u8 process_nak_on_intr(td_t *result_td,
341 * hc_info_t *hc_reg_data)
344 * @brief this function deals with the nak event according to Synopsys OTG Spec.
345 * nak is occured at OUT/IN Transaction of Interrupt Transfer.
346 * we can't use ping protocol on Interrupt Transfer. and Syonopsys OTG IP occures
347 * chhltd interrupt on nak of IN/OUT Transaction. So we should retransmit the transfer
349 * If nak is occured at IN Transaction, this function processes this interrupt as following.
350 * 1. resets the result_td->err_cnt.
351 * 2. masks ack/nak/DaaTglErr bit of HCINTMSK.
352 * 3. clears the nak bit of HCINT
353 * 4. calculates frame number to retransmit this Interrupt Transfer.
355 * If nak is occured at OUT Transaction, this function processes this interrupt as following.
356 * 1. all procedures of IN Transaction are executed.
357 * 2. calculates the size of the transferred data.
358 * 3. if the speed of USB Device is High-Speed, sets the ping protocol.
359 * 4. update the Toggle
360 * at OUT Transaction, this function check whether the speed of USB Device is High-Speed or not.
361 * if USB Device is High-Speed, then
362 * this function sets the ping protocol.
364 * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
365 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
367 * @return RE_SCHEDULE -if the direction of the Transfer is OUT
368 * NO_ACTION -if the direction of the Transfer is IN
370 /******************************************************************************/
371 u8 process_nak_on_intr(td_t *result_td,
372 hc_info_t *hc_reg_data)
374 result_td->err_cnt = 0;
376 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
377 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
378 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
380 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
383 result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
385 update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
387 update_frame_number(result_td);
390 // return RE_TRANSMIT;
395 /******************************************************************************/
397 * @name u8 process_ack_on_intr(td_t *result_td,
398 * hc_info_t *hc_reg_data)
401 * @brief this function deals with the ack event according to Synopsys OTG Spec.
402 * ack of IN/OUT Transaction don't need any retransmit.
403 * this function just resets result_td->err_cnt and masks ack/nak/DataTgl of HCINTMSK.
404 * finally, this function clears ack bit of HCINT and ed_status.is_ping_enable.
406 * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
407 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
411 /******************************************************************************/
412 u8 process_ack_on_intr(td_t *result_td,
413 hc_info_t *hc_reg_data)
415 result_td->err_cnt = 0;
417 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
418 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
419 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
421 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
426 /******************************************************************************/
428 * @name u8 process_xacterr_on_intr(td_t *result_td,
429 * hc_info_t *hc_reg_data)
431 * @brief this function deals with the xacterr event according to Synopsys OTG Spec.
432 * xacterr is occured at OUT/IN Transaction and we should retransmit the USB Transfer
433 * if the Error Counter is less than the RETRANSMIT_THRESHOLD.
434 * the reasons of xacterr is Timeout/CRC error/false EOP.
435 * the procedure to process xacterr is as following.
436 * 1. increses the result_td->err_cnt
437 * 2. check whether the result_td->err_cnt is equal to 3.
438 * 2. unmasks ack/nak/datatglerr bit of HCINTMSK.
439 * 3. clears the xacterr bit of HCINT
440 * 4. calculates the size of the transferred data.
441 * 5. update the Data Toggle.
442 * 6. update the frame number to start retransmitting the Interrupt Transfer.
444 * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
445 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
447 * @return RE_SCHEDULE -if the error count is less than 3
448 * DE_ALLOCATE -if the error count is equal to 3
450 /******************************************************************************/
451 u8 process_xacterr_on_intr(td_t *result_td,
452 hc_info_t *hc_reg_data)
456 if(result_td->err_cnt<RETRANSMIT_THRESHOLD)
458 result_td->cur_stransfer.hc_reg.hc_int_msk.d32 |=(CH_STATUS_ACK+CH_STATUS_NAK+CH_STATUS_DataTglErr);
459 ret_val = RE_SCHEDULE;
460 result_td->err_cnt++ ;
464 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
465 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
466 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
467 ret_val = DE_ALLOCATE;
468 result_td->err_cnt = 0 ;
471 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
473 result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
475 update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
477 if(ret_val == RE_SCHEDULE)
478 { //Calculates the frame number
479 update_frame_number(result_td);
485 /******************************************************************************/
487 * @name void process_bblerr_on_intr(td_t *result_td,
488 * hc_info_t *hc_reg_data)
491 * @brief this function deals with the Babble event according to Synopsys OTG Spec.
492 * babble error is occured when the USB device continues to send packets
493 * althrough EOP is occured. So Babble error is only occured at IN Transfer.
494 * when Babble Error is occured, we should stop the USB Transfer, and return the fact
497 * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
498 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
500 * @return DE_ALLOCATE
502 /******************************************************************************/
503 u8 process_bblerr_on_intr(td_t *result_td,
504 hc_info_t *hc_reg_data)
507 if(!result_td->parent_ed_p->ed_desc.is_ep_in)
512 result_td->err_cnt = 0;
513 result_td->error_code =USB_ERR_STATUS_BBLERR;
515 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
517 //Mask ack Interrupt..
518 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
519 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
520 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
522 result_td->transferred_szie += calc_transferred_size(false, result_td, hc_reg_data);
526 /******************************************************************************/
528 * @name u8 process_datatgl_on_intr( td_t *result_td,
529 * hc_info_t *hc_reg_data)
531 * @brief this function deals with the datatglerr event according to Synopsys OTG Spec.
532 * the datatglerr event is occured at IN Transfer, and the channel is not halted.
533 * this function just resets result_td->err_cnt and masks ack/nak/DataTgl of HCINTMSK.
534 * finally, this function clears datatglerr bit of HCINT.
536 * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
537 * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
539 * @return RE_SCHEDULE
541 /******************************************************************************/
542 u8 process_datatgl_on_intr(td_t *result_td,
543 hc_info_t *hc_reg_data)
545 result_td->err_cnt = 0;
547 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
548 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
549 mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
551 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
553 result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
555 update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
557 update_frame_number(result_td);
562 u8 process_frmovrrun_on_intr(td_t *result_td,
563 hc_info_t *hc_reg_data)
566 clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
568 update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
570 update_frame_number(result_td);