Ticket #2979: 6200ch.c

File 6200ch.c, 7.9 KB (added by anonymous, 19 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}