GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / media / usb / pvrusb2 / pvrusb2-debugifc.c
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 }