aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-common.c
blob: 689d379c58a5124abdb7db5423bd83a829137d9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/****************************************************************************
 *  (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
 *
 *  [File Name]   : CommonTransferChecker.c
 *  [Description] : The Source file implements the external and internal functions of CommonTransferChecker.
 *  [Author]      : Yang Soon Yeal { syatom.yang@samsung.com }
 *  [Department]  : System LSI Division/System SW Lab
 *  [Created Date]: 2009/01/12
 *  [Revision History]
 *      (1) 2008/06/12   by Yang Soon Yeal { syatom.yang@samsung.com }
 *          - Created this file and implements functions of CommonTransferChecker
 *
 ****************************************************************************/
/****************************************************************************
 * 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
 ****************************************************************************/

#include "s3c-otg-transferchecker-common.h"

/******************************************************************************/
/*!
 * @name	int  	init_done_transfer_checker(void)
 *
 * @brief		this function initiates S3CDoneTransferChecker Module.
 *
 *
 * @param	void
 *
 * @return	void
 */
/******************************************************************************/
//ss1
/*void		init_done_transfer_checker(void)
{
	return USB_ERR_SUCCESS;
}*/

/******************************************************************************/
/*!
 * @name	void  	do_transfer_checker(struct sec_otghost *otghost)
 *
 * @brief		this function processes the result of USB Transfer. So, do_transfer_checker fistly
 *			check which channel occurs OTG Interrupt and gets the status information of the channel.
 *			do_transfer_checker requests the information of td_t to S3CScheduler.
 *			To process the interrupt of the channel, do_transfer_checker calls the sub-modules of
 *			S3CDoneTransferChecker, for example, ControlTransferChecker, BulkTransferChecker.
 *			according to the process result of the channel interrupt, do_transfer_checker decides
 *			the USB Transfer will be done or retransmitted.
 *
 *
 * @param	void
 *
 * @return	void
 */
/*******************************************************************************/
void do_transfer_checker (struct sec_otghost *otghost)
__releases(&otghost->lock)
__acquires(&otghost->lock)
{
	u32 	hc_intr = 0;
	u32	hc_intr_msk = 0;
	u8	do_try_cnt = 0;

	hc_info_t	ch_info;
	u32	td_addr = 0;
	td_t 	*done_td = {0};
	u8	proc_result = 0;

	//by ss1
	otg_mem_set((void *)&ch_info, 0, sizeof(hc_info_t));

	// Get value of HAINT...
	get_intr_ch(&hc_intr,&hc_intr_msk);

start_do_transfer_checker:

	while(do_try_cnt<MAX_CH_NUMBER) {
		//checks the channel number to be masked or not.
		if(!(hc_intr & hc_intr_msk & (1<<do_try_cnt))) {
			do_try_cnt++;
			goto start_do_transfer_checker;
		}

		//Gets the address of the td_t to have the channel to be interrupted.
		if(get_td_info(do_try_cnt, &td_addr) == USB_ERR_SUCCESS) {

                        done_td = (td_t *)td_addr;

                        if(do_try_cnt != done_td->cur_stransfer.alloc_chnum) {
                                do_try_cnt++;
                                goto start_do_transfer_checker;
                        }
                }
	       	else {
                        do_try_cnt++;
                        goto start_do_transfer_checker;
                }

		//Gets the informationof channel to be interrupted.
		get_ch_info(&ch_info,do_try_cnt);

		switch(done_td->parent_ed_p->ed_desc.endpoint_type) {
		case CONTROL_TRANSFER:
			proc_result = process_control_transfer(done_td, &ch_info);
			break;
		case BULK_TRANSFER:
			proc_result = process_bulk_transfer(done_td, &ch_info);
			break;
		case INT_TRANSFER:
			proc_result = process_intr_transfer(done_td, &ch_info);
			break;
		case ISOCH_TRANSFER:
			/* proc_result = ProcessIsochTransfer(done_td, &ch_info); */
			break;
		default:break;
		}

		if((proc_result == RE_TRANSMIT) || (proc_result == RE_SCHEDULE)) {
			done_td->parent_ed_p->ed_status.is_in_transferring 	= 	false;
			done_td->is_transfer_done				= 	false;
			done_td->is_transferring				=	false;

			if(done_td->parent_ed_p->ed_desc.endpoint_type == CONTROL_TRANSFER ||
				done_td->parent_ed_p->ed_desc.endpoint_type==BULK_TRANSFER) {
				update_nonperio_stransfer(done_td);
			}
			else {
				update_perio_stransfer(done_td);
			}

			if(proc_result == RE_TRANSMIT) {
				retransmit(otghost, done_td);
			}
			else {
				reschedule(done_td);
			}
		}

		else if(proc_result==DE_ALLOCATE) {
			done_td->parent_ed_p->ed_status.is_in_transferring 	= 	false;
			done_td->parent_ed_p->ed_status.in_transferring_td	=	0;
			done_td->is_transfer_done				= 	true;
			done_td->is_transferring				=	false;

			spin_unlock_otg(&otghost->lock);
			otg_usbcore_giveback( done_td);
			spin_lock_otg(&otghost->lock);
			release_trans_resource(otghost, done_td);
		}
		else {	//NO_ACTION....
			done_td->parent_ed_p->ed_status.is_in_transferring 	= 	true;
			done_td->parent_ed_p->ed_status.in_transferring_td	=	(u32)done_td;
			done_td->is_transfer_done				= 	false;
			done_td->is_transferring				=	true;
		}
		do_try_cnt++;
	}
	// Complete to process the Channel Interrupt.
	// So. we now start to scheduler of S3CScheduler.
	do_schedule(otghost);
}


int release_trans_resource(struct sec_otghost *otghost, td_t *done_td)
{
	//remove the pDeallocateTD from parent_ed_p.
	otg_list_pop(&done_td->td_list_entry);
	done_td->parent_ed_p->num_td--;

	//Call deallocate to release the channel and bandwidth resource of S3CScheduler.
	deallocate(done_td);
	delete_td(otghost, done_td);
	return USB_ERR_SUCCESS;
}

u32 calc_transferred_size(bool f_is_complete, td_t *td, hc_info_t *hc_info)
{
	if(f_is_complete) {
		if(td->parent_ed_p->ed_desc.is_ep_in) {
			return td->cur_stransfer.buf_size - hc_info->hc_size.b.xfersize;
		}
		else {
			return	td->cur_stransfer.buf_size;
		}
	}
	else {
		return	(td->cur_stransfer.packet_cnt - hc_info->hc_size.b.pktcnt)*td->parent_ed_p->ed_desc.max_packet_size;
	}
}

void update_frame_number(td_t *pResultTD)
{
	u32 cur_frame_num=0;

	if(pResultTD->parent_ed_p->ed_desc.endpoint_type == CONTROL_TRANSFER ||
		pResultTD->parent_ed_p->ed_desc.endpoint_type == BULK_TRANSFER) {
		return;
	}

	pResultTD->parent_ed_p->ed_desc.sched_frame+= pResultTD->parent_ed_p->ed_desc.interval;
	pResultTD->parent_ed_p->ed_desc.sched_frame &= HFNUM_MAX_FRNUM;

	cur_frame_num = oci_get_frame_num();
	if(((cur_frame_num - pResultTD->parent_ed_p->ed_desc.sched_frame)&HFNUM_MAX_FRNUM) <= (HFNUM_MAX_FRNUM>>1)) {
		pResultTD->parent_ed_p->ed_desc.sched_frame = cur_frame_num;
	}
}

void update_datatgl(u8 ubCurDataTgl, td_t *td)
{
	switch(td->parent_ed_p->ed_desc.endpoint_type) {
	case CONTROL_TRANSFER:
		if(td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE) {
			td->parent_ed_p->ed_status.control_data_tgl.data_tgl = ubCurDataTgl;
		}
		break;
	case BULK_TRANSFER:
	case INT_TRANSFER:
		td->parent_ed_p->ed_status.data_tgl = ubCurDataTgl;
		break;

	case ISOCH_TRANSFER:
		break;
	default:break;
	}
}