1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (C) 2005 Mike Isely <isely@pobox.com> 5 */ 6 7 #include <linux/hex.h> 8 #include <linux/string.h> 9 #include "pvrusb2-debugifc.h" 10 #include "pvrusb2-hdw.h" 11 #include "pvrusb2-debug.h" 12 13 14 static unsigned int debugifc_count_whitespace(const char *buf, 15 unsigned int count) 16 { 17 unsigned int scnt; 18 char ch; 19 20 for (scnt = 0; scnt < count; scnt++) { 21 ch = buf[scnt]; 22 if (ch == ' ') continue; 23 if (ch == '\t') continue; 24 if (ch == '\n') continue; 25 break; 26 } 27 return scnt; 28 } 29 30 31 static unsigned int debugifc_count_nonwhitespace(const char *buf, 32 unsigned int count) 33 { 34 unsigned int scnt; 35 char ch; 36 37 for (scnt = 0; scnt < count; scnt++) { 38 ch = buf[scnt]; 39 if (ch == ' ') break; 40 if (ch == '\t') break; 41 if (ch == '\n') break; 42 } 43 return scnt; 44 } 45 46 47 static unsigned int debugifc_isolate_word(const char *buf,unsigned int count, 48 const char **wstrPtr, 49 unsigned int *wlenPtr) 50 { 51 const char *wptr; 52 unsigned int consume_cnt = 0; 53 unsigned int wlen; 54 unsigned int scnt; 55 56 wptr = NULL; 57 wlen = 0; 58 scnt = debugifc_count_whitespace(buf,count); 59 consume_cnt += scnt; count -= scnt; buf += scnt; 60 if (!count) goto done; 61 62 scnt = debugifc_count_nonwhitespace(buf,count); 63 if (!scnt) goto done; 64 wptr = buf; 65 wlen = scnt; 66 consume_cnt += scnt; count -= scnt; buf += scnt; 67 68 done: 69 *wstrPtr = wptr; 70 *wlenPtr = wlen; 71 return consume_cnt; 72 } 73 74 75 static int debugifc_parse_unsigned_number(const char *buf,unsigned int count, 76 u32 *num_ptr) 77 { 78 u32 result = 0; 79 int radix = 10; 80 if ((count >= 2) && (buf[0] == '0') && 81 ((buf[1] == 'x') || (buf[1] == 'X'))) { 82 radix = 16; 83 count -= 2; 84 buf += 2; 85 } else if ((count >= 1) && (buf[0] == '0')) { 86 radix = 8; 87 } 88 89 while (count--) { 90 int val = hex_to_bin(*buf++); 91 if (val < 0 || val >= radix) 92 return -EINVAL; 93 result *= radix; 94 result += val; 95 } 96 *num_ptr = result; 97 return 0; 98 } 99 100 101 static int debugifc_match_keyword(const char *buf,unsigned int count, 102 const char *keyword) 103 { 104 unsigned int kl; 105 if (!keyword) return 0; 106 kl = strlen(keyword); 107 if (kl != count) return 0; 108 return !memcmp(buf,keyword,kl); 109 } 110 111 112 int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt) 113 { 114 int bcnt = 0; 115 int ccnt; 116 ccnt = scnprintf(buf, acnt, "Driver hardware description: %s\n", 117 pvr2_hdw_get_desc(hdw)); 118 bcnt += ccnt; acnt -= ccnt; buf += ccnt; 119 ccnt = scnprintf(buf,acnt,"Driver state info:\n"); 120 bcnt += ccnt; acnt -= ccnt; buf += ccnt; 121 ccnt = pvr2_hdw_state_report(hdw,buf,acnt); 122 bcnt += ccnt; acnt -= ccnt; buf += ccnt; 123 124 return bcnt; 125 } 126 127 128 int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, 129 char *buf,unsigned int acnt) 130 { 131 int bcnt = 0; 132 int ccnt; 133 int ret; 134 u32 gpio_dir,gpio_in,gpio_out; 135 struct pvr2_stream_stats stats; 136 struct pvr2_stream *sp; 137 138 ret = pvr2_hdw_is_hsm(hdw); 139 ccnt = scnprintf(buf,acnt,"USB link speed: %s\n", 140 (ret < 0 ? "FAIL" : (ret ? "high" : "full"))); 141 bcnt += ccnt; acnt -= ccnt; buf += ccnt; 142 143 gpio_dir = 0; gpio_in = 0; gpio_out = 0; 144 pvr2_hdw_gpio_get_dir(hdw,&gpio_dir); 145 pvr2_hdw_gpio_get_out(hdw,&gpio_out); 146 pvr2_hdw_gpio_get_in(hdw,&gpio_in); 147 ccnt = scnprintf(buf,acnt,"GPIO state: dir=0x%x in=0x%x out=0x%x\n", 148 gpio_dir,gpio_in,gpio_out); 149 bcnt += ccnt; acnt -= ccnt; buf += ccnt; 150 151 ccnt = scnprintf(buf,acnt,"Streaming is %s\n", 152 pvr2_hdw_get_streaming(hdw) ? "on" : "off"); 153 bcnt += ccnt; acnt -= ccnt; buf += ccnt; 154 155 156 sp = pvr2_hdw_get_video_stream(hdw); 157 if (sp) { 158 pvr2_stream_get_stats(sp, &stats, 0); 159 ccnt = scnprintf( 160 buf,acnt, 161 "Bytes streamed=%u URBs: queued=%u idle=%u ready=%u processed=%u failed=%u\n", 162 stats.bytes_processed, 163 stats.buffers_in_queue, 164 stats.buffers_in_idle, 165 stats.buffers_in_ready, 166 stats.buffers_processed, 167 stats.buffers_failed); 168 bcnt += ccnt; acnt -= ccnt; buf += ccnt; 169 } 170 171 return bcnt; 172 } 173 174 175 static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, 176 unsigned int count) 177 { 178 const char *wptr; 179 unsigned int wlen; 180 unsigned int scnt; 181 182 scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); 183 if (!scnt) return 0; 184 count -= scnt; buf += scnt; 185 if (!wptr) return 0; 186 187 pvr2_trace(PVR2_TRACE_DEBUGIFC,"debugifc cmd: \"%.*s\"",wlen,wptr); 188 if (debugifc_match_keyword(wptr,wlen,"reset")) { 189 scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); 190 if (!scnt) return -EINVAL; 191 count -= scnt; buf += scnt; 192 if (!wptr) return -EINVAL; 193 if (debugifc_match_keyword(wptr,wlen,"cpu")) { 194 pvr2_hdw_cpureset_assert(hdw,!0); 195 pvr2_hdw_cpureset_assert(hdw,0); 196 return 0; 197 } else if (debugifc_match_keyword(wptr,wlen,"bus")) { 198 pvr2_hdw_device_reset(hdw); 199 } else if (debugifc_match_keyword(wptr,wlen,"soft")) { 200 return pvr2_hdw_cmd_powerup(hdw); 201 } else if (debugifc_match_keyword(wptr,wlen,"deep")) { 202 return pvr2_hdw_cmd_deep_reset(hdw); 203 } else if (debugifc_match_keyword(wptr,wlen,"firmware")) { 204 return pvr2_upload_firmware2(hdw); 205 } else if (debugifc_match_keyword(wptr,wlen,"decoder")) { 206 return pvr2_hdw_cmd_decoder_reset(hdw); 207 } else if (debugifc_match_keyword(wptr,wlen,"worker")) { 208 return pvr2_hdw_untrip(hdw); 209 } else if (debugifc_match_keyword(wptr,wlen,"usbstats")) { 210 pvr2_stream_get_stats(pvr2_hdw_get_video_stream(hdw), 211 NULL, !0); 212 return 0; 213 } 214 return -EINVAL; 215 } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) { 216 scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); 217 if (!scnt) return -EINVAL; 218 count -= scnt; buf += scnt; 219 if (!wptr) return -EINVAL; 220 if (debugifc_match_keyword(wptr,wlen,"fetch")) { 221 scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); 222 if (scnt && wptr) { 223 count -= scnt; buf += scnt; 224 if (debugifc_match_keyword(wptr, wlen, 225 "prom")) { 226 pvr2_hdw_cpufw_set_enabled(hdw, 2, !0); 227 } else if (debugifc_match_keyword(wptr, wlen, 228 "ram8k")) { 229 pvr2_hdw_cpufw_set_enabled(hdw, 0, !0); 230 } else if (debugifc_match_keyword(wptr, wlen, 231 "ram16k")) { 232 pvr2_hdw_cpufw_set_enabled(hdw, 1, !0); 233 } else { 234 return -EINVAL; 235 } 236 } 237 pvr2_hdw_cpufw_set_enabled(hdw,0,!0); 238 return 0; 239 } else if (debugifc_match_keyword(wptr,wlen,"done")) { 240 pvr2_hdw_cpufw_set_enabled(hdw,0,0); 241 return 0; 242 } else { 243 return -EINVAL; 244 } 245 } else if (debugifc_match_keyword(wptr,wlen,"gpio")) { 246 int dir_fl = 0; 247 int ret; 248 u32 msk,val; 249 scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); 250 if (!scnt) return -EINVAL; 251 count -= scnt; buf += scnt; 252 if (!wptr) return -EINVAL; 253 if (debugifc_match_keyword(wptr,wlen,"dir")) { 254 dir_fl = !0; 255 } else if (!debugifc_match_keyword(wptr,wlen,"out")) { 256 return -EINVAL; 257 } 258 scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); 259 if (!scnt) return -EINVAL; 260 count -= scnt; buf += scnt; 261 if (!wptr) return -EINVAL; 262 ret = debugifc_parse_unsigned_number(wptr,wlen,&msk); 263 if (ret) return ret; 264 scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); 265 if (wptr) { 266 ret = debugifc_parse_unsigned_number(wptr,wlen,&val); 267 if (ret) return ret; 268 } else { 269 val = msk; 270 msk = 0xffffffff; 271 } 272 if (dir_fl) { 273 ret = pvr2_hdw_gpio_chg_dir(hdw,msk,val); 274 } else { 275 ret = pvr2_hdw_gpio_chg_out(hdw,msk,val); 276 } 277 return ret; 278 } 279 pvr2_trace(PVR2_TRACE_DEBUGIFC, 280 "debugifc failed to recognize cmd: \"%.*s\"",wlen,wptr); 281 return -EINVAL; 282 } 283 284 285 int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf, 286 unsigned int count) 287 { 288 unsigned int bcnt = 0; 289 int ret; 290 291 while (count) { 292 for (bcnt = 0; bcnt < count; bcnt++) { 293 if (buf[bcnt] == '\n') break; 294 } 295 296 ret = pvr2_debugifc_do1cmd(hdw,buf,bcnt); 297 if (ret < 0) return ret; 298 if (bcnt < count) bcnt++; 299 buf += bcnt; 300 count -= bcnt; 301 } 302 303 return 0; 304 } 305