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