Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * USB NB Camera driver | |
3 | * | |
4 | * HISTORY: | |
5 | * 25-Dec-2002 Dmitri Removed lighting, sharpness parameters, methods. | |
6 | */ | |
7 | ||
8 | #include <linux/kernel.h> | |
1da177e4 LT |
9 | #include <linux/module.h> |
10 | #include <linux/init.h> | |
11 | ||
12 | #include "usbvideo.h" | |
13 | ||
14 | #define ULTRACAM_VENDOR_ID 0x0461 | |
15 | #define ULTRACAM_PRODUCT_ID 0x0813 | |
16 | ||
17 | #define MAX_CAMERAS 4 /* How many devices we allow to connect */ | |
18 | ||
19 | /* | |
20 | * This structure lives in uvd_t->user field. | |
21 | */ | |
22 | typedef struct { | |
23 | int initialized; /* Had we already sent init sequence? */ | |
24 | int camera_model; /* What type of IBM camera we got? */ | |
d56410e0 | 25 | int has_hdr; |
1da177e4 LT |
26 | } ultracam_t; |
27 | #define ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data)) | |
28 | ||
29 | static struct usbvideo *cams = NULL; | |
30 | ||
ff699e6b | 31 | static int debug; |
1da177e4 | 32 | |
ff699e6b | 33 | static int flags; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ |
1da177e4 LT |
34 | |
35 | static const int min_canvasWidth = 8; | |
36 | static const int min_canvasHeight = 4; | |
37 | ||
38 | #define FRAMERATE_MIN 0 | |
39 | #define FRAMERATE_MAX 6 | |
40 | static int framerate = -1; | |
41 | ||
42 | /* | |
43 | * Here we define several initialization variables. They may | |
44 | * be used to automatically set color, hue, brightness and | |
45 | * contrast to desired values. This is particularly useful in | |
46 | * case of webcams (which have no controls and no on-screen | |
47 | * output) and also when a client V4L software is used that | |
48 | * does not have some of those controls. In any case it's | |
49 | * good to have startup values as options. | |
50 | * | |
51 | * These values are all in [0..255] range. This simplifies | |
52 | * operation. Note that actual values of V4L variables may | |
53 | * be scaled up (as much as << 8). User can see that only | |
54 | * on overlay output, however, or through a V4L client. | |
55 | */ | |
56 | static int init_brightness = 128; | |
57 | static int init_contrast = 192; | |
58 | static int init_color = 128; | |
59 | static int init_hue = 128; | |
60 | static int hue_correction = 128; | |
61 | ||
62 | module_param(debug, int, S_IRUGO | S_IWUSR); | |
63 | MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); | |
64 | module_param(flags, int, 0); | |
65 | MODULE_PARM_DESC(flags, | |
66 | "Bitfield: 0=VIDIOCSYNC, " | |
67 | "1=B/W, " | |
68 | "2=show hints, " | |
69 | "3=show stats, " | |
70 | "4=test pattern, " | |
71 | "5=separate frames, " | |
72 | "6=clean frames"); | |
73 | module_param(framerate, int, 0); | |
74 | MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); | |
75 | ||
76 | module_param(init_brightness, int, 0); | |
77 | MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); | |
78 | module_param(init_contrast, int, 0); | |
79 | MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); | |
80 | module_param(init_color, int, 0); | |
81 | MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); | |
82 | module_param(init_hue, int, 0); | |
83 | MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); | |
84 | module_param(hue_correction, int, 0); | |
85 | MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); | |
86 | ||
87 | /* | |
88 | * ultracam_ProcessIsocData() | |
89 | * | |
90 | * Generic routine to parse the ring queue data. It employs either | |
91 | * ultracam_find_header() or ultracam_parse_lines() to do most | |
92 | * of work. | |
93 | * | |
94 | * 02-Nov-2000 First (mostly dummy) version. | |
95 | * 06-Nov-2000 Rewrote to dump all data into frame. | |
96 | */ | |
97 | static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame) | |
98 | { | |
99 | int n; | |
100 | ||
101 | assert(uvd != NULL); | |
102 | assert(frame != NULL); | |
103 | ||
104 | /* Try to move data from queue into frame buffer */ | |
105 | n = RingQueue_GetLength(&uvd->dp); | |
106 | if (n > 0) { | |
107 | int m; | |
108 | /* See how much spare we have left */ | |
109 | m = uvd->max_frame_size - frame->seqRead_Length; | |
110 | if (n > m) | |
111 | n = m; | |
112 | /* Now move that much data into frame buffer */ | |
113 | RingQueue_Dequeue( | |
114 | &uvd->dp, | |
115 | frame->data + frame->seqRead_Length, | |
116 | m); | |
117 | frame->seqRead_Length += m; | |
118 | } | |
119 | /* See if we filled the frame */ | |
120 | if (frame->seqRead_Length >= uvd->max_frame_size) { | |
121 | frame->frameState = FrameState_Done; | |
122 | uvd->curframe = -1; | |
123 | uvd->stats.frame_num++; | |
124 | } | |
125 | } | |
126 | ||
127 | /* | |
128 | * ultracam_veio() | |
129 | * | |
130 | * History: | |
131 | * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. | |
132 | */ | |
133 | static int ultracam_veio( | |
134 | struct uvd *uvd, | |
135 | unsigned char req, | |
136 | unsigned short value, | |
137 | unsigned short index, | |
138 | int is_out) | |
139 | { | |
140 | static const char proc[] = "ultracam_veio"; | |
141 | unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; | |
142 | int i; | |
143 | ||
144 | if (!CAMERA_IS_OPERATIONAL(uvd)) | |
145 | return 0; | |
146 | ||
147 | if (!is_out) { | |
148 | i = usb_control_msg( | |
149 | uvd->dev, | |
150 | usb_rcvctrlpipe(uvd->dev, 0), | |
151 | req, | |
152 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
153 | value, | |
154 | index, | |
155 | cp, | |
156 | sizeof(cp), | |
157 | 1000); | |
158 | #if 1 | |
a482f327 GKH |
159 | dev_info(&uvd->dev->dev, |
160 | "USB => %02x%02x%02x%02x%02x%02x%02x%02x " | |
161 | "(req=$%02x val=$%04x ind=$%04x)\n", | |
162 | cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], | |
163 | req, value, index); | |
1da177e4 LT |
164 | #endif |
165 | } else { | |
166 | i = usb_control_msg( | |
167 | uvd->dev, | |
168 | usb_sndctrlpipe(uvd->dev, 0), | |
169 | req, | |
170 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
171 | value, | |
172 | index, | |
173 | NULL, | |
174 | 0, | |
175 | 1000); | |
176 | } | |
177 | if (i < 0) { | |
178 | err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", | |
179 | proc, i); | |
180 | uvd->last_error = i; | |
181 | } | |
182 | return i; | |
183 | } | |
184 | ||
185 | /* | |
186 | * ultracam_calculate_fps() | |
187 | */ | |
188 | static int ultracam_calculate_fps(struct uvd *uvd) | |
189 | { | |
190 | return 3 + framerate*4 + framerate/2; | |
191 | } | |
192 | ||
193 | /* | |
194 | * ultracam_adjust_contrast() | |
195 | */ | |
196 | static void ultracam_adjust_contrast(struct uvd *uvd) | |
197 | { | |
198 | } | |
199 | ||
200 | /* | |
201 | * ultracam_set_brightness() | |
202 | * | |
203 | * This procedure changes brightness of the picture. | |
204 | */ | |
205 | static void ultracam_set_brightness(struct uvd *uvd) | |
206 | { | |
207 | } | |
208 | ||
209 | static void ultracam_set_hue(struct uvd *uvd) | |
210 | { | |
211 | } | |
212 | ||
213 | /* | |
214 | * ultracam_adjust_picture() | |
215 | * | |
216 | * This procedure gets called from V4L interface to update picture settings. | |
217 | * Here we change brightness and contrast. | |
218 | */ | |
219 | static void ultracam_adjust_picture(struct uvd *uvd) | |
220 | { | |
221 | ultracam_adjust_contrast(uvd); | |
222 | ultracam_set_brightness(uvd); | |
223 | ultracam_set_hue(uvd); | |
224 | } | |
225 | ||
226 | /* | |
227 | * ultracam_video_stop() | |
228 | * | |
229 | * This code tells camera to stop streaming. The interface remains | |
230 | * configured and bandwidth - claimed. | |
231 | */ | |
232 | static void ultracam_video_stop(struct uvd *uvd) | |
233 | { | |
234 | } | |
235 | ||
236 | /* | |
237 | * ultracam_reinit_iso() | |
238 | * | |
239 | * This procedure sends couple of commands to the camera and then | |
240 | * resets the video pipe. This sequence was observed to reinit the | |
241 | * camera or, at least, to initiate ISO data stream. | |
242 | */ | |
243 | static void ultracam_reinit_iso(struct uvd *uvd, int do_stop) | |
244 | { | |
245 | } | |
246 | ||
247 | static void ultracam_video_start(struct uvd *uvd) | |
248 | { | |
249 | ultracam_reinit_iso(uvd, 0); | |
250 | } | |
251 | ||
252 | static int ultracam_resetPipe(struct uvd *uvd) | |
253 | { | |
254 | usb_clear_halt(uvd->dev, uvd->video_endp); | |
255 | return 0; | |
256 | } | |
257 | ||
258 | static int ultracam_alternateSetting(struct uvd *uvd, int setting) | |
259 | { | |
260 | static const char proc[] = "ultracam_alternateSetting"; | |
261 | int i; | |
262 | i = usb_set_interface(uvd->dev, uvd->iface, setting); | |
263 | if (i < 0) { | |
264 | err("%s: usb_set_interface error", proc); | |
265 | uvd->last_error = i; | |
266 | return -EBUSY; | |
267 | } | |
268 | return 0; | |
269 | } | |
270 | ||
271 | /* | |
272 | * Return negative code on failure, 0 on success. | |
273 | */ | |
274 | static int ultracam_setup_on_open(struct uvd *uvd) | |
275 | { | |
276 | int setup_ok = 0; /* Success by default */ | |
277 | /* Send init sequence only once, it's large! */ | |
278 | if (!ULTRACAM_T(uvd)->initialized) { | |
279 | ultracam_alternateSetting(uvd, 0x04); | |
280 | ultracam_alternateSetting(uvd, 0x00); | |
281 | ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1); | |
282 | ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1); | |
283 | ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1); | |
284 | ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); | |
285 | ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1); | |
286 | ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1); | |
287 | ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1); | |
288 | ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1); | |
289 | ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1); | |
290 | ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1); | |
291 | ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1); | |
292 | ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1); | |
293 | ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1); | |
294 | ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1); | |
295 | ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1); | |
296 | ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1); | |
297 | ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1); | |
298 | ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1); | |
299 | ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1); | |
300 | ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1); | |
301 | ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1); | |
302 | ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); | |
303 | ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); | |
304 | ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); | |
305 | ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); | |
306 | ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); | |
307 | ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); | |
308 | ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); | |
309 | ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); | |
310 | ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); | |
311 | ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1); | |
312 | ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1); | |
313 | ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1); | |
314 | ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1); | |
315 | ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1); | |
316 | ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1); | |
317 | ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1); | |
318 | ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1); | |
319 | ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1); | |
320 | ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1); | |
321 | ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1); | |
322 | ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1); | |
323 | ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1); | |
324 | ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1); | |
325 | ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1); | |
326 | ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1); | |
327 | ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1); | |
328 | ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1); | |
329 | ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1); | |
330 | ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1); | |
331 | ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1); | |
332 | ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1); | |
333 | ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1); | |
334 | ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1); | |
335 | ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1); | |
336 | ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1); | |
337 | ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); | |
338 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); | |
339 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | |
340 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
341 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
342 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
343 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
344 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
345 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
346 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
347 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
348 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
349 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
350 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
351 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
352 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
353 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
354 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
355 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
356 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
357 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
358 | ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); | |
359 | ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1); | |
360 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | |
361 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
362 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
363 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
364 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
365 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
366 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
367 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
368 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
369 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
370 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
371 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
372 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
373 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
374 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
375 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
376 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
377 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
378 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
379 | ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1); | |
380 | ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1); | |
381 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | |
382 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | |
383 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | |
384 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | |
385 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | |
386 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | |
387 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | |
388 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
389 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | |
390 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | |
391 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | |
392 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | |
393 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | |
394 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | |
395 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
396 | ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1); | |
397 | ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1); | |
398 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | |
399 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | |
400 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | |
401 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | |
402 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | |
403 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | |
404 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | |
405 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
406 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | |
407 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | |
408 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | |
409 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | |
410 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | |
411 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | |
412 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | |
413 | ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1); | |
414 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); | |
415 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | |
416 | ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1); | |
417 | ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0); | |
418 | ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0); | |
419 | ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0); | |
420 | ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0); | |
421 | ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0); | |
422 | ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0); | |
423 | ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0); | |
424 | ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0); | |
425 | ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0); | |
426 | ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); | |
427 | ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); | |
428 | ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); | |
429 | ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); | |
430 | ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); | |
431 | ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); | |
432 | ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); | |
433 | ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); | |
434 | ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); | |
435 | ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0); | |
436 | ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1); | |
437 | ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1); | |
438 | ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1); | |
439 | ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1); | |
440 | ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1); | |
441 | ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1); | |
442 | ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1); | |
443 | ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1); | |
444 | ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1); | |
445 | ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); | |
446 | ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1); | |
447 | ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1); | |
448 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | |
449 | ultracam_alternateSetting(uvd, 0x04); | |
450 | ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); | |
451 | ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); | |
452 | ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1); | |
453 | ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1); | |
454 | ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1); | |
455 | ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0); | |
456 | ultracam_resetPipe(uvd); | |
457 | ULTRACAM_T(uvd)->initialized = (setup_ok != 0); | |
458 | } | |
459 | return setup_ok; | |
460 | } | |
461 | ||
462 | static void ultracam_configure_video(struct uvd *uvd) | |
463 | { | |
464 | if (uvd == NULL) | |
465 | return; | |
466 | ||
467 | RESTRICT_TO_RANGE(init_brightness, 0, 255); | |
468 | RESTRICT_TO_RANGE(init_contrast, 0, 255); | |
469 | RESTRICT_TO_RANGE(init_color, 0, 255); | |
470 | RESTRICT_TO_RANGE(init_hue, 0, 255); | |
471 | RESTRICT_TO_RANGE(hue_correction, 0, 255); | |
472 | ||
473 | memset(&uvd->vpic, 0, sizeof(uvd->vpic)); | |
474 | memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); | |
475 | ||
476 | uvd->vpic.colour = init_color << 8; | |
477 | uvd->vpic.hue = init_hue << 8; | |
478 | uvd->vpic.brightness = init_brightness << 8; | |
479 | uvd->vpic.contrast = init_contrast << 8; | |
480 | uvd->vpic.whiteness = 105 << 8; /* This one isn't used */ | |
481 | uvd->vpic.depth = 24; | |
482 | uvd->vpic.palette = VIDEO_PALETTE_RGB24; | |
483 | ||
484 | memset(&uvd->vcap, 0, sizeof(uvd->vcap)); | |
485 | strcpy(uvd->vcap.name, "IBM Ultra Camera"); | |
486 | uvd->vcap.type = VID_TYPE_CAPTURE; | |
487 | uvd->vcap.channels = 1; | |
488 | uvd->vcap.audios = 0; | |
489 | uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas); | |
490 | uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas); | |
491 | uvd->vcap.minwidth = min_canvasWidth; | |
492 | uvd->vcap.minheight = min_canvasHeight; | |
493 | ||
494 | memset(&uvd->vchan, 0, sizeof(uvd->vchan)); | |
495 | uvd->vchan.flags = 0; | |
496 | uvd->vchan.tuners = 0; | |
497 | uvd->vchan.channel = 0; | |
498 | uvd->vchan.type = VIDEO_TYPE_CAMERA; | |
499 | strcpy(uvd->vchan.name, "Camera"); | |
500 | } | |
501 | ||
502 | /* | |
503 | * ultracam_probe() | |
504 | * | |
505 | * This procedure queries device descriptor and accepts the interface | |
506 | * if it looks like our camera. | |
507 | * | |
508 | * History: | |
509 | * 12-Nov-2000 Reworked to comply with new probe() signature. | |
510 | * 23-Jan-2001 Added compatibility with 2.2.x kernels. | |
511 | */ | |
512 | static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid) | |
513 | { | |
514 | struct usb_device *dev = interface_to_usbdev(intf); | |
515 | struct uvd *uvd = NULL; | |
516 | int ix, i, nas; | |
517 | int actInterface=-1, inactInterface=-1, maxPS=0; | |
518 | unsigned char video_ep = 0; | |
519 | ||
520 | if (debug >= 1) | |
a482f327 | 521 | dev_info(&intf->dev, "ultracam_probe\n"); |
1da177e4 LT |
522 | |
523 | /* We don't handle multi-config cameras */ | |
524 | if (dev->descriptor.bNumConfigurations != 1) | |
525 | return -ENODEV; | |
526 | ||
a482f327 GKH |
527 | dev_info(&intf->dev, "IBM Ultra camera found (rev. 0x%04x)\n", |
528 | le16_to_cpu(dev->descriptor.bcdDevice)); | |
1da177e4 LT |
529 | |
530 | /* Validate found interface: must have one ISO endpoint */ | |
531 | nas = intf->num_altsetting; | |
532 | if (debug > 0) | |
a482f327 GKH |
533 | dev_info(&intf->dev, "Number of alternate settings=%d.\n", |
534 | nas); | |
1da177e4 LT |
535 | if (nas < 8) { |
536 | err("Too few alternate settings for this camera!"); | |
537 | return -ENODEV; | |
538 | } | |
539 | /* Validate all alternate settings */ | |
540 | for (ix=0; ix < nas; ix++) { | |
541 | const struct usb_host_interface *interface; | |
542 | const struct usb_endpoint_descriptor *endpoint; | |
543 | ||
544 | interface = &intf->altsetting[ix]; | |
545 | i = interface->desc.bAlternateSetting; | |
546 | if (interface->desc.bNumEndpoints != 1) { | |
547 | err("Interface %d. has %u. endpoints!", | |
548 | interface->desc.bInterfaceNumber, | |
549 | (unsigned)(interface->desc.bNumEndpoints)); | |
550 | return -ENODEV; | |
551 | } | |
552 | endpoint = &interface->endpoint[0].desc; | |
553 | if (video_ep == 0) | |
554 | video_ep = endpoint->bEndpointAddress; | |
555 | else if (video_ep != endpoint->bEndpointAddress) { | |
556 | err("Alternate settings have different endpoint addresses!"); | |
557 | return -ENODEV; | |
558 | } | |
13417982 | 559 | if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) { |
1da177e4 LT |
560 | err("Interface %d. has non-ISO endpoint!", |
561 | interface->desc.bInterfaceNumber); | |
562 | return -ENODEV; | |
563 | } | |
13417982 | 564 | if (usb_endpoint_dir_out(endpoint)) { |
1da177e4 LT |
565 | err("Interface %d. has ISO OUT endpoint!", |
566 | interface->desc.bInterfaceNumber); | |
567 | return -ENODEV; | |
568 | } | |
569 | if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { | |
570 | if (inactInterface < 0) | |
571 | inactInterface = i; | |
572 | else { | |
573 | err("More than one inactive alt. setting!"); | |
574 | return -ENODEV; | |
575 | } | |
576 | } else { | |
577 | if (actInterface < 0) { | |
578 | actInterface = i; | |
579 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | |
580 | if (debug > 0) | |
a482f327 GKH |
581 | dev_info(&intf->dev, |
582 | "Active setting=%d. " | |
583 | "maxPS=%d.\n", i, maxPS); | |
1da177e4 LT |
584 | } else { |
585 | /* Got another active alt. setting */ | |
586 | if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) { | |
587 | /* This one is better! */ | |
588 | actInterface = i; | |
589 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | |
590 | if (debug > 0) { | |
a482f327 GKH |
591 | dev_info(&intf->dev, |
592 | "Even better ctive " | |
593 | "setting=%d. " | |
594 | "maxPS=%d.\n", | |
595 | i, maxPS); | |
1da177e4 LT |
596 | } |
597 | } | |
598 | } | |
599 | } | |
600 | } | |
601 | if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { | |
602 | err("Failed to recognize the camera!"); | |
603 | return -ENODEV; | |
604 | } | |
605 | ||
606 | uvd = usbvideo_AllocateDevice(cams); | |
607 | if (uvd != NULL) { | |
608 | /* Here uvd is a fully allocated uvd object */ | |
609 | uvd->flags = flags; | |
610 | uvd->debug = debug; | |
611 | uvd->dev = dev; | |
612 | uvd->iface = intf->altsetting->desc.bInterfaceNumber; | |
613 | uvd->ifaceAltInactive = inactInterface; | |
614 | uvd->ifaceAltActive = actInterface; | |
615 | uvd->video_endp = video_ep; | |
616 | uvd->iso_packet_len = maxPS; | |
617 | uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; | |
618 | uvd->defaultPalette = VIDEO_PALETTE_RGB24; | |
619 | uvd->canvas = VIDEOSIZE(640, 480); /* FIXME */ | |
620 | uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/ | |
621 | ||
622 | /* Initialize ibmcam-specific data */ | |
623 | assert(ULTRACAM_T(uvd) != NULL); | |
624 | ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */ | |
625 | ULTRACAM_T(uvd)->initialized = 0; | |
626 | ||
627 | ultracam_configure_video(uvd); | |
628 | ||
629 | i = usbvideo_RegisterVideoDevice(uvd); | |
630 | if (i != 0) { | |
631 | err("usbvideo_RegisterVideoDevice() failed."); | |
632 | uvd = NULL; | |
633 | } | |
634 | } | |
635 | ||
636 | if (uvd) { | |
637 | usb_set_intfdata (intf, uvd); | |
638 | return 0; | |
639 | } | |
640 | return -EIO; | |
641 | } | |
642 | ||
643 | ||
644 | static struct usb_device_id id_table[] = { | |
645 | { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) }, | |
646 | { } /* Terminating entry */ | |
647 | }; | |
648 | ||
649 | /* | |
650 | * ultracam_init() | |
651 | * | |
652 | * This code is run to initialize the driver. | |
653 | */ | |
654 | static int __init ultracam_init(void) | |
655 | { | |
656 | struct usbvideo_cb cbTbl; | |
657 | memset(&cbTbl, 0, sizeof(cbTbl)); | |
658 | cbTbl.probe = ultracam_probe; | |
659 | cbTbl.setupOnOpen = ultracam_setup_on_open; | |
660 | cbTbl.videoStart = ultracam_video_start; | |
661 | cbTbl.videoStop = ultracam_video_stop; | |
662 | cbTbl.processData = ultracam_ProcessIsocData; | |
663 | cbTbl.postProcess = usbvideo_DeinterlaceFrame; | |
664 | cbTbl.adjustPicture = ultracam_adjust_picture; | |
665 | cbTbl.getFPS = ultracam_calculate_fps; | |
666 | return usbvideo_register( | |
667 | &cams, | |
668 | MAX_CAMERAS, | |
669 | sizeof(ultracam_t), | |
670 | "ultracam", | |
671 | &cbTbl, | |
672 | THIS_MODULE, | |
673 | id_table); | |
674 | } | |
675 | ||
676 | static void __exit ultracam_cleanup(void) | |
677 | { | |
678 | usbvideo_Deregister(&cams); | |
679 | } | |
680 | ||
681 | MODULE_DEVICE_TABLE(usb, id_table); | |
682 | MODULE_LICENSE("GPL"); | |
683 | ||
684 | module_init(ultracam_init); | |
685 | module_exit(ultracam_cleanup); |