1 /*
2  *
3  *
4  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  */
16 
17 #include <linux/string.h>
18 #include "pvrusb2-debugifc.h"
19 #include "pvrusb2-hdw.h"
20 #include "pvrusb2-debug.h"
21 
22 struct debugifc_mask_item {
23 	const char *name;
24 	unsigned long msk;
25 };
26 
27 
28 static unsigned int debugifc_count_whitespace(const char *buf,
29 					      unsigned int count)
30 {
31 	unsigned int scnt;
32 	char ch;
33 
34 	for (scnt = 0; scnt < count; scnt++) {
35 		ch = buf[scnt];
36 		if (ch == ' ') continue;
37 		if (ch == '\t') continue;
38 		if (ch == '\n') continue;
39 		break;
40 	}
41 	return scnt;
42 }
43 
44 
45 static unsigned int debugifc_count_nonwhitespace(const char *buf,
46 						 unsigned int count)
47 {
48 	unsigned int scnt;
49 	char ch;
50 
51 	for (scnt = 0; scnt < count; scnt++) {
52 		ch = buf[scnt];
53 		if (ch == ' ') break;
54 		if (ch == '\t') break;
55 		if (ch == '\n') break;
56 	}
57 	return scnt;
58 }
59 
60 
61 static unsigned int debugifc_isolate_word(const char *buf,unsigned int count,
62 					  const char **wstrPtr,
63 					  unsigned int *wlenPtr)
64 {
65 	const char *wptr;
66 	unsigned int consume_cnt = 0;
67 	unsigned int wlen;
68 	unsigned int scnt;
69 
70 	wptr = NULL;
71 	wlen = 0;
72 	scnt = debugifc_count_whitespace(buf,count);
73 	consume_cnt += scnt; count -= scnt; buf += scnt;
74 	if (!count) goto done;
75 
76 	scnt = debugifc_count_nonwhitespace(buf,count);
77 	if (!scnt) goto done;
78 	wptr = buf;
79 	wlen = scnt;
80 	consume_cnt += scnt; count -= scnt; buf += scnt;
81 
82  done:
83 	*wstrPtr = wptr;
84 	*wlenPtr = wlen;
85 	return consume_cnt;
86 }
87 
88 
89 static int debugifc_parse_unsigned_number(const char *buf,unsigned int count,
90 					  u32 *num_ptr)
91 {
92 	u32 result = 0;
93 	int radix = 10;
94 	if ((count >= 2) && (buf[0] == '0') &&
95 	    ((buf[1] == 'x') || (buf[1] == 'X'))) {
96 		radix = 16;
97 		count -= 2;
98 		buf += 2;
99 	} else if ((count >= 1) && (buf[0] == '0')) {
100 		radix = 8;
101 	}
102 
103 	while (count--) {
104 		int val = hex_to_bin(*buf++);
105 		if (val < 0 || val >= radix)
106 			return -EINVAL;
107 		result *= radix;
108 		result += val;
109 	}
110 	*num_ptr = result;
111 	return 0;
112 }
113 
114 
115 static int debugifc_match_keyword(const char *buf,unsigned int count,
116 				  const char *keyword)
117 {
118 	unsigned int kl;
119 	if (!keyword) return 0;
120 	kl = strlen(keyword);
121 	if (kl != count) return 0;
122 	return !memcmp(buf,keyword,kl);
123 }
124 
125 
126 int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
127 {
128 	int bcnt = 0;
129 	int ccnt;
130 	ccnt = scnprintf(buf, acnt, "Driver hardware description: %s\n",
131 			 pvr2_hdw_get_desc(hdw));
132 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
133 	ccnt = scnprintf(buf,acnt,"Driver state info:\n");
134 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
135 	ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
136 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
137 
138 	return bcnt;
139 }
140 
141 
142 int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
143 			       char *buf,unsigned int acnt)
144 {
145 	int bcnt = 0;
146 	int ccnt;
147 	int ret;
148 	u32 gpio_dir,gpio_in,gpio_out;
149 	struct pvr2_stream_stats stats;
150 	struct pvr2_stream *sp;
151 
152 	ret = pvr2_hdw_is_hsm(hdw);
153 	ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
154 			 (ret < 0 ? "FAIL" : (ret ? "high" : "full")));
155 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
156 
157 	gpio_dir = 0; gpio_in = 0; gpio_out = 0;
158 	pvr2_hdw_gpio_get_dir(hdw,&gpio_dir);
159 	pvr2_hdw_gpio_get_out(hdw,&gpio_out);
160 	pvr2_hdw_gpio_get_in(hdw,&gpio_in);
161 	ccnt = scnprintf(buf,acnt,"GPIO state: dir=0x%x in=0x%x out=0x%x\n",
162 			 gpio_dir,gpio_in,gpio_out);
163 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
164 
165 	ccnt = scnprintf(buf,acnt,"Streaming is %s\n",
166 			 pvr2_hdw_get_streaming(hdw) ? "on" : "off");
167 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
168 
169 
170 	sp = pvr2_hdw_get_video_stream(hdw);
171 	if (sp) {
172 		pvr2_stream_get_stats(sp, &stats, 0);
173 		ccnt = scnprintf(
174 			buf,acnt,
175 			"Bytes streamed=%u URBs: queued=%u idle=%u ready=%u processed=%u failed=%u\n",
176 			stats.bytes_processed,
177 			stats.buffers_in_queue,
178 			stats.buffers_in_idle,
179 			stats.buffers_in_ready,
180 			stats.buffers_processed,
181 			stats.buffers_failed);
182 		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
183 	}
184 
185 	return bcnt;
186 }
187 
188 
189 static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
190 				unsigned int count)
191 {
192 	const char *wptr;
193 	unsigned int wlen;
194 	unsigned int scnt;
195 
196 	scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
197 	if (!scnt) return 0;
198 	count -= scnt; buf += scnt;
199 	if (!wptr) return 0;
200 
201 	pvr2_trace(PVR2_TRACE_DEBUGIFC,"debugifc cmd: \"%.*s\"",wlen,wptr);
202 	if (debugifc_match_keyword(wptr,wlen,"reset")) {
203 		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
204 		if (!scnt) return -EINVAL;
205 		count -= scnt; buf += scnt;
206 		if (!wptr) return -EINVAL;
207 		if (debugifc_match_keyword(wptr,wlen,"cpu")) {
208 			pvr2_hdw_cpureset_assert(hdw,!0);
209 			pvr2_hdw_cpureset_assert(hdw,0);
210 			return 0;
211 		} else if (debugifc_match_keyword(wptr,wlen,"bus")) {
212 			pvr2_hdw_device_reset(hdw);
213 		} else if (debugifc_match_keyword(wptr,wlen,"soft")) {
214 			return pvr2_hdw_cmd_powerup(hdw);
215 		} else if (debugifc_match_keyword(wptr,wlen,"deep")) {
216 			return pvr2_hdw_cmd_deep_reset(hdw);
217 		} else if (debugifc_match_keyword(wptr,wlen,"firmware")) {
218 			return pvr2_upload_firmware2(hdw);
219 		} else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
220 			return pvr2_hdw_cmd_decoder_reset(hdw);
221 		} else if (debugifc_match_keyword(wptr,wlen,"worker")) {
222 			return pvr2_hdw_untrip(hdw);
223 		} else if (debugifc_match_keyword(wptr,wlen,"usbstats")) {
224 			pvr2_stream_get_stats(pvr2_hdw_get_video_stream(hdw),
225 					      NULL, !0);
226 			return 0;
227 		}
228 		return -EINVAL;
229 	} else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
230 		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
231 		if (!scnt) return -EINVAL;
232 		count -= scnt; buf += scnt;
233 		if (!wptr) return -EINVAL;
234 		if (debugifc_match_keyword(wptr,wlen,"fetch")) {
235 			scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
236 			if (scnt && wptr) {
237 				count -= scnt; buf += scnt;
238 				if (debugifc_match_keyword(wptr, wlen,
239 							   "prom")) {
240 					pvr2_hdw_cpufw_set_enabled(hdw, 2, !0);
241 				} else if (debugifc_match_keyword(wptr, wlen,
242 								  "ram8k")) {
243 					pvr2_hdw_cpufw_set_enabled(hdw, 0, !0);
244 				} else if (debugifc_match_keyword(wptr, wlen,
245 								  "ram16k")) {
246 					pvr2_hdw_cpufw_set_enabled(hdw, 1, !0);
247 				} else {
248 					return -EINVAL;
249 				}
250 			}
251 			pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
252 			return 0;
253 		} else if (debugifc_match_keyword(wptr,wlen,"done")) {
254 			pvr2_hdw_cpufw_set_enabled(hdw,0,0);
255 			return 0;
256 		} else {
257 			return -EINVAL;
258 		}
259 	} else if (debugifc_match_keyword(wptr,wlen,"gpio")) {
260 		int dir_fl = 0;
261 		int ret;
262 		u32 msk,val;
263 		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
264 		if (!scnt) return -EINVAL;
265 		count -= scnt; buf += scnt;
266 		if (!wptr) return -EINVAL;
267 		if (debugifc_match_keyword(wptr,wlen,"dir")) {
268 			dir_fl = !0;
269 		} else if (!debugifc_match_keyword(wptr,wlen,"out")) {
270 			return -EINVAL;
271 		}
272 		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
273 		if (!scnt) return -EINVAL;
274 		count -= scnt; buf += scnt;
275 		if (!wptr) return -EINVAL;
276 		ret = debugifc_parse_unsigned_number(wptr,wlen,&msk);
277 		if (ret) return ret;
278 		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
279 		if (wptr) {
280 			ret = debugifc_parse_unsigned_number(wptr,wlen,&val);
281 			if (ret) return ret;
282 		} else {
283 			val = msk;
284 			msk = 0xffffffff;
285 		}
286 		if (dir_fl) {
287 			ret = pvr2_hdw_gpio_chg_dir(hdw,msk,val);
288 		} else {
289 			ret = pvr2_hdw_gpio_chg_out(hdw,msk,val);
290 		}
291 		return ret;
292 	}
293 	pvr2_trace(PVR2_TRACE_DEBUGIFC,
294 		   "debugifc failed to recognize cmd: \"%.*s\"",wlen,wptr);
295 	return -EINVAL;
296 }
297 
298 
299 int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf,
300 			unsigned int count)
301 {
302 	unsigned int bcnt = 0;
303 	int ret;
304 
305 	while (count) {
306 		for (bcnt = 0; bcnt < count; bcnt++) {
307 			if (buf[bcnt] == '\n') break;
308 		}
309 
310 		ret = pvr2_debugifc_do1cmd(hdw,buf,bcnt);
311 		if (ret < 0) return ret;
312 		if (bcnt < count) bcnt++;
313 		buf += bcnt;
314 		count -= bcnt;
315 	}
316 
317 	return 0;
318 }
319