Ticket #2979: 6200ch.c

File 6200ch.c, 7.9 KB (added by anonymous, 17 years ago)
Line 
1/*
2 * 6200ch - an external channel changer for Motorola DCT-6200 Tuner
3 *
4 * Copyright 2004,2005 by Stacey D. Son <mythdev@son.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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 Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21#include <libavc1394/rom1394.h>
22#include <libavc1394/avc1394.h>
23#include <libraw1394/raw1394.h>
24#include <sys/types.h>
25#include <stdio.h>
26#include <errno.h>
27#include <stdlib.h>
28#include <unistd.h> // for usleep
29
30// Motorola DCT-6200 IDs
31// Note: there are at least eleven different vendor IDs for the 6200
32#define DCT6200_VENDOR_ID1 0x00000ce5
33#define DCT6200_VENDOR_ID2 0x00000e5c
34#define DCT6200_VENDOR_ID3 0x00001225
35#define DCT6200_VENDOR_ID4 0x00000f9f
36#define DCT6200_VENDOR_ID5 0x00001180
37#define DCT6200_VENDOR_ID6 0x000012c9
38#define DCT6200_VENDOR_ID7 0x000011ae
39#define DCT6200_VENDOR_ID8 0x0000152f
40#define DCT6200_VENDOR_ID9 0x000014e8
41#define DCT6200_VENDOR_ID10 0x000016b5
42#define DCT6200_VENDOR_ID11 0x00001371
43#define DCT6200_SPEC_ID    0x00005068
44#define DCT6200_SW_VERSION 0x00010101
45#define DCT6200_MODEL_ID1  0x0000620a
46#define DCT6200_MODEL_ID2  0x00006200
47#define DCT6412_VENDOR_ID1 0x00000f9f
48#define DCT6412_VENDOR_ID2 0x0000152f
49#define DCT6412_MODEL_ID1  0x000064ca
50#define DCT6412_MODEL_ID2  0x000064cb
51#define DCT6416_VENDOR_ID1 0x000017ee
52#define DCT6416_MODEL_ID1  0x0000646b
53#define DCT5100_VENDOR_ID1 0x000017ee
54#define DCT5100_MODEL_ID1  0x0000620a
55
56#define AVC1394_SUBUNIT_TYPE_6200 (9 << 19)  /* uses a reserved subunit type */
57
58#define AVC1394_6200_COMMAND_CHANNEL 0x000007C00   /* 6200 subunit command */
59#define AVC1394_6200_OPERAND_SET 0x20      /* 6200 subunit command operand */
60
61#define CTL_CMD0 AVC1394_CTYPE_CONTROL | AVC1394_SUBUNIT_TYPE_6200 | \
62        AVC1394_SUBUNIT_ID_0 | AVC1394_6200_COMMAND_CHANNEL | \
63        AVC1394_6200_OPERAND_SET
64
65#define STARTING_NODE 1  /* skip 1394 nodes to avoid error msgs */
66#define STARTING_PORT 0
67#define RETRY_COUNT_SLOW 1
68#define RETRY_COUNT_FAST 0
69
70void set_chan_slow(raw1394handle_t handle, int device, int verbose, int chn);
71void set_chan_fast(raw1394handle_t handle, int device, int verbose, int chn);
72
73void usage()
74{
75   fprintf(stderr, "Usage: 6200ch [-v] [-s] [-n NODE] [-p PORT] "
76           "<channel_num>\n");
77   fprintf(stderr, "-v        print additional verbose output\n");
78   fprintf(stderr, "-s        use single packet method\n");
79   fprintf(stderr, "-n NODE   node to start device scanning on (default:%i)\n",
80           STARTING_NODE);
81   fprintf(stderr, "-p PORT   port/adapter to use              (default:%i)\n",
82           STARTING_PORT);
83   exit(1);
84}
85
86int main (int argc, char *argv[])
87{
88   rom1394_directory dir;
89   int device = -1;
90   int i;
91   int verbose = 0;
92   int single_packet = 0;
93   quadlet_t cmd[2];
94   int chn = 550;
95
96   /* some people experience crashes when starting on node 1 */
97   int starting_node = STARTING_NODE;
98   int starting_port = STARTING_PORT;
99   int c;
100   int index;
101
102   if (argc < 2)
103      usage();
104
105   opterr = 0;
106   while ((c = getopt(argc, argv, "vsn:p:")) != -1)
107   {
108       switch (c) {
109       case 'v':
110           verbose = 1;
111           break;
112       case 's':
113           single_packet = 1;
114           break;
115       case 'n':
116           starting_node = atoi(optarg);
117           break;
118       case 'p':
119           starting_port = atoi(optarg);
120           break;
121       default:
122           fprintf(stderr, "incorrect command line arguments\n");
123           usage();
124       }
125   }
126
127   /* print out usage message if not enough arguments */
128   if (optind != argc-1) {
129       usage();
130   }
131   /* the last argument is the channel number */
132   chn = atoi(argv[optind]);
133
134#ifdef RAW1394_V_0_8
135   raw1394handle_t handle = raw1394_get_handle();
136#else
137   raw1394handle_t handle = raw1394_new_handle();
138#endif
139
140   if (!handle) {
141      if (!errno) {
142         fprintf(stderr, "Not Compatable!\n");
143      } else {
144         perror("Couldn't get 1394 handle");
145         fprintf(stderr, "Is ieee1394, driver, and raw1394 loaded?\n");
146      }
147      exit(1);
148   }
149
150   if (raw1394_set_port(handle, starting_port) < 0) {
151      perror("couldn't set port");
152      raw1394_destroy_handle(handle);
153      exit(1);
154   }
155
156   if (verbose)
157       printf("starting with node: %d\n", starting_node);
158
159   int nc = raw1394_get_nodecount(handle);
160   for (i=starting_node; i < nc; ++i) {
161      if (rom1394_get_directory(handle, i, &dir) < 0) {
162         fprintf(stderr,"error reading config rom directory for node %d\n", i);
163         raw1394_destroy_handle(handle);
164         exit(1);
165      }
166
167      if (verbose)
168         printf("node %d: vendor_id = 0x%08x model_id = 0x%08x\n",
169                 i, dir.vendor_id, dir.model_id);
170               
171      if ( ((dir.vendor_id == DCT6200_VENDOR_ID1) ||
172            (dir.vendor_id == DCT6200_VENDOR_ID2) ||
173            (dir.vendor_id == DCT6200_VENDOR_ID3) ||
174            (dir.vendor_id == DCT6200_VENDOR_ID4) ||
175            (dir.vendor_id == DCT6200_VENDOR_ID5) ||
176            (dir.vendor_id == DCT6200_VENDOR_ID6) ||
177            (dir.vendor_id == DCT6200_VENDOR_ID7) ||
178            (dir.vendor_id == DCT6200_VENDOR_ID8) ||
179            (dir.vendor_id == DCT6200_VENDOR_ID9) ||
180            (dir.vendor_id == DCT6200_VENDOR_ID10) ||
181            (dir.vendor_id == DCT6200_VENDOR_ID11) ||
182            (dir.vendor_id == DCT6412_VENDOR_ID1) ||
183            (dir.vendor_id == DCT6412_VENDOR_ID2) ||
184            (dir.vendor_id == DCT6416_VENDOR_ID1) ||
185            (dir.vendor_id == DCT5100_VENDOR_ID1)) &&
186           ((dir.model_id == DCT6200_MODEL_ID1) ||
187            (dir.model_id == DCT6200_MODEL_ID2) ||
188            (dir.model_id == DCT6412_MODEL_ID1) ||
189            (dir.model_id == DCT6412_MODEL_ID2) ||
190            (dir.model_id == DCT6416_MODEL_ID1) ||
191            (dir.model_id == DCT5100_MODEL_ID1)) ) {
192            if (dir.unit_spec_id != DCT6200_SPEC_ID)
193               fprintf(stderr, "Warning: Unit Spec ID different.\n");
194            if (dir.unit_sw_version != DCT6200_SW_VERSION)
195               fprintf(stderr, "Warning: Unit Software Version different.\n");
196            device = i;
197            break;
198      }
199   }
200   
201   if (device == -1) {
202        fprintf(stderr, "Could not find Motorola DCT-6200 on the 1394 bus.\n");
203        raw1394_destroy_handle(handle);
204        exit(1);
205   }
206
207   if (single_packet)
208       set_chan_fast(handle, device, verbose, chn);
209   else
210       set_chan_slow(handle, device, verbose, chn);
211
212   raw1394_destroy_handle(handle);
213   exit(0);
214}
215
216void set_chan_slow(raw1394handle_t handle, int device, int verbose, int chn)
217{
218   int i;
219   int dig[3];
220   quadlet_t cmd[2];
221
222   dig[2] = (chn % 10);
223   dig[1] = (chn % 100)  / 10;
224   dig[0] = (chn % 1000) / 100;
225
226   if (verbose)
227      printf("AV/C Command: %d%d%d = Op1=0x%08X Op2=0x%08X Op3=0x%08X\n",
228            dig[0], dig[1], dig[2],
229            CTL_CMD0 | dig[0], CTL_CMD0 | dig[1], CTL_CMD0 | dig[2]);
230
231   for (i=0; i<3; i++) {
232      cmd[0] = CTL_CMD0 | dig[i];
233      cmd[1] = 0x0;
234   
235      avc1394_transaction_block(handle, device, cmd, 2, RETRY_COUNT_SLOW);
236      usleep(500000);  // small delay for button to register
237   }
238}
239
240void set_chan_fast(raw1394handle_t handle, int device, int verbose, int chn)
241{
242    quadlet_t cmd[3];
243
244    cmd[0] = CTL_CMD0 | 0x67;
245    cmd[1] = (0x04 << 24) | (chn << 8) | 0x000000FF;
246    cmd[2] = 0xFF << 24;
247
248    if (verbose)
249        printf("AV/C command for channel %d = 0x%08X %08X %08X\n",
250               chn, cmd[0], cmd[1], cmd[2]);
251 
252    avc1394_transaction_block(handle, device, cmd, 3, RETRY_COUNT_FAST);
253}