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