3 * @author Nicolas VIVIEN
6 * @brief Driver for SN9C20X USB video camera
8 * @note Copyright (C) Nicolas VIVIEN
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
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>
40 #include "sn9c20x-bridge.h"
42 #include "omnivision.h"
46 * Module parameter to set frame per second
52 * Module parameter to enable/disable bulk transfers
58 * Module parameter to enable/disable JPEG format
64 * Module parameter to set the available bandwidth via the alternate setting
66 static __u8 bandwidth
= 8;
70 * Module parameter to enable/disable the horizontal flip process
76 * Module parameter to enable/disable vflip detection
78 static __u8 flip_detect
;
82 * Module parameter to enable/disable the vertical flip process
88 * Module parameter to set the brightness
90 static __u16 brightness
= SN9C20X_PERCENT(50, 0xFF);
94 * Module parameter to set the gamma
96 static __u16 gamma
= SN9C20X_PERCENT(20, 0xFF);
100 * Module parameter to set the contrast
102 static __u16 contrast
= SN9C20X_PERCENT(50, 0xFF);
106 * Module parameter to set the exposure
108 static __u16 exposure
= SN9C20X_PERCENT(20, 0xFF);
112 * Module parameter to set the gain
114 static int gain
= SN9C20X_PERCENT(20, 0xFF);
118 * Module parameter to set the sharpness
120 static __u16 sharpness
= SN9C20X_PERCENT(50, 0x3F);
124 * Module parameter to set the red gain
126 static __u16 red_gain
= SN9C20X_PERCENT(25, 0x7F);
130 * Module parameter to set the blue gain
132 static __u16 blue_gain
= SN9C20X_PERCENT(25, 0x7F);
136 * Module parameter to set the minimum number of image buffers
138 static __u8 min_buffers
= 2;
142 * Module parameter to set the maximum number of image buffers
144 static __u8 max_buffers
= 5;
148 * Module parameter to set the exposure
150 static __u8 auto_exposure
;
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;
167 * Module parameter to set the log level
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)},
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
,
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
);
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
)
289 __u16 iso_max_frame_size
;
291 struct usb_device
*udev
;
295 UDIA_DEBUG("usb_sn9c20x_isoc_init()\n");
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
);
305 UDIA_ERROR("Failed to allocate URB %d\n", i
);
306 usb_sn9c20x_uninit_urbs(dev
);
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
;
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
,
327 if (dev
->urbs
[i
].data
== NULL
) {
328 usb_sn9c20x_uninit_urbs(dev
);
332 urb
->transfer_buffer
= dev
->urbs
[i
].data
;
333 dev
->urbs
[i
].urb
= urb
;
339 int usb_sn9c20x_bulk_init(struct usb_sn9c20x
*dev
,
340 struct usb_endpoint_descriptor
*ep
)
343 unsigned int pipe
, i
;
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
);
353 usb_sn9c20x_uninit_urbs(dev
);
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
,
364 dev
->urbs
[i
].urb
= urb
;
370 int usb_sn9c20x_init_urbs(struct usb_sn9c20x
*dev
)
374 struct usb_endpoint_descriptor
*ep
;
375 struct usb_interface
*intf
= dev
->interface
;
377 ret
= usb_sn9c20x_control_read(dev
, 0x1061, &value
, 1);
385 ep
= find_endpoint(usb_altnum_to_altsetting(intf
, bandwidth
), SN9C20X_VID_ISOC
);
389 ret
= usb_set_interface(dev
->udev
, 0, bandwidth
);
394 ret
= usb_sn9c20x_control_write(dev
, 0x1061, &value
, 1);
398 ret
= usb_sn9c20x_isoc_init(dev
, ep
);
400 ep
= find_endpoint(usb_altnum_to_altsetting(intf
, 0), SN9C20X_BULK
);
404 ret
= usb_set_interface(dev
->udev
, 0, 0);
409 ret
= usb_sn9c20x_control_write(dev
, 0x1061, &value
, 1);
413 ret
= usb_sn9c20x_bulk_init(dev
, ep
);
419 for (i
= 0; i
< MAX_URBS
; i
++) {
420 ret
= usb_submit_urb(dev
->urbs
[i
].urb
, GFP_KERNEL
);
422 UDIA_ERROR("isoc_init() submit_urb %d failed with error %d\n", i
, ret
);
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
)
440 UDIA_DEBUG("Isoc cleanup\n");
445 for (i
= 0; i
< MAX_URBS
; i
++) {
446 urb
= dev
->urbs
[i
].urb
;
450 kfree(dev
->urbs
[i
].data
);
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};
462 if (buf_length
== 64) {
463 if (memcmp(buf
, frame_header
, 6) == 0)
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
);
477 void usb_sn9c20x_assemble_video(struct usb_sn9c20x
*dev
,
478 unsigned char *transfer
, unsigned int transfer_length
,
479 struct sn9c20x_buffer
**buffer
)
482 unsigned char *header
;
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",
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);
518 atomic_set(&dev
->camera
.yavg
, yavg
);
520 if (buf
->buf
.bytesused
!= 0)
521 buf
->state
= SN9C20X_BUF_STATE_DONE
;
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
,
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
);
539 dev
->vframes_dropped
++;
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
)
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
) {
580 UDIA_WARNING("Non-zero status (%d) in video "
581 "completion handler.\n", urb
->status
);
583 case -ENOENT
: /* usb_kill_urb() called. */
587 case -ECONNRESET
: /* usb_unlink_urb() called. */
588 case -ESHUTDOWN
: /* The endpoint is being disabled. */
589 sn9c20x_queue_cancel(queue
, urb
->status
== -ESHUTDOWN
);
593 spin_lock_irqsave(&queue
->irqlock
, flags
);
594 if (!list_empty(&queue
->irqqueue
))
595 buf
= list_first_entry(&queue
->irqqueue
, struct sn9c20x_buffer
,
597 spin_unlock_irqrestore(&queue
->irqlock
, flags
);
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
);
605 transfer_length
= urb
->iso_frame_desc
[i
].actual_length
;
606 transfer
= urb
->transfer_buffer
+ urb
->iso_frame_desc
[i
].offset
;
610 usb_sn9c20x_assemble_video(dev
, transfer
, transfer_length
, &buf
);
614 usb_sn9c20x_assemble_video(dev
, urb
->transfer_buffer
,
615 urb
->actual_length
, &buf
);
618 ret
= usb_submit_urb(urb
, GFP_ATOMIC
);
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
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
)
641 struct usb_device
*udev
= dev
->udev
;
643 result
= usb_control_msg(udev
, usb_sndctrlpipe(udev
, 0),
645 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_INTERFACE
,
653 UDIA_ERROR("Write register failed index = 0x%02X\n", value
);
659 * @param dev Device structure
660 * @param index register to read from
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
)
674 struct usb_device
*udev
= dev
->udev
;
678 result
= usb_control_msg(udev
, usb_rcvctrlpipe(udev
, 0),
680 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_INTERFACE
,
688 UDIA_ERROR("Read register failed 0x%02X\n", index
);
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
);
736 * @brief Load the driver
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
)
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
);
776 UDIA_ERROR("Out of memory !\n");
781 /* Init mutexes, spinlock, etc. */
782 mutex_init(&dev
->mutex
);
783 kref_init(&dev
->vopen
);
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
);
804 /* Initialize the video device */
805 dev
->vdev
= video_device_alloc();
812 /* Register the video device */
813 ret
= v4l_sn9c20x_register_video_device(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
);
831 kref_put(&dev
->vopen
, usb_sn9c20x_delete
);
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
);
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)
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");
925 if (bandwidth
< 1 || bandwidth
> 8) {
926 UDIA_WARNING("Bandwidth out of bounds [1-8]! Defaulting to 8\n");
930 if (bulk
!= 0 && bulk
!= 1) {
931 UDIA_WARNING("Bulk transfer should be 0 or 1! Defaulting to 0\n");
935 if (jpeg
!= 0 && jpeg
!= 1) {
936 UDIA_WARNING("JPEG should be 0 or 1! Defaulting to 1\n");
940 if (vflip
!= 0 && vflip
!= 1) {
941 UDIA_WARNING("Vertical flip should be 0 or 1! Defaulting to 0\n");
945 if (hflip
!= 0 && hflip
!= 1) {
946 UDIA_WARNING("Horizontal flip should be 0 or 1! Defaulting to 0\n");
950 if (sharpness
> 0x3f) {
951 UDIA_WARNING("Sharpness should be 0 to 63 ! Defaulting to 31\n");
955 if (red_gain
> 0x7f) {
956 UDIA_WARNING("Red Gain should be 0 to 127 ! Defaulting to 31\n");
960 if (blue_gain
> 0x7f) {
961 UDIA_WARNING("Blue Gain should be 0 to 127 ! Defaulting to 31\n");
965 if (auto_exposure
> 3) {
966 UDIA_WARNING("Automatic exposure should be 0, 1, 2 or 3! "
967 "Defaulting to 0\n");
971 if (auto_gain
!= 0 && auto_gain
!= 1) {
972 UDIA_WARNING("Automatic gain should be 0 or 1! "
973 "Defaulting to 0\n");
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");
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");
997 /* Register the driver with the USB subsystem */
998 result
= usb_register(&usb_sn9c20x_driver
);
1001 UDIA_ERROR("usb_register failed ! Error number %d\n", result
);
1003 UDIA_INFO(DRIVER_VERSION
" : " DRIVER_DESC
"\n");
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"
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 */