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