All Omnivision sensors now us software autoexposure calculations
[microdia.git] / sn9c20x-usb.c
blob713e9723a1c49ef4aa31163d438aa97c77104aaf
1 /**
2 * @file sn9c20x-usb.c
3 * @author Nicolas VIVIEN
4 * @date 2008-02-01
6 * @brief Driver for SN9C20X USB video camera
8 * @note Copyright (C) Nicolas VIVIEN
10 * @par Licences
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/kernel.h>
30 #include <linux/version.h>
31 #include <linux/errno.h>
32 #include <linux/slab.h>
33 #include <linux/kref.h>
34 #include <linux/stat.h>
36 #include <linux/usb.h>
37 #include <media/v4l2-common.h>
39 #include "sn9c20x.h"
40 #include "sn9c20x-bridge.h"
41 #include "micron.h"
42 #include "omnivision.h"
44 /**
45 * @var fps
46 * Module parameter to set frame per second
48 static __u8 fps = 25;
50 /**
51 * @var bulk
52 * Module parameter to enable/disable bulk transfers
54 static __u8 bulk;
56 /**
57 * @var jpeg
58 * Module parameter to enable/disable JPEG format
60 __u8 jpeg = 1;
62 /**
63 * @var bandwidth
64 * Module parameter to set the available bandwidth via the alternate setting
66 static __u8 bandwidth = 8;
68 /**
69 * @var hflip
70 * Module parameter to enable/disable the horizontal flip process
72 static __u8 hflip;
74 /**
75 * @var flip_detect
76 * Module parameter to enable/disable vflip detection
78 static __u8 flip_detect;
80 /**
81 * @var vflip
82 * Module parameter to enable/disable the vertical flip process
84 static __u8 vflip;
86 /**
87 * @var brightness
88 * Module parameter to set the brightness
90 static __u16 brightness = SN9C20X_PERCENT(50, 0xFF);
92 /**
93 * @var gamma
94 * Module parameter to set the gamma
96 static __u16 gamma = SN9C20X_PERCENT(20, 0xFF);
98 /**
99 * @var contrast
100 * Module parameter to set the contrast
102 static __u16 contrast = SN9C20X_PERCENT(50, 0xFF);
105 * @var exposure
106 * Module parameter to set the exposure
108 static __u16 exposure = SN9C20X_PERCENT(20, 0xFF);
111 * @var gain
112 * Module parameter to set the gain
114 static int gain = SN9C20X_PERCENT(20, 0xFF);
117 * @var sharpness
118 * Module parameter to set the sharpness
120 static __u16 sharpness = SN9C20X_PERCENT(50, 0x3F);
123 * @var red_gain
124 * Module parameter to set the red gain
126 static __u16 red_gain = SN9C20X_PERCENT(25, 0x7F);
129 * @var blue_gain
130 * Module parameter to set the blue gain
132 static __u16 blue_gain = SN9C20X_PERCENT(25, 0x7F);
135 * @var min_buffers
136 * Module parameter to set the minimum number of image buffers
138 static __u8 min_buffers = 2;
141 * @var max_buffers
142 * Module parameter to set the maximum number of image buffers
144 static __u8 max_buffers = 5;
147 * @var auto_exposure
148 * Module parameter to set the exposure
150 static __u8 auto_exposure;
153 * @var auto_gain
154 * Module parameter to set the gain
156 static __u8 auto_gain;
160 * @var auto_whitebalance
161 * Module parameter to set the auto-whitebalance
163 static __u8 auto_whitebalance = 1;
166 * @var log_level
167 * Module parameter to set the log level
169 __u8 log_level = 5;
173 * @var sn9c20x_table
174 * Define all the hotplug supported devices by this driver
176 static struct usb_device_id sn9c20x_table[] = {
177 /* SN9C201 + MI1300 */
178 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6240_PID, MT9M001_SENSOR, 0x5d)},
179 /* SN9C201 + MI1310 */
180 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6242_PID, MT9M111_SENSOR, 0x5d)},
181 /* SN9C201 + S5K4AAFX */
182 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6243_PID, 0, 0)},
183 /* SN9C201 + OV9655 */
184 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6248_PID, OV9655_SENSOR, 0x30)},
185 /* SN9C201 + CX1332 */
186 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_624B_PID, 0, 0)},
187 /* SN9C201 + MI1320 */
188 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_624C_PID, 0, 0)},
189 /* SN9C201 + SOI968 */
190 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_624E_PID, SOI968_SENSOR, 0x30)},
191 /* SN9C201 + OV9650 */
192 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_624F_PID, OV9650_SENSOR, 0x30)},
193 /* SN9C201 + OV9650 */
194 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6251_PID, OV9650_SENSOR, 0x30)},
195 /* SN9C201 + OV9650 */
196 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6253_PID, OV9650_SENSOR, 0x30)},
197 /* SN9C201 + OV7670ISP */
198 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6260_PID, OV7670_SENSOR, 0x21)},
199 /* SN9C201 + OM6802 */
200 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6262_PID, 0, 0)},
201 /* SN9C201 + MI0360/MT9V111 */
202 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6270_PID, 0, 0)},
203 /* SN9C201 + S5K53BEB */
204 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_627A_PID, 0, 0)},
205 /* SN9C201 + OV7660 */
206 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_627B_PID, OV7660_SENSOR, 0x21)},
207 /* SN9C201 + HV7131R */
208 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_627C_PID, HV7131R_SENSOR, 0x11)},
209 /* EEPROM */
210 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_627F_PID, OV9650_SENSOR, 0x30)},
211 /* SN9C202 + MI1300 */
212 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6280_PID, MT9M001_SENSOR, 0x5d)},
213 /* SN9C202 + MI1310 */
214 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6282_PID, MT9M111_SENSOR, 0x5d)},
215 /* SN9C202 + S5K4AAFX */
216 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6283_PID, 0, 0)},
217 /* SN9C202 + OV9655 */
218 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_6288_PID, OV9655_SENSOR, 0x30)},
219 /* SN9C202 + ICM107 */
220 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_628A_PID, 0, 0)},
221 /* SN9C202 + CX1332 */
222 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_628B_PID, 0, 0)},
223 /* SN9C202 + MI1320 */
224 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_628C_PID, 0, 0)},
225 /* SN9C202 + SOI968 */
226 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_628E_PID, SOI968_SENSOR, 0x30)},
227 /* SN9C202 + OV9650 */
228 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_628F_PID, OV9650_SENSOR, 0x30)},
229 /* SN9C202 + OV7670ISP */
230 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_62A0_PID, OV7670_SENSOR, 0x21)},
231 /* SN9C202 + OM6802 */
232 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_62A2_PID, 0, 0)},
233 /* SN9C202 + MI0360/MT9V111 */
234 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_62B0_PID, 0, 0)},
235 /* SN9C202 + OV9655 */
236 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_62B3_PID, OV9655_SENSOR, 0x30)},
237 /* SN9C202 + S5K53BEB */
238 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_62BA_PID, 0, 0)},
239 /* SN9C202 + OV7660 */
240 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_62BB_PID, OV7660_SENSOR, 0x21)},
241 /* SN9C202 + HV7131R */
242 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_62BC_PID, HV7131R_SENSOR, 0x11)},
243 /* SN9C202 + OV7663 */
244 {SN9C20X_USB_DEVICE(USB_0C45_VID, USB_62BE_PID, 0, 0)},
245 /* => 628f (SN9C202 + OV9650) */
246 {SN9C20X_USB_DEVICE(USB_045E_VID, USB_00F4_PID, OV9650_SENSOR, 0x30)},
247 /* => 627b (SN9C201 + OV7660) */
248 {SN9C20X_USB_DEVICE(USB_145F_VID, USB_013D_PID, OV7660_SENSOR, 0x21)},
249 /* => 62be (SN9C202 + OV7663 + EEPROM) */
250 {SN9C20X_USB_DEVICE(USB_04F2_VID, USB_A128_PID, 0, 0)},
255 MODULE_DEVICE_TABLE(usb, sn9c20x_table); /**< Define the supported devices */
257 DEFINE_MUTEX(open_lock); /**< Define global mutex */
259 struct usb_endpoint_descriptor *find_endpoint(struct usb_host_interface *alts,
260 __u8 epaddr)
262 unsigned long i;
263 struct usb_endpoint_descriptor *ep;
265 for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
266 ep = &alts->endpoint[i].desc;
267 if ((ep->bEndpointAddress & 0xf) == epaddr) {
268 UDIA_DEBUG("Found Endpoint 0x%X\n", epaddr);
269 return ep;
273 return NULL;
276 * @param dev Device structure
277 * @param ep Usb endpoint structure
279 * @returns 0 if all is OK
281 * @brief Initilize an isochronous pipe.
283 * This function permits to initialize an URB transfert (or isochronous pipe).
285 int usb_sn9c20x_isoc_init(struct usb_sn9c20x *dev,
286 struct usb_endpoint_descriptor *ep)
288 int i, j;
289 __u16 iso_max_frame_size;
290 struct urb *urb;
291 struct usb_device *udev;
293 udev = dev->udev;
295 UDIA_DEBUG("usb_sn9c20x_isoc_init()\n");
297 iso_max_frame_size =
298 max_packet_sz(le16_to_cpu(le16_to_cpu(ep->wMaxPacketSize))) *
299 hb_multiplier(le16_to_cpu(le16_to_cpu(ep->wMaxPacketSize)));
301 for (i = 0; i < MAX_URBS; i++) {
302 urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
304 if (urb == NULL) {
305 UDIA_ERROR("Failed to allocate URB %d\n", i);
306 usb_sn9c20x_uninit_urbs(dev);
307 return -ENOMEM;
310 urb->interval = 1;
311 urb->dev = udev;
312 urb->pipe = usb_rcvisocpipe(udev, ep->bEndpointAddress);
313 urb->transfer_flags = URB_ISO_ASAP;
314 urb->transfer_buffer_length = iso_max_frame_size * ISO_FRAMES_PER_DESC;
315 urb->complete = usb_sn9c20x_completion_handler;
316 urb->context = dev;
317 urb->start_frame = 0;
318 urb->number_of_packets = ISO_FRAMES_PER_DESC;
320 for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
321 urb->iso_frame_desc[j].offset = j * iso_max_frame_size;
322 urb->iso_frame_desc[j].length = iso_max_frame_size;
325 dev->urbs[i].data = kzalloc(urb->transfer_buffer_length,
326 GFP_KERNEL);
327 if (dev->urbs[i].data == NULL) {
328 usb_sn9c20x_uninit_urbs(dev);
329 return -ENOMEM;
332 urb->transfer_buffer = dev->urbs[i].data;
333 dev->urbs[i].urb = urb;
336 return 0;
339 int usb_sn9c20x_bulk_init(struct usb_sn9c20x *dev,
340 struct usb_endpoint_descriptor *ep)
342 struct urb *urb;
343 unsigned int pipe, i;
344 __u16 psize;
345 __u32 size;
346 psize = max_packet_sz(le16_to_cpu(le16_to_cpu(ep->wMaxPacketSize)));
347 size = psize * ISO_FRAMES_PER_DESC;
348 pipe = usb_rcvbulkpipe(dev->udev, ep->bEndpointAddress);
350 for (i = 0; i < MAX_URBS; ++i) {
351 urb = usb_alloc_urb(0, GFP_KERNEL);
352 if (urb == NULL) {
353 usb_sn9c20x_uninit_urbs(dev);
354 return -ENOMEM;
357 dev->urbs[i].data = kzalloc(size, GFP_KERNEL);
359 usb_fill_bulk_urb(urb, dev->udev, pipe,
360 dev->urbs[i].data, size,
361 usb_sn9c20x_completion_handler,
362 dev);
364 dev->urbs[i].urb = urb;
367 return 0;
370 int usb_sn9c20x_init_urbs(struct usb_sn9c20x *dev)
372 int ret, i;
373 __u8 value;
374 struct usb_endpoint_descriptor *ep;
375 struct usb_interface *intf = dev->interface;
377 ret = usb_sn9c20x_control_read(dev, 0x1061, &value, 1);
378 if (ret < 0)
379 return ret;
381 if (!bulk) {
382 if (bandwidth > 8)
383 return -EINVAL;
385 ep = find_endpoint(usb_altnum_to_altsetting(intf, bandwidth), SN9C20X_VID_ISOC);
386 if (ep == NULL)
387 return -EIO;
389 ret = usb_set_interface(dev->udev, 0, bandwidth);
390 if (ret < 0)
391 return ret;
393 value |= 0x01;
394 ret = usb_sn9c20x_control_write(dev, 0x1061, &value, 1);
395 if (ret < 0)
396 return ret;
398 ret = usb_sn9c20x_isoc_init(dev, ep);
399 } else {
400 ep = find_endpoint(usb_altnum_to_altsetting(intf, 0), SN9C20X_BULK);
401 if (ep == NULL)
402 return -EIO;
404 ret = usb_set_interface(dev->udev, 0, 0);
405 if (ret < 0)
406 return ret;
408 value &= ~0x01;
409 ret = usb_sn9c20x_control_write(dev, 0x1061, &value, 1);
410 if (ret < 0)
411 return ret;
413 ret = usb_sn9c20x_bulk_init(dev, ep);
416 if (ret < 0)
417 return ret;
419 for (i = 0; i < MAX_URBS; i++) {
420 ret = usb_submit_urb(dev->urbs[i].urb, GFP_KERNEL);
421 if (ret)
422 UDIA_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
425 return 0;
429 * @param dev Device structure
431 * @brief Clean-up all the ISOC buffers
433 * This function permits to clean-up all the ISOC buffers.
435 void usb_sn9c20x_uninit_urbs(struct usb_sn9c20x *dev)
437 int i;
438 struct urb *urb;
440 UDIA_DEBUG("Isoc cleanup\n");
442 if (dev == NULL)
443 return;
445 for (i = 0; i < MAX_URBS; i++) {
446 urb = dev->urbs[i].urb;
447 if (urb == NULL)
448 continue;
449 usb_kill_urb(urb);
450 kfree(dev->urbs[i].data);
451 usb_free_urb(urb);
452 dev->urbs[i].urb = NULL;
456 int usb_sn9c20x_detect_frame(unsigned char *buf, unsigned int buf_length)
458 unsigned char frame_header[] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
459 int index;
460 if (buf_length < 64)
461 return -1;
462 if (buf_length == 64) {
463 if (memcmp(buf, frame_header, 6) == 0)
464 return 0;
465 else
466 return -1;
468 for (index = 0; index < buf_length - 63; index++) {
469 if (memcmp(buf + index, frame_header, 6) == 0) {
470 UDIA_INFO("Found Header at %d\n", index);
471 return index;
474 return -1;
477 void usb_sn9c20x_assemble_video(struct usb_sn9c20x *dev,
478 unsigned char *transfer, unsigned int transfer_length,
479 struct sn9c20x_buffer **buffer)
481 void *mem = NULL;
482 unsigned char *header;
483 int header_index;
484 int yavg;
485 struct sn9c20x_buffer *buf = *buffer;
486 struct sn9c20x_video_queue *queue = &dev->queue;
488 if (buf->state != SN9C20X_BUF_STATE_ACTIVE)
489 buf->state = SN9C20X_BUF_STATE_ACTIVE;
491 header_index = usb_sn9c20x_detect_frame(transfer, transfer_length);
492 if (header_index >= 0) {
493 if (header_index + buf->buf.bytesused > buf->buf.length) {
494 UDIA_WARNING("Frame Buffer overflow!\n");
495 dev->vframes_overflow++;
496 buf->state = SN9C20X_BUF_STATE_DONE;
498 header_index = min(buf->buf.length - buf->buf.bytesused,
499 (unsigned int)header_index);
500 mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
501 memcpy(mem, transfer, header_index);
502 buf->buf.bytesused += header_index;
503 header = transfer+header_index;
504 /* UDIA_INFO("color window: %dx%d\n",
505 header[0x3a] << 4,
506 header[0x3b] << 3);
507 UDIA_INFO("Frame Size: %d\n", buf->buf.bytesused);*/
508 yavg = ((header[35] >> 2) & 3)|(header[20] << 2)|(header[19] << 10);
509 yavg += ((header[35] >> 4) & 3)|(header[22] << 2)|(header[21] << 10);
510 yavg += ((header[35] >> 6) & 3)|(header[24] << 2)|(header[23] << 10);
511 yavg += (header[36] & 3)|(header[26] << 2)|(header[25] << 10);
512 yavg += ((header[36] >> 2) & 3)|(header[28] << 2)|(header[27] << 10);
513 yavg += ((header[36] >> 4) & 3)|(header[30] << 2)|(header[29] << 10);
514 yavg += ((header[36] >> 6) & 3)|(header[32] << 2)|(header[31] << 10);
515 yavg += ((header[44] >> 4) & 3)|(header[34] << 2)|(header[33] << 10);
516 UDIA_DEBUG("AVGY Total: %d (%d)\n", yavg, yavg >> 9);
517 yavg >>= 9;
518 atomic_set(&dev->camera.yavg, yavg);
520 if (buf->buf.bytesused != 0)
521 buf->state = SN9C20X_BUF_STATE_DONE;
522 } else {
523 if (transfer_length + buf->buf.bytesused > buf->buf.length) {
524 UDIA_WARNING("Frame Buffer overflow!\n");
525 dev->vframes_overflow++;
526 buf->state = SN9C20X_BUF_STATE_DONE;
528 transfer_length = min(buf->buf.length - buf->buf.bytesused,
529 transfer_length);
530 mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
531 memcpy(mem, transfer, transfer_length);
532 buf->buf.bytesused += transfer_length;
534 if (buf->state == SN9C20X_BUF_STATE_DONE ||
535 buf->state == SN9C20X_BUF_STATE_ERROR) {
536 buf = sn9c20x_queue_next_buffer(queue, buf);
537 *buffer = buf;
538 if (buf == NULL) {
539 dev->vframes_dropped++;
540 } else {
541 if (header_index + 64 < transfer_length) {
542 memcpy(queue->mem + buf->buf.m.offset,
543 transfer + header_index + 64,
544 transfer_length - (header_index + 64));
545 buf->buf.bytesused +=
546 transfer_length - (header_index + 64);
552 * @param urb URB structure
554 * @brief ISOC handler
556 * This function is called as an URB transfert is complete (Isochronous pipe).
557 * So, the traitement is done in interrupt time, so it has be fast, not crash,
558 * and not stall. Neat.
560 void usb_sn9c20x_completion_handler(struct urb *urb)
562 int i;
563 int ret;
564 unsigned long flags;
566 unsigned char *transfer = NULL;
567 unsigned int transfer_length;
569 struct sn9c20x_buffer *buf = NULL;
570 struct usb_sn9c20x *dev = urb->context;
571 struct sn9c20x_video_queue *queue = &dev->queue;
573 UDIA_STREAM("Isoc handler\n");
575 switch (urb->status) {
576 case 0:
577 break;
579 default:
580 UDIA_WARNING("Non-zero status (%d) in video "
581 "completion handler.\n", urb->status);
583 case -ENOENT: /* usb_kill_urb() called. */
584 if (dev->frozen)
585 return;
587 case -ECONNRESET: /* usb_unlink_urb() called. */
588 case -ESHUTDOWN: /* The endpoint is being disabled. */
589 sn9c20x_queue_cancel(queue, urb->status == -ESHUTDOWN);
590 return;
593 spin_lock_irqsave(&queue->irqlock, flags);
594 if (!list_empty(&queue->irqqueue))
595 buf = list_first_entry(&queue->irqqueue, struct sn9c20x_buffer,
596 queue);
597 spin_unlock_irqrestore(&queue->irqlock, flags);
598 if (!bulk) {
599 for (i = 0; i < urb->number_of_packets; i++) {
600 if (urb->iso_frame_desc[i].status != 0) {
601 UDIA_ERROR("Iso frame %d of USB has error %d\n",
602 i, urb->iso_frame_desc[i].status);
603 continue;
605 transfer_length = urb->iso_frame_desc[i].actual_length;
606 transfer = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
607 if (buf == NULL)
608 continue;
610 usb_sn9c20x_assemble_video(dev, transfer, transfer_length, &buf);
612 } else {
613 if (buf != NULL) {
614 usb_sn9c20x_assemble_video(dev, urb->transfer_buffer,
615 urb->actual_length, &buf);
618 ret = usb_submit_urb(urb, GFP_ATOMIC);
620 if (ret != 0) {
621 UDIA_ERROR("Error (%d) re-submitting urb in "
622 "sn9c20x_isoc_handler.\n", ret);
627 * @param dev Device structure
628 * @param value register to write to
629 * @param data
630 * @param length number of bytes
632 * @returns 0 if all is OK
634 * @brief Write a 16-bit value to a 16-bit register
636 * This function permits to write a 16-bit value to a 16-bit register on the USB bus.
638 int usb_sn9c20x_control_write(struct usb_sn9c20x *dev, __u16 value, __u8 *data, __u16 length)
640 int result;
641 struct usb_device *udev = dev->udev;
643 result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
644 0x08,
645 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
646 value,
647 0x00,
648 data,
649 length,
650 500);
652 if (result < 0)
653 UDIA_ERROR("Write register failed index = 0x%02X\n", value);
655 return result;
659 * @param dev Device structure
660 * @param index register to read from
661 * @param data
662 * @param length number of bytes
664 * @returns 0 if all is OK
666 * @brief Read a 16-bit value from a 16-bit register
668 * This function permits to read a 16-bit value from a 16-bit register on the USB bus.
670 int usb_sn9c20x_control_read(struct usb_sn9c20x *dev, __u16 index, __u8 *data, __u16 length)
672 int result;
674 struct usb_device *udev = dev->udev;
676 *data = 0;
678 result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
679 0x00,
680 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
681 index,
682 0x00,
683 data,
684 length,
685 500);
687 if (result < 0)
688 UDIA_ERROR("Read register failed 0x%02X\n", index);
690 return result;
695 * @param dev
697 * @returns 0 if all is OK
699 * @brief Set the default value about the video settings.
701 * This function permits to set the video settings for each video camera model.
704 static int usb_sn9c20x_default_settings(struct usb_sn9c20x *dev)
706 dev->vframes_overflow = 0;
707 dev->vframes_incomplete = 0;
708 dev->vframes_dropped = 0;
710 dev->queue.min_buffers = min_buffers;
711 dev->queue.max_buffers = max_buffers;
713 dev->vsettings.fps = fps;
715 v4l2_set_control_default(dev, V4L2_CID_HFLIP, hflip);
716 v4l2_set_control_default(dev, V4L2_CID_VFLIP, vflip);
717 v4l2_set_control_default(dev, V4L2_CID_GAIN, gain);
718 v4l2_set_control_default(dev, V4L2_CID_BRIGHTNESS, brightness);
719 v4l2_set_control_default(dev, V4L2_CID_CONTRAST, contrast);
720 v4l2_set_control_default(dev, V4L2_CID_GAMMA, gamma);
721 v4l2_set_control_default(dev, V4L2_CID_SHARPNESS, sharpness);
722 v4l2_set_control_default(dev, V4L2_CID_RED_BALANCE, red_gain);
723 v4l2_set_control_default(dev, V4L2_CID_BLUE_BALANCE, blue_gain);
724 v4l2_set_control_default(dev, V4L2_CID_EXPOSURE_AUTO, auto_exposure);
725 v4l2_set_control_default(dev, V4L2_CID_AUTOGAIN, auto_gain);
726 v4l2_set_control_default(dev, V4L2_CID_AUTO_WHITE_BALANCE, auto_whitebalance);
727 v4l2_set_control_default(dev, V4L2_CID_EXPOSURE, exposure);
729 sn9c20x_set_resolution(dev, 640, 480);
730 sn9c20x_set_format(dev, sn9c20x_fmts[0].pix_fmt);
732 return 0;
736 * @brief Load the driver
738 * @param interface
739 * @param id
741 * @returns 0 if all is OK
743 * This function detects the device and allocate the buffers for the device
744 * and the video interface.
746 static int usb_sn9c20x_probe(struct usb_interface *interface, const struct usb_device_id *id)
748 int ret;
750 int vendor_id;
751 int product_id;
752 int bNumInterfaces;
754 struct usb_sn9c20x *dev = NULL;
755 struct usb_device *udev = interface_to_usbdev(interface);
757 /* Get USB VendorID and ProductID */
758 vendor_id = le16_to_cpu(udev->descriptor.idVendor);
759 product_id = le16_to_cpu(udev->descriptor.idProduct);
761 /* Check if we can handle this device */
762 UDIA_DEBUG("Probe function called with VendorID=%04X, ProductID=%04X and InterfaceNumber=%d\n",
763 vendor_id, product_id, interface->cur_altsetting->desc.bInterfaceNumber);
765 UDIA_INFO("SN9C20X USB 2.0 Webcam - %04X:%04X plugged-in.\n",
766 vendor_id, product_id);
770 // Allocate structure, initialize pointers, mutexes, etc.
771 // and link it to the usb_device
773 dev = kzalloc(sizeof(struct usb_sn9c20x), GFP_KERNEL);
775 if (dev == NULL) {
776 UDIA_ERROR("Out of memory !\n");
777 ret = -ENOMEM;
778 goto error;
781 /* Init mutexes, spinlock, etc. */
782 mutex_init(&dev->mutex);
783 kref_init(&dev->vopen);
785 dev->udev = udev;
786 dev->interface = interface;
788 /* Read the product release */
789 dev->release = le16_to_cpu(udev->descriptor.bcdDevice);
790 UDIA_DEBUG("Release: %04x\n", dev->release);
792 /* How many interfaces (1 or 3) ? */
793 bNumInterfaces = udev->config->desc.bNumInterfaces;
794 UDIA_DEBUG("Number of interfaces : %d\n", bNumInterfaces);
796 dev->camera.sensor = id->driver_info & 0xFF;
797 dev->camera.address = (id->driver_info >> 8) & 0xFF;
799 /* Initialize the camera */
800 ret = sn9c20x_initialize(dev);
801 if (ret < 0)
802 goto error;
804 /* Initialize the video device */
805 dev->vdev = video_device_alloc();
807 if (!dev->vdev) {
808 ret = -ENOMEM;
809 goto free_dev;
812 /* Register the video device */
813 ret = v4l_sn9c20x_register_video_device(dev);
815 if (ret)
816 goto free_dev;
818 /* Create the entries in the sys filesystem */
819 sn9c20x_create_sysfs_files(dev->vdev);
821 sn9c20x_create_debugfs_files(dev);
823 /* Save our data pointer in this interface device */
824 usb_set_intfdata(interface, dev);
826 usb_sn9c20x_default_settings(dev);
828 return 0;
830 free_dev:
831 kref_put(&dev->vopen, usb_sn9c20x_delete);
832 error:
833 return ret;
836 void usb_sn9c20x_delete(struct kref *kref)
838 struct usb_sn9c20x *dev;
839 dev = container_of(kref, struct usb_sn9c20x, vopen);
841 if (dev->vdev != NULL) {
842 sn9c20x_remove_sysfs_files(dev->vdev);
843 sn9c20x_remove_debugfs_files(dev);
844 v4l_sn9c20x_unregister_video_device(dev);
846 kfree(dev);
850 * @param interface
852 * @brief This function is called when the device is disconnected
853 * or when the kernel module is unloaded.
855 static void usb_sn9c20x_disconnect(struct usb_interface *interface)
857 struct usb_sn9c20x *dev = usb_get_intfdata(interface);
859 UDIA_INFO("SN9C20X USB 2.0 Webcam unplugged\n");
861 usb_set_intfdata(interface, NULL);
863 mutex_lock(&open_lock);
864 kref_put(&dev->vopen, usb_sn9c20x_delete);
865 mutex_unlock(&open_lock);
870 * @var usb_sn9c20x_driver
872 * This variable contains some callback
874 static struct usb_driver usb_sn9c20x_driver = {
875 .name = "usb_sn9c20x_driver",
876 .probe = usb_sn9c20x_probe,
877 .disconnect = usb_sn9c20x_disconnect,
878 .id_table = sn9c20x_table,
881 module_param(fps, byte, 0444); /**< @brief Module parameter frames per second */
882 module_param(bulk, byte, 0444);
883 module_param(jpeg, byte, 0444);
884 module_param(bandwidth, byte, 0444);
885 module_param(hflip, byte, 0444); /**< @brief Module parameter horizontal flip process */
886 module_param(vflip, byte, 0444); /**< @brief Module parameter vertical flip process */
887 module_param(flip_detect, byte, 0444); /**< @brief Module parameter flip detect */
888 module_param(auto_exposure, byte, 0444); /**< @brief Module parameter automatic exposure control */
889 module_param(auto_gain, byte, 0444); /**< @brief Module parameter automatic gain control */
890 module_param(auto_whitebalance, byte, 0444); /**< @brief Module parameter automatic whitebalance control */
891 module_param(brightness, ushort, 0444); /**< @brief Module parameter brightness */
892 module_param(gamma, ushort, 0444); /**< @brief Module parameter gamma */
893 module_param(contrast, ushort, 0444); /**< @brief Module parameter contrast */
894 module_param(exposure, ushort, 0444); /**< @brief Module parameter exposure */
895 module_param(sharpness, ushort, 0444); /**< @brief Module parameter sharpness */
896 module_param(red_gain, ushort, 0444); /**< @brief Module parameter red gain */
897 module_param(blue_gain, ushort, 0444); /**< @brief Module parameter blue gain */
899 module_param(min_buffers, byte, 0444);
900 module_param(max_buffers, byte, 0444);
902 module_param(log_level, byte, 0444);
905 * @returns 0 if all is OK
907 * @brief Initialize the driver.
909 * This function is called at first.
910 * This function permits to define the default values from the command line.
912 static int __init usb_sn9c20x_init(void)
914 int result;
916 UDIA_INFO("SN9C20X USB 2.0 webcam driver loaded\n");
918 sn9c20x_init_debugfs();
920 if (fps < 10 || fps > 30) {
921 UDIA_WARNING("Framerate out of bounds [10-30]! Defaulting to 25\n");
922 fps = 25;
925 if (bandwidth < 1 || bandwidth > 8) {
926 UDIA_WARNING("Bandwidth out of bounds [1-8]! Defaulting to 8\n");
927 bandwidth = 8;
930 if (bulk != 0 && bulk != 1) {
931 UDIA_WARNING("Bulk transfer should be 0 or 1! Defaulting to 0\n");
932 bulk = 0;
935 if (jpeg != 0 && jpeg != 1) {
936 UDIA_WARNING("JPEG should be 0 or 1! Defaulting to 1\n");
937 jpeg = 1;
940 if (vflip != 0 && vflip != 1) {
941 UDIA_WARNING("Vertical flip should be 0 or 1! Defaulting to 0\n");
942 vflip = 0;
945 if (hflip != 0 && hflip != 1) {
946 UDIA_WARNING("Horizontal flip should be 0 or 1! Defaulting to 0\n");
947 hflip = 0;
950 if (sharpness > 0x3f) {
951 UDIA_WARNING("Sharpness should be 0 to 63 ! Defaulting to 31\n");
952 sharpness = 0x1f;
955 if (red_gain > 0x7f) {
956 UDIA_WARNING("Red Gain should be 0 to 127 ! Defaulting to 31\n");
957 red_gain = 31;
960 if (blue_gain > 0x7f) {
961 UDIA_WARNING("Blue Gain should be 0 to 127 ! Defaulting to 31\n");
962 blue_gain = 31;
965 if (auto_exposure > 3) {
966 UDIA_WARNING("Automatic exposure should be 0, 1, 2 or 3! "
967 "Defaulting to 0\n");
968 auto_exposure = 0;
971 if (auto_gain != 0 && auto_gain != 1) {
972 UDIA_WARNING("Automatic gain should be 0 or 1! "
973 "Defaulting to 0\n");
974 auto_gain = 0;
977 if (auto_whitebalance != 0 && auto_whitebalance != 1) {
978 UDIA_WARNING("Automatic whitebalance should be 0 or 1! "
979 "Defaulting to 1\n");
980 auto_whitebalance = 1;
983 if (min_buffers < 2) {
984 UDIA_WARNING("Minimum buffers can't be less then 2! "
985 "Defaulting to 2\n");
986 min_buffers = 2;
990 if (min_buffers > max_buffers) {
991 UDIA_WARNING("Minimum buffers must be less then or equal to "
992 "max buffers! Defaulting to 2, 10\n");
993 min_buffers = 2;
994 max_buffers = 5;
997 /* Register the driver with the USB subsystem */
998 result = usb_register(&usb_sn9c20x_driver);
1000 if (result)
1001 UDIA_ERROR("usb_register failed ! Error number %d\n", result);
1003 UDIA_INFO(DRIVER_VERSION " : " DRIVER_DESC "\n");
1005 return result;
1010 * @brief Close the driver
1012 * This function is called at last when you unload the driver.
1014 static void __exit usb_sn9c20x_exit(void)
1016 UDIA_INFO("usb_sn9c20x_exit: SN9C20X USB 2.0 webcam driver unloaded\n");
1018 sn9c20x_uninit_debugfs();
1020 /* Deregister this driver with the USB subsystem */
1021 usb_deregister(&usb_sn9c20x_driver);
1025 module_init(usb_sn9c20x_init); /**< @brief Module initialize */
1026 module_exit(usb_sn9c20x_exit); /**< @brief Module exit */
1029 MODULE_PARM_DESC(fps, "Frames per second [10-30]"); /**< @brief Description of 'fps' parameter */
1031 MODULE_PARM_DESC(jpeg, "Enable JPEG support (default is enabled)");
1032 MODULE_PARM_DESC(bulk, "Enable Bulk transfer (default is to use ISOC)");
1033 MODULE_PARM_DESC(bandwidth, "Bandwidth Setting (only for ISOC)");
1035 MODULE_PARM_DESC(hflip, "Horizontal image flip"); /**< @brief Description of 'hflip' parameter */
1036 MODULE_PARM_DESC(vflip, "Vertical image flip"); /**< @brief Description of 'vflip' parameter */
1037 MODULE_PARM_DESC(flip_detect, "Image flip detection"); /**< @brief Description of 'vflip_detect' parameter */
1038 MODULE_PARM_DESC(auto_exposure, "Automatic exposure control"); /**< @brief Description of 'auto_exposure' parameter */
1039 MODULE_PARM_DESC(auto_gain, "Automatic gain control"); /**< @brief Description of 'auto_gain' parameter */
1040 MODULE_PARM_DESC(auto_whitebalance, "Automatic whitebalance"); /**< @brief Description of 'auto_whitebalance' parameter */
1041 MODULE_PARM_DESC(brightness, "Brightness setting"); /**< @brief Description of 'brightness' parameter */
1042 MODULE_PARM_DESC(gamma, "Gamma setting"); /**< @brief Description of 'gamma' parameter */
1043 MODULE_PARM_DESC(exposure, "Exposure setting"); /**< @brief Description of 'exposure' parameter */
1044 MODULE_PARM_DESC(gain, "Gain setting"); /**< @brief Description of 'gain' parameter */
1045 MODULE_PARM_DESC(contrast, "Contrast setting"); /**< @brief Description of 'contrast' parameter */
1046 MODULE_PARM_DESC(sharpness, "Sharpness setting"); /**< @brief Description of 'sharpness' parameter */
1047 MODULE_PARM_DESC(red_gain, "Red Gain setting"); /**< @brief Description of 'Red Gain' parameter */
1048 MODULE_PARM_DESC(blue_gain, "Blue Gain setting"); /**< @brief Description of 'Blue Gain' parameter */
1050 MODULE_PARM_DESC(min_buffers, "Minimum number of image buffers");
1051 MODULE_PARM_DESC(max_buffers, "Maximum number of image buffers");
1052 MODULE_PARM_DESC(log_level, " <n>\n"
1053 "Driver log level\n"
1054 "1 = info (default)\n"
1055 "2 = warning\n"
1056 "4 = error\n"
1057 "8 = debug\n"
1058 "16 = stream\n");
1060 MODULE_LICENSE("GPL"); /**< @brief Driver is under licence GPL */
1061 MODULE_AUTHOR(DRIVER_AUTHOR); /**< @brief Driver is written by Nicolas VIVIEN */
1062 MODULE_DESCRIPTION(DRIVER_DESC); /**< @brief Define the description of the driver */
1063 MODULE_SUPPORTED_DEVICE(DRIVER_SUPPORT); /**< @brief List of supported device */