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
12struct debugifc_mask_item {
13 const char *name;
14 unsigned long msk;
15};
16
17
18static 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
35static 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
51static 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
79static 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(ch: *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
105static 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(p: buf,q: keyword,size: kl);
113}
114
115
116int 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, size: acnt, fmt: "Driver hardware description: %s\n",
121 pvr2_hdw_get_desc(hdw));
122 bcnt += ccnt; acnt -= ccnt; buf += ccnt;
123 ccnt = scnprintf(buf,size: acnt,fmt: "Driver state info:\n");
124 bcnt += ccnt; acnt -= ccnt; buf += ccnt;
125 ccnt = pvr2_hdw_state_report(hdw,buf_ptr: buf,buf_size: acnt);
126 bcnt += ccnt; acnt -= ccnt; buf += ccnt;
127
128 return bcnt;
129}
130
131
132int 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,size: acnt,fmt: "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,size: acnt,fmt: "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,size: acnt,fmt: "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, zero_counts: 0);
163 ccnt = scnprintf(
164 buf,size: acnt,
165 fmt: "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
179static 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,wstrPtr: &wptr,wlenPtr: &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(buf: wptr,count: wlen,keyword: "reset")) {
193 scnt = debugifc_isolate_word(buf,count,wstrPtr: &wptr,wlenPtr: &wlen);
194 if (!scnt) return -EINVAL;
195 count -= scnt; buf += scnt;
196 if (!wptr) return -EINVAL;
197 if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "cpu")) {
198 pvr2_hdw_cpureset_assert(hdw,!0);
199 pvr2_hdw_cpureset_assert(hdw,0);
200 return 0;
201 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "bus")) {
202 pvr2_hdw_device_reset(hdw);
203 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "soft")) {
204 return pvr2_hdw_cmd_powerup(hdw);
205 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "deep")) {
206 return pvr2_hdw_cmd_deep_reset(hdw);
207 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "firmware")) {
208 return pvr2_upload_firmware2(hdw);
209 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "decoder")) {
210 return pvr2_hdw_cmd_decoder_reset(hdw);
211 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "worker")) {
212 return pvr2_hdw_untrip(hdw);
213 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "usbstats")) {
214 pvr2_stream_get_stats(pvr2_hdw_get_video_stream(hdw),
215 NULL, zero_counts: !0);
216 return 0;
217 }
218 return -EINVAL;
219 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "cpufw")) {
220 scnt = debugifc_isolate_word(buf,count,wstrPtr: &wptr,wlenPtr: &wlen);
221 if (!scnt) return -EINVAL;
222 count -= scnt; buf += scnt;
223 if (!wptr) return -EINVAL;
224 if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "fetch")) {
225 scnt = debugifc_isolate_word(buf,count,wstrPtr: &wptr,wlenPtr: &wlen);
226 if (scnt && wptr) {
227 count -= scnt; buf += scnt;
228 if (debugifc_match_keyword(buf: wptr, count: wlen,
229 keyword: "prom")) {
230 pvr2_hdw_cpufw_set_enabled(hdw, mode: 2, enable_flag: !0);
231 } else if (debugifc_match_keyword(buf: wptr, count: wlen,
232 keyword: "ram8k")) {
233 pvr2_hdw_cpufw_set_enabled(hdw, mode: 0, enable_flag: !0);
234 } else if (debugifc_match_keyword(buf: wptr, count: wlen,
235 keyword: "ram16k")) {
236 pvr2_hdw_cpufw_set_enabled(hdw, mode: 1, enable_flag: !0);
237 } else {
238 return -EINVAL;
239 }
240 }
241 pvr2_hdw_cpufw_set_enabled(hdw,mode: 0,enable_flag: !0);
242 return 0;
243 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "done")) {
244 pvr2_hdw_cpufw_set_enabled(hdw,mode: 0,enable_flag: 0);
245 return 0;
246 } else {
247 return -EINVAL;
248 }
249 } else if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "gpio")) {
250 int dir_fl = 0;
251 int ret;
252 u32 msk,val;
253 scnt = debugifc_isolate_word(buf,count,wstrPtr: &wptr,wlenPtr: &wlen);
254 if (!scnt) return -EINVAL;
255 count -= scnt; buf += scnt;
256 if (!wptr) return -EINVAL;
257 if (debugifc_match_keyword(buf: wptr,count: wlen,keyword: "dir")) {
258 dir_fl = !0;
259 } else if (!debugifc_match_keyword(buf: wptr,count: wlen,keyword: "out")) {
260 return -EINVAL;
261 }
262 scnt = debugifc_isolate_word(buf,count,wstrPtr: &wptr,wlenPtr: &wlen);
263 if (!scnt) return -EINVAL;
264 count -= scnt; buf += scnt;
265 if (!wptr) return -EINVAL;
266 ret = debugifc_parse_unsigned_number(buf: wptr,count: wlen,num_ptr: &msk);
267 if (ret) return ret;
268 scnt = debugifc_isolate_word(buf,count,wstrPtr: &wptr,wlenPtr: &wlen);
269 if (wptr) {
270 ret = debugifc_parse_unsigned_number(buf: wptr,count: wlen,num_ptr: &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
289int 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,count: 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

source code of linux/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c