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