linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
<<
>>
Prefs
   1/*
   2 *
   3 *  $Id$
   4 *
   5 *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
   6 *
   7 *  This program is free software; you can redistribute it and/or modify
   8 *  it under the terms of the GNU General Public License as published by
   9 *  the Free Software Foundation; either version 2 of the License
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 *
  20 */
  21
  22#include <linux/string.h>
  23#include <linux/slab.h>
  24#include "pvrusb2-debugifc.h"
  25#include "pvrusb2-hdw.h"
  26#include "pvrusb2-debug.h"
  27#include "pvrusb2-i2c-core.h"
  28
  29struct debugifc_mask_item {
  30        const char *name;
  31        unsigned long msk;
  32};
  33
  34static struct debugifc_mask_item mask_items[] = {
  35        {"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
  36        {"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
  37        {"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
  38        {"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
  39        {"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
  40};
  41
  42
  43static unsigned int debugifc_count_whitespace(const char *buf,
  44                                              unsigned int count)
  45{
  46        unsigned int scnt;
  47        char ch;
  48
  49        for (scnt = 0; scnt < count; scnt++) {
  50                ch = buf[scnt];
  51                if (ch == ' ') continue;
  52                if (ch == '\t') continue;
  53                if (ch == '\n') continue;
  54                break;
  55        }
  56        return scnt;
  57}
  58
  59
  60static unsigned int debugifc_count_nonwhitespace(const char *buf,
  61                                                 unsigned int count)
  62{
  63        unsigned int scnt;
  64        char ch;
  65
  66        for (scnt = 0; scnt < count; scnt++) {
  67                ch = buf[scnt];
  68                if (ch == ' ') break;
  69                if (ch == '\t') break;
  70                if (ch == '\n') break;
  71        }
  72        return scnt;
  73}
  74
  75
  76static unsigned int debugifc_isolate_word(const char *buf,unsigned int count,
  77                                          const char **wstrPtr,
  78                                          unsigned int *wlenPtr)
  79{
  80        const char *wptr;
  81        unsigned int consume_cnt = 0;
  82        unsigned int wlen;
  83        unsigned int scnt;
  84
  85        wptr = NULL;
  86        wlen = 0;
  87        scnt = debugifc_count_whitespace(buf,count);
  88        consume_cnt += scnt; count -= scnt; buf += scnt;
  89        if (!count) goto done;
  90
  91        scnt = debugifc_count_nonwhitespace(buf,count);
  92        if (!scnt) goto done;
  93        wptr = buf;
  94        wlen = scnt;
  95        consume_cnt += scnt; count -= scnt; buf += scnt;
  96
  97 done:
  98        *wstrPtr = wptr;
  99        *wlenPtr = wlen;
 100        return consume_cnt;
 101}
 102
 103
 104static int debugifc_parse_unsigned_number(const char *buf,unsigned int count,
 105                                          u32 *num_ptr)
 106{
 107        u32 result = 0;
 108        u32 val;
 109        int ch;
 110        int radix = 10;
 111        if ((count >= 2) && (buf[0] == '0') &&
 112            ((buf[1] == 'x') || (buf[1] == 'X'))) {
 113                radix = 16;
 114                count -= 2;
 115                buf += 2;
 116        } else if ((count >= 1) && (buf[0] == '0')) {
 117                radix = 8;
 118        }
 119
 120        while (count--) {
 121                ch = *buf++;
 122                if ((ch >= '0') && (ch <= '9')) {
 123                        val = ch - '0';
 124                } else if ((ch >= 'a') && (ch <= 'f')) {
 125                        val = ch - 'a' + 10;
 126                } else if ((ch >= 'A') && (ch <= 'F')) {
 127                        val = ch - 'A' + 10;
 128                } else {
 129                        return -EINVAL;
 130                }
 131                if (val >= radix) return -EINVAL;
 132                result *= radix;
 133                result += val;
 134        }
 135        *num_ptr = result;
 136        return 0;
 137}
 138
 139
 140static int debugifc_match_keyword(const char *buf,unsigned int count,
 141                                  const char *keyword)
 142{
 143        unsigned int kl;
 144        if (!keyword) return 0;
 145        kl = strlen(keyword);
 146        if (kl != count) return 0;
 147        return !memcmp(buf,keyword,kl);
 148}
 149
 150
 151static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
 152{
 153        struct debugifc_mask_item *mip;
 154        unsigned int idx;
 155        for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
 156                mip = mask_items + idx;
 157                if (debugifc_match_keyword(buf,count,mip->name)) {
 158                        return mip->msk;
 159                }
 160        }
 161        return 0;
 162}
 163
 164
 165static int debugifc_print_mask(char *buf,unsigned int sz,
 166                               unsigned long msk,unsigned long val)
 167{
 168        struct debugifc_mask_item *mip;
 169        unsigned int idx;
 170        int bcnt = 0;
 171        int ccnt;
 172        for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
 173                mip = mask_items + idx;
 174                if (!(mip->msk & msk)) continue;
 175                ccnt = scnprintf(buf,sz,"%s%c%s",
 176                                 (bcnt ? " " : ""),
 177                                 ((mip->msk & val) ? '+' : '-'),
 178                                 mip->name);
 179                sz -= ccnt;
 180                buf += ccnt;
 181                bcnt += ccnt;
 182        }
 183        return bcnt;
 184}
 185
 186static unsigned int debugifc_parse_subsys_mask(const char *buf,
 187                                               unsigned int count,
 188                                               unsigned long *mskPtr,
 189                                               unsigned long *valPtr)
 190{
 191        const char *wptr;
 192        unsigned int consume_cnt = 0;
 193        unsigned int scnt;
 194        unsigned int wlen;
 195        int mode;
 196        unsigned long m1,msk,val;
 197
 198        msk = 0;
 199        val = 0;
 200
 201        while (count) {
 202                scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 203                if (!scnt) break;
 204                consume_cnt += scnt; count -= scnt; buf += scnt;
 205                if (!wptr) break;
 206
 207                mode = 0;
 208                if (wlen) switch (wptr[0]) {
 209                case '+':
 210                        wptr++;
 211                        wlen--;
 212                        break;
 213                case '-':
 214                        mode = 1;
 215                        wptr++;
 216                        wlen--;
 217                        break;
 218                }
 219                if (!wlen) continue;
 220                m1 = debugifc_find_mask(wptr,wlen);
 221                if (!m1) break;
 222                msk |= m1;
 223                if (!mode) val |= m1;
 224        }
 225        *mskPtr = msk;
 226        *valPtr = val;
 227        return consume_cnt;
 228}
 229
 230
 231int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
 232{
 233        int bcnt = 0;
 234        int ccnt;
 235        struct pvr2_hdw_debug_info dbg;
 236
 237        pvr2_hdw_get_debug_info(hdw,&dbg);
 238
 239        ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
 240                         (dbg.big_lock_held ? "held" : "free"),
 241                         (dbg.ctl_lock_held ? "held" : "free"));
 242        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 243        if (dbg.ctl_lock_held) {
 244                ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
 245                                 " cmd_wlen=%d cmd_rlen=%d"
 246                                 " wpend=%d rpend=%d tmout=%d rstatus=%d"
 247                                 " wstatus=%d",
 248                                 dbg.cmd_debug_state,dbg.cmd_code,
 249                                 dbg.cmd_debug_write_len,
 250                                 dbg.cmd_debug_read_len,
 251                                 dbg.cmd_debug_write_pend,
 252                                 dbg.cmd_debug_read_pend,
 253                                 dbg.cmd_debug_timeout,
 254                                 dbg.cmd_debug_rstatus,
 255                                 dbg.cmd_debug_wstatus);
 256                bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 257        }
 258        ccnt = scnprintf(buf,acnt,"\n");
 259        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 260        ccnt = scnprintf(
 261                buf,acnt,"driver flags: %s %s %s\n",
 262                (dbg.flag_init_ok ? "initialized" : "uninitialized"),
 263                (dbg.flag_ok ? "ok" : "fail"),
 264                (dbg.flag_disconnected ? "disconnected" : "connected"));
 265        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 266        ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
 267        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 268        ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
 269        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 270        ccnt = scnprintf(buf,acnt,"\n");
 271        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 272        ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
 273        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 274        ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
 275        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 276        ccnt = scnprintf(buf,acnt,"\n");
 277        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 278
 279        ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
 280        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 281        ccnt = pvr2_i2c_report(hdw,buf,acnt);
 282        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 283
 284        return bcnt;
 285}
 286
 287
 288int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
 289                               char *buf,unsigned int acnt)
 290{
 291        int bcnt = 0;
 292        int ccnt;
 293        unsigned long msk;
 294        int ret;
 295        u32 gpio_dir,gpio_in,gpio_out;
 296
 297        ret = pvr2_hdw_is_hsm(hdw);
 298        ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
 299                         (ret < 0 ? "FAIL" : (ret ? "high" : "full")));
 300        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 301
 302        gpio_dir = 0; gpio_in = 0; gpio_out = 0;
 303        pvr2_hdw_gpio_get_dir(hdw,&gpio_dir);
 304        pvr2_hdw_gpio_get_out(hdw,&gpio_out);
 305        pvr2_hdw_gpio_get_in(hdw,&gpio_in);
 306        ccnt = scnprintf(buf,acnt,"GPIO state: dir=0x%x in=0x%x out=0x%x\n",
 307                         gpio_dir,gpio_in,gpio_out);
 308        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 309
 310        ccnt = scnprintf(buf,acnt,"Streaming is %s\n",
 311                         pvr2_hdw_get_streaming(hdw) ? "on" : "off");
 312        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 313
 314        msk = pvr2_hdw_subsys_get(hdw);
 315        ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
 316        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 317        ccnt = debugifc_print_mask(buf,acnt,msk,msk);
 318        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 319        ccnt = scnprintf(buf,acnt,"\n");
 320        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 321        ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
 322        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 323        ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
 324        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 325        ccnt = scnprintf(buf,acnt,"\n");
 326        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 327
 328        msk = pvr2_hdw_subsys_stream_get(hdw);
 329        ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
 330        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 331        ccnt = debugifc_print_mask(buf,acnt,msk,msk);
 332        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 333        ccnt = scnprintf(buf,acnt,"\n");
 334        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 335
 336        return bcnt;
 337}
 338
 339
 340static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
 341                                unsigned int count)
 342{
 343        const char *wptr;
 344        unsigned int wlen;
 345        unsigned int scnt;
 346
 347        scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 348        if (!scnt) return 0;
 349        count -= scnt; buf += scnt;
 350        if (!wptr) return 0;
 351
 352        pvr2_trace(PVR2_TRACE_DEBUGIFC,"debugifc cmd: \"%.*s\"",wlen,wptr);
 353        if (debugifc_match_keyword(wptr,wlen,"reset")) {
 354                scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 355                if (!scnt) return -EINVAL;
 356                count -= scnt; buf += scnt;
 357                if (!wptr) return -EINVAL;
 358                if (debugifc_match_keyword(wptr,wlen,"cpu")) {
 359                        pvr2_hdw_cpureset_assert(hdw,!0);
 360                        pvr2_hdw_cpureset_assert(hdw,0);
 361                        return 0;
 362                } else if (debugifc_match_keyword(wptr,wlen,"bus")) {
 363                        pvr2_hdw_device_reset(hdw);
 364                } else if (debugifc_match_keyword(wptr,wlen,"soft")) {
 365                        return pvr2_hdw_cmd_powerup(hdw);
 366                } else if (debugifc_match_keyword(wptr,wlen,"deep")) {
 367                        return pvr2_hdw_cmd_deep_reset(hdw);
 368                } else if (debugifc_match_keyword(wptr,wlen,"firmware")) {
 369                        return pvr2_upload_firmware2(hdw);
 370                } else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
 371                        return pvr2_hdw_cmd_decoder_reset(hdw);
 372                }
 373                return -EINVAL;
 374        } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
 375                unsigned long msk = 0;
 376                unsigned long val = 0;
 377                if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
 378                        pvr2_trace(PVR2_TRACE_DEBUGIFC,
 379                                   "debugifc parse error on subsys mask");
 380                        return -EINVAL;
 381                }
 382                pvr2_hdw_subsys_bit_chg(hdw,msk,val);
 383                return 0;
 384        } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
 385                unsigned long msk = 0;
 386                unsigned long val = 0;
 387                if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
 388                        pvr2_trace(PVR2_TRACE_DEBUGIFC,
 389                                   "debugifc parse error on stream mask");
 390                        return -EINVAL;
 391                }
 392                pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
 393                return 0;
 394        } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
 395                scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 396                if (!scnt) return -EINVAL;
 397                count -= scnt; buf += scnt;
 398                if (!wptr) return -EINVAL;
 399                if (debugifc_match_keyword(wptr,wlen,"fetch")) {
 400                        scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 401                        if (scnt && wptr) {
 402                                count -= scnt; buf += scnt;
 403                                if (debugifc_match_keyword(wptr,wlen,"prom")) {
 404                                        pvr2_hdw_cpufw_set_enabled(hdw,!0,!0);
 405                                } else if (debugifc_match_keyword(wptr,wlen,
 406                                                                  "ram")) {
 407                                        pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
 408                                } else {
 409                                        return -EINVAL;
 410                                }
 411                        }
 412                        pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
 413                        return 0;
 414                } else if (debugifc_match_keyword(wptr,wlen,"done")) {
 415                        pvr2_hdw_cpufw_set_enabled(hdw,0,0);
 416                        return 0;
 417                } else {
 418                        return -EINVAL;
 419                }
 420        } else if (debugifc_match_keyword(wptr,wlen,"gpio")) {
 421                int dir_fl = 0;
 422                int ret;
 423                u32 msk,val;
 424                scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 425                if (!scnt) return -EINVAL;
 426                count -= scnt; buf += scnt;
 427                if (!wptr) return -EINVAL;
 428                if (debugifc_match_keyword(wptr,wlen,"dir")) {
 429                        dir_fl = !0;
 430                } else if (!debugifc_match_keyword(wptr,wlen,"out")) {
 431                        return -EINVAL;
 432                }
 433                scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 434                if (!scnt) return -EINVAL;
 435                count -= scnt; buf += scnt;
 436                if (!wptr) return -EINVAL;
 437                ret = debugifc_parse_unsigned_number(wptr,wlen,&msk);
 438                if (ret) return ret;
 439                scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 440                if (wptr) {
 441                        ret = debugifc_parse_unsigned_number(wptr,wlen,&val);
 442                        if (ret) return ret;
 443                } else {
 444                        val = msk;
 445                        msk = 0xffffffff;
 446                }
 447                if (dir_fl) {
 448                        ret = pvr2_hdw_gpio_chg_dir(hdw,msk,val);
 449                } else {
 450                        ret = pvr2_hdw_gpio_chg_out(hdw,msk,val);
 451                }
 452                return ret;
 453        }
 454        pvr2_trace(PVR2_TRACE_DEBUGIFC,
 455                   "debugifc failed to recognize cmd: \"%.*s\"",wlen,wptr);
 456        return -EINVAL;
 457}
 458
 459
 460int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf,
 461                        unsigned int count)
 462{
 463        unsigned int bcnt = 0;
 464        int ret;
 465
 466        while (count) {
 467                for (bcnt = 0; bcnt < count; bcnt++) {
 468                        if (buf[bcnt] == '\n') break;
 469                }
 470
 471                ret = pvr2_debugifc_do1cmd(hdw,buf,bcnt);
 472                if (ret < 0) return ret;
 473                if (bcnt < count) bcnt++;
 474                buf += bcnt;
 475                count -= bcnt;
 476        }
 477
 478        return 0;
 479}
 480
 481
 482/*
 483  Stuff for Emacs to see, in order to encourage consistent editing style:
 484  *** Local Variables: ***
 485  *** mode: c ***
 486  *** fill-column: 75 ***
 487  *** tab-width: 8 ***
 488  *** c-basic-offset: 8 ***
 489  *** End: ***
 490  */
 491