304 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 13static 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 30static 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 46static 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 74static 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 100static 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 111int 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 127int 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 174static 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 284int 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