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