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