/*- * Copyright (c) 2008 FUKAUMI Naoki. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG static void print_request(struct usb_ctl_request *ucr) { fprintf(stderr, "request: %02x %02x %02x %02x %02x %02x %02x %02x\n", ucr->ucr_request.bmRequestType, ucr->ucr_request.bRequest, ucr->ucr_request.wValue[0], ucr->ucr_request.wValue[1], ucr->ucr_request.wIndex[0], ucr->ucr_request.wIndex[1], ucr->ucr_request.wLength[0], ucr->ucr_request.wLength[1]); return; } static void print_data(uint8_t *data, int len) { int off = 0; while (off < len) { if ((off % 16) == 0) fprintf(stderr, "%04x:", off); fprintf(stderr, " %02x", data[off]); if ((off % 16) == 15) fprintf(stderr, "\n"); off++; } if ((off % 16) != 0) fprintf(stderr, "\n"); return; } #endif int send_ctl(uint8_t *data, int fd, int req, int val, int idx, int len) { struct usb_ctl_request ucr; int r; memset(&ucr, 0, sizeof(ucr)); ucr.ucr_request.bmRequestType = UT_READ_VENDOR_DEVICE; ucr.ucr_request.bRequest = req; USETW(ucr.ucr_request.wValue, val); USETW(ucr.ucr_request.wIndex, idx); USETW(ucr.ucr_request.wLength, len); ucr.ucr_data = data; r = ioctl(fd, USB_DO_REQUEST, &ucr); if (req == 0x08) usleep(10000); #ifdef DEBUG print_request(&ucr); print_data(data, ucr.ucr_actlen); #endif return r; } int chan2freq(int chan, int catv) { if (catv == 0) { if (chan < 13 || chan > 62) return -1; return (473 + (chan - 13) * 6); } else { if (chan < 13 || chan > 63) return -1; if (chan < 23) return (111 + (chan - 13) * 6); else if (catv == 2 && chan >= 24 && chan <= 27) return (233 + (chan - 24) * 6); else return (225 + (chan - 23) * 6); } } int main(int argc, char *argv[]) { double p, cnr; uint32_t val; uint8_t data[0x200], r5 = 0x91, saddr = 0x5a, tid = 0; int catv = 0, chan, freq, null = 0, ugen; int xpid_min = 0x1fff, xpid_max = 0x1fff; setprogname(argv[0]); if (argc != 3) { fprintf(stderr, "usage: %s device channel\n", getprogname()); exit(EXIT_FAILURE); } if ((ugen = open(argv[1], O_WRONLY)) == -1) err(EXIT_FAILURE, "%s", argv[1]); if (argv[2][0] == 'X') { null = 1; /* output PAT and NULL packet only */ xpid_min = 0x0001; xpid_max = 0x1ffe; argv[2]++; } if (argv[2][0] == 'X') { null = 2; /* output XOR table in payload of NULL packet */ argv[2]++; } if (argv[2][0] == 'C') { catv = 1; argv[2]++; } if (argv[2][0] == 'C') { catv = 2; /* frequency for C24-C27 may be shifted by +2MHz */ argv[2]++; } chan = strtoul(argv[2], NULL, 0); if ((freq = chan2freq(chan, catv)) < 0) { fprintf(stderr, "invalid channel\n"); goto err; } send_ctl(data, ugen, 0x0c, 0x0000, 0x0000, 0x003a); send_ctl(data, ugen, 0x17, 0x0002, 0x0000, 0x0003); send_ctl(data, ugen, 0x08, 0xfb07, 0x0000, 0x0001); /* HDUS: Tuner off */ send_ctl(data, ugen, 0x08, 0x0100, 0x0000, 0x0001); send_ctl(data, ugen, 0x08, 0xdd0c, 0x0000, 0x0001); /* HDUS: Tuner on */ send_ctl(data, ugen, 0x08, 0xd500, 0x0000, 0x0001); send_ctl(data, ugen, 0x08, 0x0800, 0x0000, 0x0001); send_ctl(data, ugen, 0x08, 0x4040, 0x0000, 0x0001); send_ctl(data, ugen, 0x08, 0x8080, 0x0000, 0x0001); send_ctl(data, ugen, 0x08, 0x0404, 0x0000, 0x0001); /* HDUS: Tuner init */ send_ctl(data, ugen, 0x03, 0x0120, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0220, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0320, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0420, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0520, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0620, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0720, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0820, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0c20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x1120, 0x0021, 0x0002); send_ctl(data, ugen, 0x03, 0x1220, 0x000b, 0x0002); send_ctl(data, ugen, 0x03, 0x1320, 0x002c, 0x0002); send_ctl(data, ugen, 0x03, 0x1420, 0x000a, 0x0002); send_ctl(data, ugen, 0x03, 0x1520, 0x0040, 0x0002); send_ctl(data, ugen, 0x03, 0x1620, 0x000a, 0x0002); send_ctl(data, ugen, 0x03, 0x1720, 0x0070, 0x0002); send_ctl(data, ugen, 0x03, 0x1820, 0x0031, 0x0002); send_ctl(data, ugen, 0x03, 0x1920, 0x0013, 0x0002); send_ctl(data, ugen, 0x03, 0x1a20, 0x0031, 0x0002); send_ctl(data, ugen, 0x03, 0x1b20, 0x0013, 0x0002); send_ctl(data, ugen, 0x03, 0x1c20, 0x002a, 0x0002); send_ctl(data, ugen, 0x03, 0x1d20, 0x00aa, 0x0002); send_ctl(data, ugen, 0x03, 0x1e20, 0x00a2, 0x0002); send_ctl(data, ugen, 0x03, 0x1f20, 0x0008, 0x0002); send_ctl(data, ugen, 0x03, 0x2020, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x2120, 0x00ff, 0x0002); send_ctl(data, ugen, 0x03, 0x2220, 0x0080, 0x0002); send_ctl(data, ugen, 0x03, 0x2320, 0x004c, 0x0002); send_ctl(data, ugen, 0x03, 0x2420, 0x004c, 0x0002); send_ctl(data, ugen, 0x03, 0x2520, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x2620, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x2720, 0x000c, 0x0002); send_ctl(data, ugen, 0x03, 0x2820, 0x0060, 0x0002); send_ctl(data, ugen, 0x03, 0x2920, 0x006b, 0x0002); send_ctl(data, ugen, 0x03, 0x2a20, 0x0040, 0x0002); send_ctl(data, ugen, 0x03, 0x2b20, 0x0040, 0x0002); send_ctl(data, ugen, 0x03, 0x2c20, 0x00ff, 0x0002); send_ctl(data, ugen, 0x03, 0x2d20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x2e20, 0x00ff, 0x0002); send_ctl(data, ugen, 0x03, 0x2f20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x3020, 0x0028, 0x0002); send_ctl(data, ugen, 0x03, 0x3120, 0x000f, 0x0002); send_ctl(data, ugen, 0x03, 0x3220, 0x00a0, 0x0002); send_ctl(data, ugen, 0x03, 0x3420, 0x003f, 0x0002); send_ctl(data, ugen, 0x03, 0x3820, 0x0001, 0x0002); send_ctl(data, ugen, 0x03, 0x3920, 0x0070, 0x0002); send_ctl(data, ugen, 0x03, 0x3a20, 0x002d, 0x0002); send_ctl(data, ugen, 0x03, 0x3b20, 0x0021, 0x0002); send_ctl(data, ugen, 0x03, 0x3c20, 0x003f, 0x0002); send_ctl(data, ugen, 0x03, 0x3d20, 0x0010, 0x0002); send_ctl(data, ugen, 0x03, 0x3e20, 0x0008, 0x0002); send_ctl(data, ugen, 0x03, 0x3f20, 0x000c, 0x0002); send_ctl(data, ugen, 0x03, 0x4020, 0x000c, 0x0002); send_ctl(data, ugen, 0x03, 0x4120, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x4220, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x4320, 0x004f, 0x0002); send_ctl(data, ugen, 0x03, 0x4420, 0x00ff, 0x0002); send_ctl(data, ugen, 0x03, 0x4620, 0x0020, 0x0002); send_ctl(data, ugen, 0x03, 0x4720, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x4820, 0x0090, 0x0002); send_ctl(data, ugen, 0x03, 0x4920, 0x00e6, 0x0002); send_ctl(data, ugen, 0x03, 0x4a20, 0x0002, 0x0002); send_ctl(data, ugen, 0x03, 0x4b20, 0x0054, 0x0002); send_ctl(data, ugen, 0x03, 0x4c20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x5020, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x5120, 0x0058, 0x0002); send_ctl(data, ugen, 0x03, 0x5220, 0x0020, 0x0002); send_ctl(data, ugen, 0x03, 0x5420, 0x0057, 0x0002); send_ctl(data, ugen, 0x03, 0x5520, 0x00f1, 0x0002); send_ctl(data, ugen, 0x03, 0x5620, 0x0020, 0x0002); send_ctl(data, ugen, 0x03, 0x5720, 0x0070, 0x0002); send_ctl(data, ugen, 0x03, 0x5820, 0x0060, 0x0002); send_ctl(data, ugen, 0x03, 0x5c20, 0x0050, 0x0002); send_ctl(data, ugen, 0x03, 0x5d20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x5f20, 0x0080, 0x0002); send_ctl(data, ugen, 0x03, 0x7020, 0x0018, 0x0002); send_ctl(data, ugen, 0x03, 0x7120, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x7220, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x7520, 0x0022, 0x0002); send_ctl(data, ugen, 0x03, 0x7620, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x7720, 0x0001, 0x0002); send_ctl(data, ugen, 0x03, 0x7c20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x7d20, 0x0052, 0x0002); send_ctl(data, ugen, 0x03, 0xba20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0xbb20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0xbc20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0xc220, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0xc720, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0xe420, 0x001a, 0x0002); send_ctl(data, ugen, 0x03, 0xe920, 0x0008, 0x0002); send_ctl(data, ugen, 0x03, 0xec20, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0xef20, 0x0000, 0x0002); /* ASIE5606 on */ send_ctl(data, ugen, 0x08, ((tid == 0) ? 0x1100 : 0x8000) | 0x00, 0x0000, 0x0001); send_ctl(data, ugen, 0x08, ((tid == 0) ? 0x1100 : 0x8000) | 0xff, 0x0000, 0x0001); /* ASIE5606 init */ send_ctl(data, ugen, 0x02, 0x0900 | saddr, 0x0000, 0x0002); if (data[0] != 1) { saddr = 0x4a; /* HDUSF */ r5 = 0x80; /* DES */ send_ctl(data, ugen, 0x02, 0x0900 | saddr, 0x0000, 0x0002); send_ctl(data, ugen, 0x23, 0x0000 | saddr, 0x0000, 0x0002); send_ctl(data, ugen, 0x02, 0x0900 | saddr, 0x0000, 0x0002); } send_ctl(data, ugen, 0x03, 0x0500 | saddr, r5, 0x0002); if (r5 == 0x91) { /* Set XOR values */ for (val = 0x1000; val < 0x2000; val += 0x0100) send_ctl(data, ugen, 0x03, val | saddr, (null == 2) ? 0x00ff : 0x0000, 0x0002); } else { /* Set key */ for (val = 0x1000; val < 0x2000; val += 0x0100) send_ctl(data, ugen, 0x03, val | saddr, 0x0000, 0x0002); } setfreq: fprintf(stderr, "chan: %s%d%s\n", (catv > 0) ? "C" : "", chan, (null > 0) ? " (PAT/NULL only)" : ""); fprintf(stderr, "freq: %d.142857 MHz\n", freq); /* HDUS: Set frequency */ val = (freq + 57) * 7 + 1; send_ctl(data, ugen, 0x0d, 0xfe00, (val & 0xff00) | 0xc0, 0x0004); send_ctl(data, ugen, 0x0d, ((val & 0xff) << 8) | 0x03, (freq < 205) ? 0x8191 : ((freq < 421) ? 0x8291 : 0x8491), 0x0004); send_ctl(data, ugen, 0x0d, 0xe306, 0x0000, 0x0002); send_ctl(data, ugen, 0x0e, 0x0020, 0x0000, 0x0008); send_ctl(data, ugen, 0x03, 0x0120, 0x0040, 0x0002); send_ctl(data, ugen, 0x09, 0x0100 | tid, 0x0000, 0x0001); /* Set PID filter */ val = (tid == 0) ? 0x40 : 0xc0; send_ctl(data, ugen, 0x04, val, 0x0000, 0x0002); send_ctl(data, ugen, 0x05, ((data[1] | 0x0b) << 8) | val, 0x0000, 0x0002); send_ctl(data, ugen, 0x05, (xpid_min & 0xff00) | (val + 1), (xpid_min & 0xff), 0x0003); send_ctl(data, ugen, 0x05, (xpid_max & 0xff00) | (val + 3), (xpid_max & 0xff), 0x0003); /* Start */ send_ctl(data, ugen, 0x06, tid, 0x0000, 0x0001); for (;;) { sleep(1); send_ctl(data, ugen, 0x02, 0x8b20, 0x0000, 0x0002); val = data[1] << 16; send_ctl(data, ugen, 0x02, 0x8c20, 0x0000, 0x0002); val |= data[1] << 8; send_ctl(data, ugen, 0x02, 0x8d20, 0x0000, 0x0002); val |= data[1]; p = 10.0 * log10(5505024.0 / (double)val); cnr = 0.000024*p*p*p*p - 0.0016*p*p*p + 0.0398*p*p + 0.5491*p + 3.0965; fprintf(stderr, "level: %f\n", cnr); /* Remocon */ send_ctl(data, ugen, 0x00, 0x0000, 0x0000, 0x0021); for (val = 0; val < data[32]; val++) { #ifdef DEBUG fprintf(stderr, "remocon: %02x %02x %02x %02x\n", data[val * 4], data[val * 4 + 1], data[val * 4 + 2], data[val * 4 + 3]); #endif switch (data[val * 4]) { case 0x79: send_ctl(data, ugen, 0x07, tid, 0x0000, 0x0001); if ((freq = chan2freq(--chan, catv)) != -1) goto setfreq; else chan++; case 0x7a: send_ctl(data, ugen, 0x07, tid, 0x0000, 0x0001); if ((freq = chan2freq(++chan, catv)) != -1) goto setfreq; else chan--; case 0x7e: goto poweroff; } } } poweroff: /* Stop */ send_ctl(data, ugen, 0x07, tid, 0x0000, 0x0001); send_ctl(data, ugen, 0x03, 0x8000 | saddr, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0400 | saddr, 0x0000, 0x0002); send_ctl(data, ugen, 0x03, 0x0000 | saddr, 0x0000, 0x0002); if (saddr == 0x4a) send_ctl(data, ugen, 0x21, 0x0000 | saddr, 0x0000, 0x0001); /* HDUS: Tuner off */ send_ctl(data, ugen, 0x08, 0x0100, 0x0000, 0x0001); send_ctl(data, ugen, 0x08, 0xdd0c, 0x0000, 0x0001); close(ugen); return EXIT_SUCCESS; err: close(ugen); return EXIT_FAILURE; }