1 /*
2 * 1394-Based Digital Camera Control Library
3 *
4 * Written by David Moore <dcm@acm.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <inttypes.h>
24 #include <string.h>
25
26 #include <dc1394/control.h>
27 #include "internal.h"
28 #include "platform.h"
29 #include "log.h"
30
31 static void
destroy_camera_info(camera_info_t * info)32 destroy_camera_info (camera_info_t * info)
33 {
34 free (info->vendor);
35 free (info->model);
36 }
37
38 static int
add_camera(dc1394_t * d,camera_info_t * info)39 add_camera (dc1394_t * d, camera_info_t * info)
40 {
41 int n = d->num_cameras;
42 dc1394_log_debug ("Adding camera %"PRIx64":%d %x:%x (%s:%s)",
43 info->guid, info->unit, info->vendor_id, info->model_id,
44 info->vendor, info->model);
45
46 /* For now, exclude duplicate cameras caused by seeing the same camera
47 * on different busses. A better solution is to let the user choose
48 * between these different versions of the same camera, which will require
49 * a new API in the future. */
50 int i;
51 for (i = 0; i < n; i++) {
52 if (d->cameras[i].guid == info->guid
53 && d->cameras[i].unit == info->unit) {
54 dc1394_log_debug ("Rejected camera %"PRIx64" as duplicate",
55 info->unit);
56 destroy_camera_info (info);
57 return 0;
58 }
59 }
60 d->cameras = realloc (d->cameras, (n + 1) * sizeof (camera_info_t));
61 memcpy (d->cameras + n, info, sizeof (camera_info_t));
62 d->num_cameras = n + 1;
63 return 0;
64 }
65
66 static char *
parse_leaf(uint32_t offset,uint32_t * quads,int num_quads)67 parse_leaf (uint32_t offset, uint32_t * quads, int num_quads)
68 {
69 if (offset >= num_quads)
70 return NULL;
71 int num_entries = quads[offset] >> 16;
72 if (offset + num_entries >= num_quads)
73 return NULL;
74
75 uint32_t * dquads = quads + offset + 1;
76 char * str = malloc ((num_entries - 1) * 4 + 1);
77 int i;
78 for (i = 0; i < num_entries - 2; i++) {
79 uint32_t q = dquads[i+2];
80 str[4*i+0] = q >> 24;
81 str[4*i+1] = (q >> 16) & 0xff;
82 str[4*i+2] = (q >> 8) & 0xff;
83 str[4*i+3] = q & 0xff;
84 }
85 str[4*i] = '\0';
86 return str;
87 }
88
89 static int
identify_unit(dc1394_t * d,platform_info_t * platform,platform_device_t * dev,uint64_t guid,uint32_t offset,uint32_t * quads,int num_quads,int unit_num,uint32_t vendor_id)90 identify_unit (dc1394_t * d, platform_info_t * platform,
91 platform_device_t * dev, uint64_t guid,
92 uint32_t offset, uint32_t * quads, int num_quads, int unit_num,
93 uint32_t vendor_id)
94 {
95 if (offset >= num_quads)
96 return -1;
97 int num_entries = quads[offset] >> 16;
98 if (offset + num_entries >= num_quads)
99 return -1;
100
101 camera_info_t info;
102 memset (&info, 0, sizeof (camera_info_t));
103
104 info.guid = guid;
105 info.unit = unit_num;
106 info.device = dev;
107 info.vendor_id = vendor_id;
108 info.unit_directory = offset;
109 info.platform = platform;
110
111 uint32_t * dquads = quads + offset + 1;
112 int i;
113 for (i = 0; i < num_entries; i++) {
114 uint32_t q = dquads[i];
115 if ((q >> 24) == 0x12)
116 info.unit_spec_ID = q & 0xffffff;
117 if ((q >> 24) == 0x13)
118 info.unit_sw_version = q & 0xffffff;
119 if ((q >> 24) == 0xD4)
120 info.unit_dependent_directory = (q & 0xffffff) + offset + i + 1;
121 if ((q >> 24) == 0x17)
122 info.model_id = q & 0xffffff;
123 }
124
125 /*
126 Note on Point Grey (PG) cameras:
127 Although not always advertised, PG cameras are 'sometimes' compatible
128 with IIDC specs. This is especially the case with PG stereo products.
129 The following modifications have been tested with a stereo head
130 (BumbleBee). Most other cameras should be compatible, please consider
131 contributing to the lib if your PG camera is not recognized.
132
133 PG cams sometimes have a Unit_Spec_ID of 0xB09D, instead of the
134 0xA02D of classic IIDC cameras. Also, their software revision differs.
135 I could only get a 1.14 version from my BumbleBee but other versions
136 might exist.
137
138 As PG is regularly providing firmware updates you might also install
139 the latest one in your camera for an increased compatibility.
140
141 Damien
142
143 (updated 2005-04-30)
144 */
145
146 if ((info.unit_spec_ID != 0xA02D) &&
147 (info.unit_spec_ID != 0xB09D))
148 return -1;
149 if (!info.unit_dependent_directory)
150 return -1;
151
152 if (info.unit_dependent_directory >= num_quads)
153 goto done;
154 num_entries = quads[info.unit_dependent_directory] >> 16;
155 if (info.unit_dependent_directory + num_entries >= num_quads)
156 goto done;
157
158 dquads = quads + info.unit_dependent_directory + 1;
159 for (i = 0; i < num_entries; i++) {
160 uint32_t q = dquads[i];
161 if ((q >> 24) == 0x81)
162 info.vendor = parse_leaf ((q & 0xffffff) +
163 info.unit_dependent_directory + 1 + i,
164 quads, num_quads);
165 if ((q >> 24) == 0x82)
166 info.model = parse_leaf ((q & 0xffffff) +
167 info.unit_dependent_directory + 1 + i,
168 quads, num_quads);
169 }
170 done:
171 info.unit_directory = info.unit_directory * 4 + 0x400;
172 info.unit_dependent_directory = info.unit_dependent_directory * 4 + 0x400;
173 return add_camera (d, &info);
174 }
175
176 static int
identify_camera(dc1394_t * d,platform_info_t * platform,platform_device_t * dev)177 identify_camera (dc1394_t * d, platform_info_t * platform,
178 platform_device_t * dev)
179 {
180 uint64_t guid;
181 uint32_t quads[256];
182 int num_quads = 256;
183 if (platform->dispatch->device_get_config_rom (dev, quads,
184 &num_quads) < 0) {
185 dc1394_log_warning ("Failed to get config ROM from %s device",
186 platform->name);
187 return -1;
188 }
189
190 dc1394_log_debug ("Got %d quads of config ROM", num_quads);
191
192 if (num_quads < 7)
193 return -1;
194
195 /* Require 4 quadlets in the bus info block */
196 if ((quads[0] >> 24) != 0x4) {
197 dc1394_log_debug ("Expected 4 quadlets in bus info block, got %d",
198 quads[0] >> 24);
199 return -1;
200 }
201
202 /* Require "1394" as the bus identity */
203 if (quads[1] != 0x31333934)
204 return -1;
205
206 guid = ((uint64_t)quads[3] << 32) | quads[4];
207
208 int num_entries = quads[5] >> 16;
209 if (num_quads < num_entries + 6)
210 return -1;
211 int unit = 0;
212 uint32_t vendor_id = 0;
213 int i;
214 for (i = 0; i < num_entries; i++) {
215 uint32_t q = quads[6+i];
216 if ((q >> 24) == 0x03)
217 vendor_id = q & 0xffffff;
218 if ((q >> 24) == 0xD1) {
219 uint32_t offset = (q & 0xffffff) + 6 + i;
220 identify_unit (d, platform, dev, guid, offset, quads, num_quads,
221 unit++, vendor_id);
222 }
223 }
224 return 0;
225 }
226
227 void
free_enumeration(dc1394_t * d)228 free_enumeration (dc1394_t * d)
229 {
230 int i;
231 for (i = 0; i < d->num_platforms; i++) {
232 platform_info_t * p = d->platforms + i;
233 if (p->device_list)
234 p->dispatch->free_device_list (p->device_list);
235 p->device_list = NULL;
236 }
237
238 for (i = 0; i < d->num_cameras; i++)
239 destroy_camera_info (d->cameras + i);
240 free (d->cameras);
241 d->num_cameras = 0;
242 d->cameras = NULL;
243 }
244
245 int
refresh_enumeration(dc1394_t * d)246 refresh_enumeration (dc1394_t * d)
247 {
248 free_enumeration (d);
249
250 dc1394_log_debug ("Enumerating cameras...");
251 int i;
252 for (i = 0; i < d->num_platforms; i++) {
253 platform_info_t * p = d->platforms + i;
254 if (!p->p)
255 continue;
256 dc1394_log_debug("Enumerating platform %s", p->name);
257 p->device_list = p->dispatch->get_device_list (p->p);
258 if (!p->device_list) {
259 dc1394_log_warning("Platform %s failed to get device list",
260 p->name);
261 continue;
262 }
263
264 platform_device_t ** list = p->device_list->devices;
265 int j;
266 dc1394_log_debug ("Platform %s has %d device(s)",
267 p->name, p->device_list->num_devices);
268 for (j = 0; j < p->device_list->num_devices; j++)
269 if (identify_camera (d, p, list[j]) < 0)
270 dc1394_log_debug ("Failed to identify %s device %d",
271 p->name, j);
272 }
273
274 return 0;
275 }
276
277 dc1394error_t
dc1394_camera_enumerate(dc1394_t * d,dc1394camera_list_t ** list)278 dc1394_camera_enumerate (dc1394_t * d, dc1394camera_list_t **list)
279 {
280 if (refresh_enumeration (d) < 0)
281 return DC1394_FAILURE;
282
283 dc1394camera_list_t * l;
284
285 l = calloc (1, sizeof (dc1394camera_list_t));
286 *list = l;
287 if (d->num_cameras == 0)
288 return DC1394_SUCCESS;
289
290 l->ids = malloc (d->num_cameras * sizeof (dc1394camera_id_t));
291 l->num = 0;
292
293 int i;
294 for (i = 0; i < d->num_cameras; i++) {
295 l->ids[i].guid = d->cameras[i].guid;
296 l->ids[i].unit = d->cameras[i].unit;
297 l->num++;
298 }
299 return DC1394_SUCCESS;
300 }
301
302 /*
303 Free a list of cameras returned by dc1394_enumerate_cameras()
304 */
305 void
dc1394_camera_free_list(dc1394camera_list_t * list)306 dc1394_camera_free_list (dc1394camera_list_t *list)
307 {
308 if (list)
309 free (list->ids);
310 list->ids = NULL;
311 free (list);
312 }
313
314