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 } 319