diff options
-rw-r--r-- | Documentation/video4linux/sn9c102.txt | 246 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/Kconfig | 4 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102.h | 57 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_config.h | 86 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_core.c | 719 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_devtable.h | 142 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_hv7131d.c | 7 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_mi0343.c | 7 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_ov7630.c | 336 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_ov7660.c | 592 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_pas106b.c | 7 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_pas202bca.c | 238 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_pas202bcb.c | 97 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_sensor.h | 168 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_tas5110c1b.c | 8 | ||||
-rw-r--r-- | drivers/media/video/sn9c102/sn9c102_tas5130d1b.c | 8 |
17 files changed, 1894 insertions, 830 deletions
diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt index 8cda472db36d..2913da3d0878 100644 --- a/Documentation/video4linux/sn9c102.txt +++ b/Documentation/video4linux/sn9c102.txt | |||
@@ -1,5 +1,5 @@ | |||
1 | 1 | ||
2 | SN9C10x PC Camera Controllers | 2 | SN9C1xx PC Camera Controllers |
3 | Driver for Linux | 3 | Driver for Linux |
4 | ============================= | 4 | ============================= |
5 | 5 | ||
@@ -53,20 +53,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
53 | 53 | ||
54 | 4. Overview and features | 54 | 4. Overview and features |
55 | ======================== | 55 | ======================== |
56 | This driver attempts to support the video interface of the devices mounting the | 56 | This driver attempts to support the video interface of the devices assembling |
57 | SONiX SN9C101, SN9C102 and SN9C103 PC Camera Controllers. | 57 | the SONiX SN9C101, SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers |
58 | 58 | ("SN9C1xx" from now on). | |
59 | It's worth to note that SONiX has never collaborated with the author during the | ||
60 | development of this project, despite several requests for enough detailed | ||
61 | specifications of the register tables, compression engine and video data format | ||
62 | of the above chips. Nevertheless, these informations are no longer necessary, | ||
63 | because all the aspects related to these chips are known and have been | ||
64 | described in detail in this documentation. | ||
65 | 59 | ||
66 | The driver relies on the Video4Linux2 and USB core modules. It has been | 60 | The driver relies on the Video4Linux2 and USB core modules. It has been |
67 | designed to run properly on SMP systems as well. | 61 | designed to run properly on SMP systems as well. |
68 | 62 | ||
69 | The latest version of the SN9C10x driver can be found at the following URL: | 63 | The latest version of the SN9C1xx driver can be found at the following URL: |
70 | http://www.linux-projects.org/ | 64 | http://www.linux-projects.org/ |
71 | 65 | ||
72 | Some of the features of the driver are: | 66 | Some of the features of the driver are: |
@@ -85,11 +79,11 @@ Some of the features of the driver are: | |||
85 | high compression quality (see also "Notes for V4L2 application developers" | 79 | high compression quality (see also "Notes for V4L2 application developers" |
86 | and "Video frame formats" paragraphs); | 80 | and "Video frame formats" paragraphs); |
87 | - full support for the capabilities of many of the possible image sensors that | 81 | - full support for the capabilities of many of the possible image sensors that |
88 | can be connected to the SN9C10x bridges, including, for instance, red, green, | 82 | can be connected to the SN9C1xx bridges, including, for instance, red, green, |
89 | blue and global gain adjustments and exposure (see "Supported devices" | 83 | blue and global gain adjustments and exposure (see "Supported devices" |
90 | paragraph for details); | 84 | paragraph for details); |
91 | - use of default color settings for sunlight conditions; | 85 | - use of default color settings for sunlight conditions; |
92 | - dynamic I/O interface for both SN9C10x and image sensor control and | 86 | - dynamic I/O interface for both SN9C1xx and image sensor control and |
93 | monitoring (see "Optional device control through 'sysfs'" paragraph); | 87 | monitoring (see "Optional device control through 'sysfs'" paragraph); |
94 | - dynamic driver control thanks to various module parameters (see "Module | 88 | - dynamic driver control thanks to various module parameters (see "Module |
95 | parameters" paragraph); | 89 | parameters" paragraph); |
@@ -130,8 +124,8 @@ necessary: | |||
130 | CONFIG_USB_UHCI_HCD=m | 124 | CONFIG_USB_UHCI_HCD=m |
131 | CONFIG_USB_OHCI_HCD=m | 125 | CONFIG_USB_OHCI_HCD=m |
132 | 126 | ||
133 | The SN9C103 controller also provides a built-in microphone interface. It is | 127 | The SN9C103, SN9c105 and SN9C120 controllers also provide a built-in microphone |
134 | supported by the USB Audio driver thanks to the ALSA API: | 128 | interface. It is supported by the USB Audio driver thanks to the ALSA API: |
135 | 129 | ||
136 | # Sound | 130 | # Sound |
137 | # | 131 | # |
@@ -155,18 +149,27 @@ And finally: | |||
155 | 6. Module loading | 149 | 6. Module loading |
156 | ================= | 150 | ================= |
157 | To use the driver, it is necessary to load the "sn9c102" module into memory | 151 | To use the driver, it is necessary to load the "sn9c102" module into memory |
158 | after every other module required: "videodev", "usbcore" and, depending on | 152 | after every other module required: "videodev", "v4l2_common", "compat_ioctl32", |
159 | the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd". | 153 | "usbcore" and, depending on the USB host controller you have, "ehci-hcd", |
154 | "uhci-hcd" or "ohci-hcd". | ||
160 | 155 | ||
161 | Loading can be done as shown below: | 156 | Loading can be done as shown below: |
162 | 157 | ||
163 | [root@localhost home]# modprobe sn9c102 | 158 | [root@localhost home]# modprobe sn9c102 |
164 | 159 | ||
165 | At this point the devices should be recognized. You can invoke "dmesg" to | 160 | Note that the module is called "sn9c102" for historic reasons, althought it |
166 | analyze kernel messages and verify that the loading process has gone well: | 161 | does not just support the SN9C102. |
162 | |||
163 | At this point all the devices supported by the driver and connected to the USB | ||
164 | ports should be recognized. You can invoke "dmesg" to analyze kernel messages | ||
165 | and verify that the loading process has gone well: | ||
167 | 166 | ||
168 | [user@localhost home]$ dmesg | 167 | [user@localhost home]$ dmesg |
169 | 168 | ||
169 | or, to isolate all the kernel messages generated by the driver: | ||
170 | |||
171 | [user@localhost home]$ dmesg | grep sn9c102 | ||
172 | |||
170 | 173 | ||
171 | 7. Module parameters | 174 | 7. Module parameters |
172 | ==================== | 175 | ==================== |
@@ -198,10 +201,11 @@ Default: 0 | |||
198 | ------------------------------------------------------------------------------- | 201 | ------------------------------------------------------------------------------- |
199 | Name: frame_timeout | 202 | Name: frame_timeout |
200 | Type: uint array (min = 0, max = 64) | 203 | Type: uint array (min = 0, max = 64) |
201 | Syntax: <n[,...]> | 204 | Syntax: <0|n[,...]> |
202 | Description: Timeout for a video frame in seconds. This parameter is | 205 | Description: Timeout for a video frame in seconds before returning an I/O |
203 | specific for each detected camera. This parameter can be | 206 | error; 0 for infinity. This parameter is specific for each |
204 | changed at runtime thanks to the /sys filesystem interface. | 207 | detected camera and can be changed at runtime thanks to the |
208 | /sys filesystem interface. | ||
205 | Default: 2 | 209 | Default: 2 |
206 | ------------------------------------------------------------------------------- | 210 | ------------------------------------------------------------------------------- |
207 | Name: debug | 211 | Name: debug |
@@ -223,20 +227,21 @@ Default: 2 | |||
223 | 8. Optional device control through "sysfs" [1] | 227 | 8. Optional device control through "sysfs" [1] |
224 | ========================================== | 228 | ========================================== |
225 | If the kernel has been compiled with the CONFIG_VIDEO_ADV_DEBUG option enabled, | 229 | If the kernel has been compiled with the CONFIG_VIDEO_ADV_DEBUG option enabled, |
226 | it is possible to read and write both the SN9C10x and the image sensor | 230 | it is possible to read and write both the SN9C1xx and the image sensor |
227 | registers by using the "sysfs" filesystem interface. | 231 | registers by using the "sysfs" filesystem interface. |
228 | 232 | ||
229 | Every time a supported device is recognized, a write-only file named "green" is | 233 | Every time a supported device is recognized, a write-only file named "green" is |
230 | created in the /sys/class/video4linux/videoX directory. You can set the green | 234 | created in the /sys/class/video4linux/videoX directory. You can set the green |
231 | channel's gain by writing the desired value to it. The value may range from 0 | 235 | channel's gain by writing the desired value to it. The value may range from 0 |
232 | to 15 for SN9C101 or SN9C102 bridges, from 0 to 127 for SN9C103 bridges. | 236 | to 15 for the SN9C101 or SN9C102 bridges, from 0 to 127 for the SN9C103, |
233 | Similarly, only for SN9C103 controllers, blue and red gain control files are | 237 | SN9C105 and SN9C120 bridges. |
234 | available in the same directory, for which accepted values may range from 0 to | 238 | Similarly, only for the SN9C103, SN9C105 and SN9120 controllers, blue and red |
235 | 127. | 239 | gain control files are available in the same directory, for which accepted |
240 | values may range from 0 to 127. | ||
236 | 241 | ||
237 | There are other four entries in the directory above for each registered camera: | 242 | There are other four entries in the directory above for each registered camera: |
238 | "reg", "val", "i2c_reg" and "i2c_val". The first two files control the | 243 | "reg", "val", "i2c_reg" and "i2c_val". The first two files control the |
239 | SN9C10x bridge, while the other two control the sensor chip. "reg" and | 244 | SN9C1xx bridge, while the other two control the sensor chip. "reg" and |
240 | "i2c_reg" hold the values of the current register index where the following | 245 | "i2c_reg" hold the values of the current register index where the following |
241 | reading/writing operations are addressed at through "val" and "i2c_val". Their | 246 | reading/writing operations are addressed at through "val" and "i2c_val". Their |
242 | use is not intended for end-users. Note that "i2c_reg" and "i2c_val" will not | 247 | use is not intended for end-users. Note that "i2c_reg" and "i2c_val" will not |
@@ -259,61 +264,84 @@ Now let's set the green gain's register of the SN9C101 or SN9C102 chips to 2: | |||
259 | [root@localhost #] echo 0x11 > reg | 264 | [root@localhost #] echo 0x11 > reg |
260 | [root@localhost #] echo 2 > val | 265 | [root@localhost #] echo 2 > val |
261 | 266 | ||
262 | Note that the SN9C10x always returns 0 when some of its registers are read. | 267 | Note that the SN9C1xx always returns 0 when some of its registers are read. |
263 | To avoid race conditions, all the I/O accesses to the above files are | 268 | To avoid race conditions, all the I/O accesses to the above files are |
264 | serialized. | 269 | serialized. |
265 | |||
266 | The sysfs interface also provides the "frame_header" entry, which exports the | 270 | The sysfs interface also provides the "frame_header" entry, which exports the |
267 | frame header of the most recent requested and captured video frame. The header | 271 | frame header of the most recent requested and captured video frame. The header |
268 | is always 18-bytes long and is appended to every video frame by the SN9C10x | 272 | is always 18-bytes long and is appended to every video frame by the SN9C1xx |
269 | controllers. As an example, this additional information can be used by the user | 273 | controllers. As an example, this additional information can be used by the user |
270 | application for implementing auto-exposure features via software. | 274 | application for implementing auto-exposure features via software. |
271 | 275 | ||
272 | The following table describes the frame header: | 276 | The following table describes the frame header exported by the SN9C101 and |
273 | 277 | SN9C102: | |
274 | Byte # Value Description | 278 | |
275 | ------ ----- ----------- | 279 | Byte # Value or bits Description |
276 | 0x00 0xFF Frame synchronisation pattern. | 280 | ------ ------------- ----------- |
277 | 0x01 0xFF Frame synchronisation pattern. | 281 | 0x00 0xFF Frame synchronisation pattern |
278 | 0x02 0x00 Frame synchronisation pattern. | 282 | 0x01 0xFF Frame synchronisation pattern |
279 | 0x03 0xC4 Frame synchronisation pattern. | 283 | 0x02 0x00 Frame synchronisation pattern |
280 | 0x04 0xC4 Frame synchronisation pattern. | 284 | 0x03 0xC4 Frame synchronisation pattern |
281 | 0x05 0x96 Frame synchronisation pattern. | 285 | 0x04 0xC4 Frame synchronisation pattern |
282 | 0x06 0xXX Unknown meaning. The exact value depends on the chip; | 286 | 0x05 0x96 Frame synchronisation pattern |
283 | possible values are 0x00, 0x01 and 0x20. | 287 | 0x06 [3:0] Read channel gain control = (1+R_GAIN/8) |
284 | 0x07 0xXX Variable value, whose bits are ff00uzzc, where ff is a | 288 | [7:4] Blue channel gain control = (1+B_GAIN/8) |
285 | frame counter, u is unknown, zz is a size indicator | 289 | 0x07 [ 0 ] Compression mode. 0=No compression, 1=Compression enabled |
286 | (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for | 290 | [2:1] Maximum scale factor for compression |
287 | "compression enabled" (1 = yes, 0 = no). | 291 | [ 3 ] 1 = USB fifo(2K bytes) is full |
288 | 0x08 0xXX Brightness sum inside Auto-Exposure area (low-byte). | 292 | [ 4 ] 1 = Digital gain is finish |
289 | 0x09 0xXX Brightness sum inside Auto-Exposure area (high-byte). | 293 | [ 5 ] 1 = Exposure is finish |
290 | For a pure white image, this number will be equal to 500 | 294 | [7:6] Frame index |
291 | times the area of the specified AE area. For images | 295 | 0x08 [7:0] Y sum inside Auto-Exposure area (low-byte) |
292 | that are not pure white, the value scales down according | 296 | 0x09 [7:0] Y sum inside Auto-Exposure area (high-byte) |
293 | to relative whiteness. | 297 | where Y sum = (R/4 + 5G/16 + B/8) / 32 |
294 | 0x0A 0xXX Brightness sum outside Auto-Exposure area (low-byte). | 298 | 0x0A [7:0] Y sum outside Auto-Exposure area (low-byte) |
295 | 0x0B 0xXX Brightness sum outside Auto-Exposure area (high-byte). | 299 | 0x0B [7:0] Y sum outside Auto-Exposure area (high-byte) |
296 | For a pure white image, this number will be equal to 125 | 300 | where Y sum = (R/4 + 5G/16 + B/8) / 128 |
297 | times the area outside of the specified AE area. For | 301 | 0x0C 0xXX Not used |
298 | images that are not pure white, the value scales down | 302 | 0x0D 0xXX Not used |
299 | according to relative whiteness. | 303 | 0x0E 0xXX Not used |
300 | according to relative whiteness. | 304 | 0x0F 0xXX Not used |
301 | 305 | 0x10 0xXX Not used | |
302 | The following bytes are used by the SN9C103 bridge only: | 306 | 0x11 0xXX Not used |
303 | 307 | ||
304 | 0x0C 0xXX Unknown meaning | 308 | The following table describes the frame header exported by the SN9C103: |
305 | 0x0D 0xXX Unknown meaning | 309 | |
306 | 0x0E 0xXX Unknown meaning | 310 | Byte # Value or bits Description |
307 | 0x0F 0xXX Unknown meaning | 311 | ------ ------------- ----------- |
308 | 0x10 0xXX Unknown meaning | 312 | 0x00 0xFF Frame synchronisation pattern |
309 | 0x11 0xXX Unknown meaning | 313 | 0x01 0xFF Frame synchronisation pattern |
314 | 0x02 0x00 Frame synchronisation pattern | ||
315 | 0x03 0xC4 Frame synchronisation pattern | ||
316 | 0x04 0xC4 Frame synchronisation pattern | ||
317 | 0x05 0x96 Frame synchronisation pattern | ||
318 | 0x06 [6:0] Read channel gain control = (1/2+R_GAIN/64) | ||
319 | 0x07 [6:0] Blue channel gain control = (1/2+B_GAIN/64) | ||
320 | [7:4] | ||
321 | 0x08 [ 0 ] Compression mode. 0=No compression, 1=Compression enabled | ||
322 | [2:1] Maximum scale factor for compression | ||
323 | [ 3 ] 1 = USB fifo(2K bytes) is full | ||
324 | [ 4 ] 1 = Digital gain is finish | ||
325 | [ 5 ] 1 = Exposure is finish | ||
326 | [7:6] Frame index | ||
327 | 0x09 [7:0] Y sum inside Auto-Exposure area (low-byte) | ||
328 | 0x0A [7:0] Y sum inside Auto-Exposure area (high-byte) | ||
329 | where Y sum = (R/4 + 5G/16 + B/8) / 32 | ||
330 | 0x0B [7:0] Y sum outside Auto-Exposure area (low-byte) | ||
331 | 0x0C [7:0] Y sum outside Auto-Exposure area (high-byte) | ||
332 | where Y sum = (R/4 + 5G/16 + B/8) / 128 | ||
333 | 0x0D [1:0] Audio frame number | ||
334 | [ 2 ] 1 = Audio is recording | ||
335 | 0x0E [7:0] Audio summation (low-byte) | ||
336 | 0x0F [7:0] Audio summation (high-byte) | ||
337 | 0x10 [7:0] Audio sample count | ||
338 | 0x11 [7:0] Audio peak data in audio frame | ||
310 | 339 | ||
311 | The AE area (sx, sy, ex, ey) in the active window can be set by programming the | 340 | The AE area (sx, sy, ex, ey) in the active window can be set by programming the |
312 | registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C10x controllers, where one unit | 341 | registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C1xx controllers, where one unit |
313 | corresponds to 32 pixels. | 342 | corresponds to 32 pixels. |
314 | 343 | ||
315 | [1] Part of the meaning of the frame header has been documented by Bertrik | 344 | [1] The frame headers exported by the SN9C105 and SN9C120 are not described. |
316 | Sikken. | ||
317 | 345 | ||
318 | 346 | ||
319 | 9. Supported devices | 347 | 9. Supported devices |
@@ -323,15 +351,19 @@ here. They have never collaborated with the author, so no advertising. | |||
323 | 351 | ||
324 | From the point of view of a driver, what unambiguously identify a device are | 352 | From the point of view of a driver, what unambiguously identify a device are |
325 | its vendor and product USB identifiers. Below is a list of known identifiers of | 353 | its vendor and product USB identifiers. Below is a list of known identifiers of |
326 | devices mounting the SN9C10x PC camera controllers: | 354 | devices assembling the SN9C1xx PC camera controllers: |
327 | 355 | ||
328 | Vendor ID Product ID | 356 | Vendor ID Product ID |
329 | --------- ---------- | 357 | --------- ---------- |
358 | 0x0471 0x0327 | ||
359 | 0x0471 0x0328 | ||
330 | 0x0c45 0x6001 | 360 | 0x0c45 0x6001 |
331 | 0x0c45 0x6005 | 361 | 0x0c45 0x6005 |
332 | 0x0c45 0x6007 | 362 | 0x0c45 0x6007 |
333 | 0x0c45 0x6009 | 363 | 0x0c45 0x6009 |
334 | 0x0c45 0x600d | 364 | 0x0c45 0x600d |
365 | 0x0c45 0x6011 | ||
366 | 0x0c45 0x6019 | ||
335 | 0x0c45 0x6024 | 367 | 0x0c45 0x6024 |
336 | 0x0c45 0x6025 | 368 | 0x0c45 0x6025 |
337 | 0x0c45 0x6028 | 369 | 0x0c45 0x6028 |
@@ -342,6 +374,7 @@ Vendor ID Product ID | |||
342 | 0x0c45 0x602d | 374 | 0x0c45 0x602d |
343 | 0x0c45 0x602e | 375 | 0x0c45 0x602e |
344 | 0x0c45 0x6030 | 376 | 0x0c45 0x6030 |
377 | 0x0c45 0x603f | ||
345 | 0x0c45 0x6080 | 378 | 0x0c45 0x6080 |
346 | 0x0c45 0x6082 | 379 | 0x0c45 0x6082 |
347 | 0x0c45 0x6083 | 380 | 0x0c45 0x6083 |
@@ -368,24 +401,40 @@ Vendor ID Product ID | |||
368 | 0x0c45 0x60bb | 401 | 0x0c45 0x60bb |
369 | 0x0c45 0x60bc | 402 | 0x0c45 0x60bc |
370 | 0x0c45 0x60be | 403 | 0x0c45 0x60be |
404 | 0x0c45 0x60c0 | ||
405 | 0x0c45 0x60c8 | ||
406 | 0x0c45 0x60cc | ||
407 | 0x0c45 0x60ea | ||
408 | 0x0c45 0x60ec | ||
409 | 0x0c45 0x60fa | ||
410 | 0x0c45 0x60fb | ||
411 | 0x0c45 0x60fc | ||
412 | 0x0c45 0x60fe | ||
413 | 0x0c45 0x6130 | ||
414 | 0x0c45 0x613a | ||
415 | 0x0c45 0x613b | ||
416 | 0x0c45 0x613c | ||
417 | 0x0c45 0x613e | ||
371 | 418 | ||
372 | The list above does not imply that all those devices work with this driver: up | 419 | The list above does not imply that all those devices work with this driver: up |
373 | until now only the ones that mount the following image sensors are supported; | 420 | until now only the ones that assemble the following image sensors are |
374 | kernel messages will always tell you whether this is the case: | 421 | supported; kernel messages will always tell you whether this is the case (see |
422 | "Module loading" paragraph): | ||
375 | 423 | ||
376 | Model Manufacturer | 424 | Model Manufacturer |
377 | ----- ------------ | 425 | ----- ------------ |
378 | HV7131D Hynix Semiconductor, Inc. | 426 | HV7131D Hynix Semiconductor, Inc. |
379 | MI-0343 Micron Technology, Inc. | 427 | MI-0343 Micron Technology, Inc. |
380 | OV7630 OmniVision Technologies, Inc. | 428 | OV7630 OmniVision Technologies, Inc. |
429 | OV7660 OmniVision Technologies, Inc. | ||
381 | PAS106B PixArt Imaging, Inc. | 430 | PAS106B PixArt Imaging, Inc. |
382 | PAS202BCA PixArt Imaging, Inc. | 431 | PAS202BCA PixArt Imaging, Inc. |
383 | PAS202BCB PixArt Imaging, Inc. | 432 | PAS202BCB PixArt Imaging, Inc. |
384 | TAS5110C1B Taiwan Advanced Sensor Corporation | 433 | TAS5110C1B Taiwan Advanced Sensor Corporation |
385 | TAS5130D1B Taiwan Advanced Sensor Corporation | 434 | TAS5130D1B Taiwan Advanced Sensor Corporation |
386 | 435 | ||
387 | All the available control settings of each image sensor are supported through | 436 | Some of the available control settings of each image sensor are supported |
388 | the V4L2 interface. | 437 | through the V4L2 interface. |
389 | 438 | ||
390 | Donations of new models for further testing and support would be much | 439 | Donations of new models for further testing and support would be much |
391 | appreciated. Non-available hardware will not be supported by the author of this | 440 | appreciated. Non-available hardware will not be supported by the author of this |
@@ -429,12 +478,15 @@ supplied by this driver). | |||
429 | 478 | ||
430 | 11. Video frame formats [1] | 479 | 11. Video frame formats [1] |
431 | ======================= | 480 | ======================= |
432 | The SN9C10x PC Camera Controllers can send images in two possible video | 481 | The SN9C1xx PC Camera Controllers can send images in two possible video |
433 | formats over the USB: either native "Sequential RGB Bayer" or Huffman | 482 | formats over the USB: either native "Sequential RGB Bayer" or compressed. |
434 | compressed. The latter is used to achieve high frame rates. The current video | 483 | The compression is used to achieve high frame rates. With regard to the |
435 | format may be selected or queried from the user application by calling the | 484 | SN9C101, SN9C102 and SN9C103, the compression is based on the Huffman encoding |
436 | VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2 API | 485 | algorithm described below, while the SN9C105 and SN9C120 the compression is |
437 | specifications. | 486 | based on the JPEG standard. |
487 | The current video format may be selected or queried from the user application | ||
488 | by calling the VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2 | ||
489 | API specifications. | ||
438 | 490 | ||
439 | The name "Sequential Bayer" indicates the organization of the red, green and | 491 | The name "Sequential Bayer" indicates the organization of the red, green and |
440 | blue pixels in one video frame. Each pixel is associated with a 8-bit long | 492 | blue pixels in one video frame. Each pixel is associated with a 8-bit long |
@@ -447,14 +499,14 @@ G[m] R[m+1] G[m+2] R[m+2] ... G[2m-2] R[2m-1] | |||
447 | ... G[n(m-2)] R[n(m-1)] | 499 | ... G[n(m-2)] R[n(m-1)] |
448 | 500 | ||
449 | The above matrix also represents the sequential or progressive read-out mode of | 501 | The above matrix also represents the sequential or progressive read-out mode of |
450 | the (n, m) Bayer color filter array used in many CCD/CMOS image sensors. | 502 | the (n, m) Bayer color filter array used in many CCD or CMOS image sensors. |
451 | 503 | ||
452 | One compressed video frame consists of a bitstream that encodes for every R, G, | 504 | The Huffman compressed video frame consists of a bitstream that encodes for |
453 | or B pixel the difference between the value of the pixel itself and some | 505 | every R, G, or B pixel the difference between the value of the pixel itself and |
454 | reference pixel value. Pixels are organised in the Bayer pattern and the Bayer | 506 | some reference pixel value. Pixels are organised in the Bayer pattern and the |
455 | sub-pixels are tracked individually and alternatingly. For example, in the | 507 | Bayer sub-pixels are tracked individually and alternatingly. For example, in |
456 | first line values for the B and G1 pixels are alternatingly encoded, while in | 508 | the first line values for the B and G1 pixels are alternatingly encoded, while |
457 | the second line values for the G2 and R pixels are alternatingly encoded. | 509 | in the second line values for the G2 and R pixels are alternatingly encoded. |
458 | 510 | ||
459 | The pixel reference value is calculated as follows: | 511 | The pixel reference value is calculated as follows: |
460 | - the 4 top left pixels are encoded in raw uncompressed 8-bit format; | 512 | - the 4 top left pixels are encoded in raw uncompressed 8-bit format; |
@@ -470,8 +522,9 @@ The pixel reference value is calculated as follows: | |||
470 | decoding. | 522 | decoding. |
471 | 523 | ||
472 | The algorithm purely describes the conversion from compressed Bayer code used | 524 | The algorithm purely describes the conversion from compressed Bayer code used |
473 | in the SN9C10x chips to uncompressed Bayer. Additional steps are required to | 525 | in the SN9C101, SN9C102 and SN9C103 chips to uncompressed Bayer. Additional |
474 | convert this to a color image (i.e. a color interpolation algorithm). | 526 | steps are required to convert this to a color image (i.e. a color interpolation |
527 | algorithm). | ||
475 | 528 | ||
476 | The following Huffman codes have been found: | 529 | The following Huffman codes have been found: |
477 | 0: +0 (relative to reference pixel value) | 530 | 0: +0 (relative to reference pixel value) |
@@ -506,13 +559,18 @@ order): | |||
506 | - Philippe Coval for having helped testing the PAS202BCA image sensor; | 559 | - Philippe Coval for having helped testing the PAS202BCA image sensor; |
507 | - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the | 560 | - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the |
508 | donation of a webcam; | 561 | donation of a webcam; |
562 | - Dennis Heitmann for the donation of a webcam; | ||
509 | - Jon Hollstrom for the donation of a webcam; | 563 | - Jon Hollstrom for the donation of a webcam; |
564 | - Nick McGill for the donation of a webcam; | ||
510 | - Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB | 565 | - Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB |
511 | image sensor; | 566 | image sensor; |
512 | - Stefano Mozzi, who donated 45 EU; | 567 | - Stefano Mozzi, who donated 45 EU; |
513 | - Andrew Pearce for the donation of a webcam; | 568 | - Andrew Pearce for the donation of a webcam; |
569 | - John Pullan for the donation of a webcam; | ||
514 | - Bertrik Sikken, who reverse-engineered and documented the Huffman compression | 570 | - Bertrik Sikken, who reverse-engineered and documented the Huffman compression |
515 | algorithm used in the SN9C10x controllers and implemented the first decoder; | 571 | algorithm used in the SN9C101, SN9C102 and SN9C103 controllers and |
572 | implemented the first decoder; | ||
516 | - Mizuno Takafumi for the donation of a webcam; | 573 | - Mizuno Takafumi for the donation of a webcam; |
517 | - an "anonymous" donator (who didn't want his name to be revealed) for the | 574 | - an "anonymous" donator (who didn't want his name to be revealed) for the |
518 | donation of a webcam. | 575 | donation of a webcam. |
576 | - an anonymous donator for the donation of four webcams. | ||
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig index cf552e6b8ecf..1a7ccb666ab0 100644 --- a/drivers/media/video/sn9c102/Kconfig +++ b/drivers/media/video/sn9c102/Kconfig | |||
@@ -1,9 +1,9 @@ | |||
1 | config USB_SN9C102 | 1 | config USB_SN9C102 |
2 | tristate "USB SN9C10x PC Camera Controller support" | 2 | tristate "USB SN9C1xx PC Camera Controller support" |
3 | depends on USB && VIDEO_V4L1 | 3 | depends on USB && VIDEO_V4L1 |
4 | ---help--- | 4 | ---help--- |
5 | Say Y here if you want support for cameras based on SONiX SN9C101, | 5 | Say Y here if you want support for cameras based on SONiX SN9C101, |
6 | SN9C102 or SN9C103 PC Camera Controllers. | 6 | SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers. |
7 | 7 | ||
8 | See <file:Documentation/video4linux/sn9c102.txt> for more info. | 8 | See <file:Documentation/video4linux/sn9c102.txt> for more info. |
9 | 9 | ||
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile index 536ad3098da4..30e3dfe537fe 100644 --- a/drivers/media/video/sn9c102/Makefile +++ b/drivers/media/video/sn9c102/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ | 1 | sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ |
2 | sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \ | 2 | sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \ |
3 | sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ | 3 | sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ |
4 | sn9c102_tas5130d1b.o | 4 | sn9c102_tas5130d1b.o |
5 | 5 | ||
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h index 2c6ff396dafc..5428f34e7c5b 100644 --- a/drivers/media/video/sn9c102/sn9c102.h +++ b/drivers/media/video/sn9c102/sn9c102.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * V4L2 driver for SN9C10x PC Camera Controllers * | 2 | * V4L2 driver for SN9C1xx PC Camera Controllers * |
3 | * * | 3 | * * |
4 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | 4 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * |
5 | * * | 5 | * * |
@@ -37,33 +37,10 @@ | |||
37 | #include <linux/string.h> | 37 | #include <linux/string.h> |
38 | #include <linux/stddef.h> | 38 | #include <linux/stddef.h> |
39 | 39 | ||
40 | #include "sn9c102_config.h" | ||
40 | #include "sn9c102_sensor.h" | 41 | #include "sn9c102_sensor.h" |
42 | #include "sn9c102_devtable.h" | ||
41 | 43 | ||
42 | /*****************************************************************************/ | ||
43 | |||
44 | #define SN9C102_DEBUG | ||
45 | #define SN9C102_DEBUG_LEVEL 2 | ||
46 | #define SN9C102_MAX_DEVICES 64 | ||
47 | #define SN9C102_PRESERVE_IMGSCALE 0 | ||
48 | #define SN9C102_FORCE_MUNMAP 0 | ||
49 | #define SN9C102_MAX_FRAMES 32 | ||
50 | #define SN9C102_URBS 2 | ||
51 | #define SN9C102_ISO_PACKETS 7 | ||
52 | #define SN9C102_ALTERNATE_SETTING 8 | ||
53 | #define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS) | ||
54 | #define SN9C102_CTRL_TIMEOUT 300 | ||
55 | #define SN9C102_FRAME_TIMEOUT 2 | ||
56 | |||
57 | /*****************************************************************************/ | ||
58 | |||
59 | enum sn9c102_bridge { | ||
60 | BRIDGE_SN9C101 = 0x01, | ||
61 | BRIDGE_SN9C102 = 0x02, | ||
62 | BRIDGE_SN9C103 = 0x04, | ||
63 | }; | ||
64 | |||
65 | SN9C102_ID_TABLE | ||
66 | SN9C102_SENSOR_TABLE | ||
67 | 44 | ||
68 | enum sn9c102_frame_state { | 45 | enum sn9c102_frame_state { |
69 | F_UNUSED, | 46 | F_UNUSED, |
@@ -99,13 +76,11 @@ enum sn9c102_stream_state { | |||
99 | STREAM_ON, | 76 | STREAM_ON, |
100 | }; | 77 | }; |
101 | 78 | ||
102 | typedef char sn9c103_sof_header_t[18]; | 79 | typedef char sn9c102_sof_header_t[62]; |
103 | typedef char sn9c102_sof_header_t[12]; | ||
104 | typedef char sn9c102_eof_header_t[4]; | ||
105 | 80 | ||
106 | struct sn9c102_sysfs_attr { | 81 | struct sn9c102_sysfs_attr { |
107 | u8 reg, i2c_reg; | 82 | u8 reg, i2c_reg; |
108 | sn9c103_sof_header_t frame_header; | 83 | sn9c102_sof_header_t frame_header; |
109 | }; | 84 | }; |
110 | 85 | ||
111 | struct sn9c102_module_param { | 86 | struct sn9c102_module_param { |
@@ -137,8 +112,8 @@ struct sn9c102_device { | |||
137 | struct v4l2_jpegcompression compression; | 112 | struct v4l2_jpegcompression compression; |
138 | 113 | ||
139 | struct sn9c102_sysfs_attr sysfs; | 114 | struct sn9c102_sysfs_attr sysfs; |
140 | sn9c103_sof_header_t sof_header; | 115 | sn9c102_sof_header_t sof_header; |
141 | u16 reg[63]; | 116 | u16 reg[384]; |
142 | 117 | ||
143 | struct sn9c102_module_param module_param; | 118 | struct sn9c102_module_param module_param; |
144 | 119 | ||
@@ -155,10 +130,7 @@ struct sn9c102_device { | |||
155 | struct sn9c102_device* | 130 | struct sn9c102_device* |
156 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id) | 131 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id) |
157 | { | 132 | { |
158 | if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) | 133 | return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; |
159 | return cam; | ||
160 | |||
161 | return NULL; | ||
162 | } | 134 | } |
163 | 135 | ||
164 | 136 | ||
@@ -169,6 +141,19 @@ sn9c102_attach_sensor(struct sn9c102_device* cam, | |||
169 | memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor)); | 141 | memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor)); |
170 | } | 142 | } |
171 | 143 | ||
144 | |||
145 | enum sn9c102_bridge | ||
146 | sn9c102_get_bridge(struct sn9c102_device* cam) | ||
147 | { | ||
148 | return cam->bridge; | ||
149 | } | ||
150 | |||
151 | |||
152 | struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam) | ||
153 | { | ||
154 | return &cam->sensor; | ||
155 | } | ||
156 | |||
172 | /*****************************************************************************/ | 157 | /*****************************************************************************/ |
173 | 158 | ||
174 | #undef DBG | 159 | #undef DBG |
diff --git a/drivers/media/video/sn9c102/sn9c102_config.h b/drivers/media/video/sn9c102/sn9c102_config.h new file mode 100644 index 000000000000..0f4e0378b071 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_config.h | |||
@@ -0,0 +1,86 @@ | |||
1 | /*************************************************************************** | ||
2 | * Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program 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 * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _SN9C102_CONFIG_H_ | ||
22 | #define _SN9C102_CONFIG_H_ | ||
23 | |||
24 | #include <linux/types.h> | ||
25 | #include <linux/jiffies.h> | ||
26 | |||
27 | #define SN9C102_DEBUG | ||
28 | #define SN9C102_DEBUG_LEVEL 2 | ||
29 | #define SN9C102_MAX_DEVICES 64 | ||
30 | #define SN9C102_PRESERVE_IMGSCALE 0 | ||
31 | #define SN9C102_FORCE_MUNMAP 0 | ||
32 | #define SN9C102_MAX_FRAMES 32 | ||
33 | #define SN9C102_URBS 2 | ||
34 | #define SN9C102_ISO_PACKETS 7 | ||
35 | #define SN9C102_ALTERNATE_SETTING 8 | ||
36 | #define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS) | ||
37 | #define SN9C102_CTRL_TIMEOUT 300 | ||
38 | #define SN9C102_FRAME_TIMEOUT 0 | ||
39 | |||
40 | /*****************************************************************************/ | ||
41 | |||
42 | static const u8 SN9C102_Y_QTABLE0[64] = { | ||
43 | 8, 5, 5, 8, 12, 20, 25, 30, | ||
44 | 6, 6, 7, 9, 13, 29, 30, 27, | ||
45 | 7, 6, 8, 12, 20, 28, 34, 28, | ||
46 | 7, 8, 11, 14, 25, 43, 40, 31, | ||
47 | 9, 11, 18, 28, 34, 54, 51, 38, | ||
48 | 12, 17, 27, 32, 40, 52, 56, 46, | ||
49 | 24, 32, 39, 43, 51, 60, 60, 50, | ||
50 | 36, 46, 47, 49, 56, 50, 51, 49 | ||
51 | }; | ||
52 | |||
53 | static const u8 SN9C102_UV_QTABLE0[64] = { | ||
54 | 8, 9, 12, 23, 49, 49, 49, 49, | ||
55 | 9, 10, 13, 33, 49, 49, 49, 49, | ||
56 | 12, 13, 28, 49, 49, 49, 49, 49, | ||
57 | 23, 33, 49, 49, 49, 49, 49, 49, | ||
58 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
59 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
60 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
61 | 49, 49, 49, 49, 49, 49, 49, 49 | ||
62 | }; | ||
63 | |||
64 | static const u8 SN9C102_Y_QTABLE1[64] = { | ||
65 | 16, 11, 10, 16, 24, 40, 51, 61, | ||
66 | 12, 12, 14, 19, 26, 58, 60, 55, | ||
67 | 14, 13, 16, 24, 40, 57, 69, 56, | ||
68 | 14, 17, 22, 29, 51, 87, 80, 62, | ||
69 | 18, 22, 37, 56, 68, 109, 103, 77, | ||
70 | 24, 35, 55, 64, 81, 104, 113, 92, | ||
71 | 49, 64, 78, 87, 103, 121, 120, 101, | ||
72 | 72, 92, 95, 98, 112, 100, 103, 99 | ||
73 | }; | ||
74 | |||
75 | static const u8 SN9C102_UV_QTABLE1[64] = { | ||
76 | 17, 18, 24, 47, 99, 99, 99, 99, | ||
77 | 18, 21, 26, 66, 99, 99, 99, 99, | ||
78 | 24, 26, 56, 99, 99, 99, 99, 99, | ||
79 | 47, 66, 99, 99, 99, 99, 99, 99, | ||
80 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
81 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
82 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
83 | 99, 99, 99, 99, 99, 99, 99, 99 | ||
84 | }; | ||
85 | |||
86 | #endif /* _SN9C102_CONFIG_H_ */ | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 04d4c8f28b89..d0e2b40a7725 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * V4L2 driver for SN9C10x PC Camera Controllers * | 2 | * V4L2 driver for SN9C1xx PC Camera Controllers * |
3 | * * | 3 | * * |
4 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | 4 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * |
5 | * * | 5 | * * |
6 | * This program is free software; you can redistribute it and/or modify * | 6 | * This program is free software; you can redistribute it and/or modify * |
7 | * it under the terms of the GNU General Public License as published by * | 7 | * it under the terms of the GNU General Public License as published by * |
@@ -43,12 +43,12 @@ | |||
43 | 43 | ||
44 | /*****************************************************************************/ | 44 | /*****************************************************************************/ |
45 | 45 | ||
46 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers" | 46 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" |
47 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" | 47 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" |
48 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | 48 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" |
49 | #define SN9C102_MODULE_LICENSE "GPL" | 49 | #define SN9C102_MODULE_LICENSE "GPL" |
50 | #define SN9C102_MODULE_VERSION "1:1.27" | 50 | #define SN9C102_MODULE_VERSION "1:1.34" |
51 | #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 27) | 51 | #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 34) |
52 | 52 | ||
53 | /*****************************************************************************/ | 53 | /*****************************************************************************/ |
54 | 54 | ||
@@ -91,7 +91,8 @@ static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] = | |||
91 | SN9C102_FRAME_TIMEOUT}; | 91 | SN9C102_FRAME_TIMEOUT}; |
92 | module_param_array(frame_timeout, uint, NULL, 0644); | 92 | module_param_array(frame_timeout, uint, NULL, 0644); |
93 | MODULE_PARM_DESC(frame_timeout, | 93 | MODULE_PARM_DESC(frame_timeout, |
94 | "\n<n[,...]> Timeout for a video frame in seconds." | 94 | "\n<0|n[,...]> Timeout for a video frame in seconds before" |
95 | "\nreturning an I/O error; 0 for infinity." | ||
95 | "\nThis parameter is specific for each detected camera." | 96 | "\nThis parameter is specific for each detected camera." |
96 | "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." | 97 | "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." |
97 | "\n"); | 98 | "\n"); |
@@ -113,32 +114,13 @@ MODULE_PARM_DESC(debug, | |||
113 | 114 | ||
114 | /*****************************************************************************/ | 115 | /*****************************************************************************/ |
115 | 116 | ||
116 | static sn9c102_sof_header_t sn9c102_sof_header[] = { | ||
117 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00}, | ||
118 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01}, | ||
119 | }; | ||
120 | |||
121 | static sn9c103_sof_header_t sn9c103_sof_header[] = { | ||
122 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20}, | ||
123 | }; | ||
124 | |||
125 | static sn9c102_eof_header_t sn9c102_eof_header[] = { | ||
126 | {0x00, 0x00, 0x00, 0x00}, | ||
127 | {0x40, 0x00, 0x00, 0x00}, | ||
128 | {0x80, 0x00, 0x00, 0x00}, | ||
129 | {0xc0, 0x00, 0x00, 0x00}, | ||
130 | }; | ||
131 | |||
132 | /*****************************************************************************/ | ||
133 | |||
134 | static u32 | 117 | static u32 |
135 | sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, | 118 | sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, |
136 | enum sn9c102_io_method io) | 119 | enum sn9c102_io_method io) |
137 | { | 120 | { |
138 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | 121 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); |
139 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | 122 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); |
140 | const size_t imagesize = cam->module_param.force_munmap || | 123 | size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? |
141 | io == IO_READ ? | ||
142 | (p->width * p->height * p->priv) / 8 : | 124 | (p->width * p->height * p->priv) / 8 : |
143 | (r->width * r->height * p->priv) / 8; | 125 | (r->width * r->height * p->priv) / 8; |
144 | void* buff = NULL; | 126 | void* buff = NULL; |
@@ -147,9 +129,13 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, | |||
147 | if (count > SN9C102_MAX_FRAMES) | 129 | if (count > SN9C102_MAX_FRAMES) |
148 | count = SN9C102_MAX_FRAMES; | 130 | count = SN9C102_MAX_FRAMES; |
149 | 131 | ||
132 | if (cam->bridge == BRIDGE_SN9C105 || cam->bridge == BRIDGE_SN9C120) | ||
133 | imagesize += 589 + 2; /* length of JPEG header + EOI marker */ | ||
134 | |||
150 | cam->nbuffers = count; | 135 | cam->nbuffers = count; |
151 | while (cam->nbuffers > 0) { | 136 | while (cam->nbuffers > 0) { |
152 | if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) | 137 | if ((buff = vmalloc_32_user(cam->nbuffers * |
138 | PAGE_ALIGN(imagesize)))) | ||
153 | break; | 139 | break; |
154 | cam->nbuffers--; | 140 | cam->nbuffers--; |
155 | } | 141 | } |
@@ -322,9 +308,21 @@ static int | |||
322 | sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, | 308 | sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, |
323 | struct sn9c102_sensor* sensor) | 309 | struct sn9c102_sensor* sensor) |
324 | { | 310 | { |
325 | int r; | 311 | int r , err = 0; |
312 | |||
326 | r = sn9c102_read_reg(cam, 0x08); | 313 | r = sn9c102_read_reg(cam, 0x08); |
327 | return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0; | 314 | if (r < 0) |
315 | err += r; | ||
316 | |||
317 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { | ||
318 | if (!(r & 0x08)) | ||
319 | err += -1; | ||
320 | } else { | ||
321 | if (r & 0x08) | ||
322 | err += -1; | ||
323 | } | ||
324 | |||
325 | return err ? -EIO : 0; | ||
328 | } | 326 | } |
329 | 327 | ||
330 | 328 | ||
@@ -415,7 +413,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, | |||
415 | data[4] = data3; | 413 | data[4] = data3; |
416 | data[5] = data4; | 414 | data[5] = data4; |
417 | data[6] = data5; | 415 | data[6] = data5; |
418 | data[7] = 0x14; | 416 | data[7] = 0x17; |
419 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | 417 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, |
420 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | 418 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); |
421 | if (res < 0) | 419 | if (res < 0) |
@@ -467,31 +465,35 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) | |||
467 | 465 | ||
468 | /*****************************************************************************/ | 466 | /*****************************************************************************/ |
469 | 467 | ||
470 | static void* | 468 | static size_t sn9c102_sof_length(struct sn9c102_device* cam) |
471 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
472 | { | 469 | { |
473 | size_t soflen = 0, i; | ||
474 | u8 j, n = 0; | ||
475 | |||
476 | switch (cam->bridge) { | 470 | switch (cam->bridge) { |
477 | case BRIDGE_SN9C101: | 471 | case BRIDGE_SN9C101: |
478 | case BRIDGE_SN9C102: | 472 | case BRIDGE_SN9C102: |
479 | soflen = sizeof(sn9c102_sof_header_t); | 473 | return 12; |
480 | n = sizeof(sn9c102_sof_header) / soflen; | ||
481 | break; | ||
482 | case BRIDGE_SN9C103: | 474 | case BRIDGE_SN9C103: |
483 | soflen = sizeof(sn9c103_sof_header_t); | 475 | return 18; |
484 | n = sizeof(sn9c103_sof_header) / soflen; | 476 | case BRIDGE_SN9C105: |
477 | case BRIDGE_SN9C120: | ||
478 | return 62; | ||
485 | } | 479 | } |
486 | 480 | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | |||
485 | static void* | ||
486 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
487 | { | ||
488 | char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; | ||
489 | size_t soflen = 0, i; | ||
490 | |||
491 | soflen = sn9c102_sof_length(cam); | ||
492 | |||
487 | for (i = 0; (len >= soflen) && (i <= len - soflen); i++) | 493 | for (i = 0; (len >= soflen) && (i <= len - soflen); i++) |
488 | for (j = 0; j < n; j++) | 494 | if (!memcmp(mem + i, sof_header, sizeof(sof_header))) { |
489 | /* The invariable part of the header is 6 bytes long */ | 495 | memcpy(cam->sof_header, mem + i, |
490 | if ((cam->bridge != BRIDGE_SN9C103 && | 496 | sizeof(sn9c102_sof_header_t)); |
491 | !memcmp(mem + i, sn9c102_sof_header[j], 6)) || | ||
492 | (cam->bridge == BRIDGE_SN9C103 && | ||
493 | !memcmp(mem + i, sn9c103_sof_header[j], 6))) { | ||
494 | memcpy(cam->sof_header, mem + i, soflen); | ||
495 | /* Skip the header */ | 497 | /* Skip the header */ |
496 | return mem + i + soflen; | 498 | return mem + i + soflen; |
497 | } | 499 | } |
@@ -503,21 +505,123 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | |||
503 | static void* | 505 | static void* |
504 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | 506 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) |
505 | { | 507 | { |
506 | size_t eoflen = sizeof(sn9c102_eof_header_t), i; | 508 | char eof_header[4][4] = { |
507 | unsigned j, n = sizeof(sn9c102_eof_header) / eoflen; | 509 | {0x00, 0x00, 0x00, 0x00}, |
510 | {0x40, 0x00, 0x00, 0x00}, | ||
511 | {0x80, 0x00, 0x00, 0x00}, | ||
512 | {0xc0, 0x00, 0x00, 0x00}, | ||
513 | }; | ||
514 | size_t i, j; | ||
508 | 515 | ||
509 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | 516 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || |
517 | cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | ||
510 | return NULL; /* EOF header does not exist in compressed data */ | 518 | return NULL; /* EOF header does not exist in compressed data */ |
511 | 519 | ||
512 | for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++) | 520 | for (i = 0; (len >= 4) && (i <= len - 4); i++) |
513 | for (j = 0; j < n; j++) | 521 | for (j = 0; j < ARRAY_SIZE(eof_header); j++) |
514 | if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen)) | 522 | if (!memcmp(mem + i, eof_header[j], 4)) |
515 | return mem + i; | 523 | return mem + i; |
516 | 524 | ||
517 | return NULL; | 525 | return NULL; |
518 | } | 526 | } |
519 | 527 | ||
520 | 528 | ||
529 | static void | ||
530 | sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f) | ||
531 | { | ||
532 | static u8 jpeg_header[589] = { | ||
533 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05, | ||
534 | 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06, | ||
535 | 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, | ||
536 | 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16, | ||
537 | 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16, | ||
538 | 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29, | ||
539 | 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29, | ||
540 | 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a, | ||
541 | 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28, | ||
542 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, | ||
543 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, | ||
544 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, | ||
545 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, | ||
546 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2, | ||
547 | 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
548 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, | ||
549 | 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, | ||
550 | 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
551 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, | ||
552 | 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, | ||
553 | 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, | ||
554 | 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, | ||
555 | 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, | ||
556 | 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, | ||
557 | 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, | ||
558 | 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, | ||
559 | 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, | ||
560 | 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, | ||
561 | 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, | ||
562 | 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, | ||
563 | 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, | ||
564 | 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, | ||
565 | 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, | ||
566 | 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, | ||
567 | 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, | ||
568 | 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, | ||
569 | 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, | ||
570 | 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, | ||
571 | 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, | ||
572 | 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, | ||
573 | 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, | ||
574 | 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, | ||
575 | 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, | ||
576 | 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, | ||
577 | 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, | ||
578 | 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, | ||
579 | 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, | ||
580 | 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, | ||
581 | 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | ||
582 | 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, | ||
583 | 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, | ||
584 | 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, | ||
585 | 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, | ||
586 | 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, | ||
587 | 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, | ||
588 | 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11, | ||
589 | 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02, | ||
590 | 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, | ||
591 | 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 | ||
592 | }; | ||
593 | u8 *pos = f->bufmem; | ||
594 | |||
595 | memcpy(pos, jpeg_header, sizeof(jpeg_header)); | ||
596 | *(pos + 6) = 0x00; | ||
597 | *(pos + 7 + 64) = 0x01; | ||
598 | if (cam->compression.quality == 0) { | ||
599 | memcpy(pos + 7, SN9C102_Y_QTABLE0, 64); | ||
600 | memcpy(pos + 8 + 64, SN9C102_UV_QTABLE0, 64); | ||
601 | } else if (cam->compression.quality == 1) { | ||
602 | memcpy(pos + 7, SN9C102_Y_QTABLE1, 64); | ||
603 | memcpy(pos + 8 + 64, SN9C102_UV_QTABLE1, 64); | ||
604 | } | ||
605 | *(pos + 564) = cam->sensor.pix_format.width & 0xFF; | ||
606 | *(pos + 563) = (cam->sensor.pix_format.width >> 8) & 0xFF; | ||
607 | *(pos + 562) = cam->sensor.pix_format.height & 0xFF; | ||
608 | *(pos + 561) = (cam->sensor.pix_format.height >> 8) & 0xFF; | ||
609 | *(pos + 567) = 0x21; | ||
610 | |||
611 | f->buf.bytesused += sizeof(jpeg_header); | ||
612 | } | ||
613 | |||
614 | |||
615 | static void | ||
616 | sn9c102_write_eoimarker(struct sn9c102_device* cam, struct sn9c102_frame_t* f) | ||
617 | { | ||
618 | static const u8 eoi_marker[2] = {0xff, 0xd9}; | ||
619 | |||
620 | memcpy(f->bufmem + f->buf.bytesused, eoi_marker, sizeof(eoi_marker)); | ||
621 | f->buf.bytesused += sizeof(eoi_marker); | ||
622 | } | ||
623 | |||
624 | |||
521 | static void sn9c102_urb_complete(struct urb *urb) | 625 | static void sn9c102_urb_complete(struct urb *urb) |
522 | { | 626 | { |
523 | struct sn9c102_device* cam = urb->context; | 627 | struct sn9c102_device* cam = urb->context; |
@@ -535,7 +639,7 @@ static void sn9c102_urb_complete(struct urb *urb) | |||
535 | cam->stream = STREAM_OFF; | 639 | cam->stream = STREAM_OFF; |
536 | if ((*f)) | 640 | if ((*f)) |
537 | (*f)->state = F_QUEUED; | 641 | (*f)->state = F_QUEUED; |
538 | DBG(3, "Stream interrupted"); | 642 | DBG(3, "Stream interrupted by application"); |
539 | wake_up(&cam->wait_stream); | 643 | wake_up(&cam->wait_stream); |
540 | } | 644 | } |
541 | 645 | ||
@@ -557,10 +661,9 @@ static void sn9c102_urb_complete(struct urb *urb) | |||
557 | imagesize = (cam->sensor.pix_format.width * | 661 | imagesize = (cam->sensor.pix_format.width * |
558 | cam->sensor.pix_format.height * | 662 | cam->sensor.pix_format.height * |
559 | cam->sensor.pix_format.priv) / 8; | 663 | cam->sensor.pix_format.priv) / 8; |
560 | 664 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | |
561 | soflen = (cam->bridge) == BRIDGE_SN9C103 ? | 665 | imagesize += 589; /* length of jpeg header */ |
562 | sizeof(sn9c103_sof_header_t) : | 666 | soflen = sn9c102_sof_length(cam); |
563 | sizeof(sn9c102_sof_header_t); | ||
564 | 667 | ||
565 | for (i = 0; i < urb->number_of_packets; i++) { | 668 | for (i = 0; i < urb->number_of_packets; i++) { |
566 | unsigned int img, len, status; | 669 | unsigned int img, len, status; |
@@ -610,12 +713,21 @@ end_of_frame: | |||
610 | (*f)->buf.bytesused += img; | 713 | (*f)->buf.bytesused += img; |
611 | 714 | ||
612 | if ((*f)->buf.bytesused == imagesize || | 715 | if ((*f)->buf.bytesused == imagesize || |
613 | (cam->sensor.pix_format.pixelformat == | 716 | ((cam->sensor.pix_format.pixelformat == |
614 | V4L2_PIX_FMT_SN9C10X && eof)) { | 717 | V4L2_PIX_FMT_SN9C10X || |
718 | cam->sensor.pix_format.pixelformat == | ||
719 | V4L2_PIX_FMT_JPEG) && eof)) { | ||
615 | u32 b; | 720 | u32 b; |
721 | |||
722 | if (cam->sensor.pix_format.pixelformat | ||
723 | == V4L2_PIX_FMT_JPEG) | ||
724 | sn9c102_write_eoimarker(cam, | ||
725 | (*f)); | ||
726 | |||
616 | b = (*f)->buf.bytesused; | 727 | b = (*f)->buf.bytesused; |
617 | (*f)->state = F_DONE; | 728 | (*f)->state = F_DONE; |
618 | (*f)->buf.sequence= ++cam->frame_count; | 729 | (*f)->buf.sequence= ++cam->frame_count; |
730 | |||
619 | spin_lock(&cam->queue_lock); | 731 | spin_lock(&cam->queue_lock); |
620 | list_move_tail(&(*f)->frame, | 732 | list_move_tail(&(*f)->frame, |
621 | &cam->outqueue); | 733 | &cam->outqueue); |
@@ -627,8 +739,10 @@ end_of_frame: | |||
627 | else | 739 | else |
628 | (*f) = NULL; | 740 | (*f) = NULL; |
629 | spin_unlock(&cam->queue_lock); | 741 | spin_unlock(&cam->queue_lock); |
742 | |||
630 | memcpy(cam->sysfs.frame_header, | 743 | memcpy(cam->sysfs.frame_header, |
631 | cam->sof_header, soflen); | 744 | cam->sof_header, soflen); |
745 | |||
632 | DBG(3, "Video frame captured: %lu " | 746 | DBG(3, "Video frame captured: %lu " |
633 | "bytes", (unsigned long)(b)); | 747 | "bytes", (unsigned long)(b)); |
634 | 748 | ||
@@ -661,6 +775,9 @@ start_of_frame: | |||
661 | (*f)->buf.bytesused = 0; | 775 | (*f)->buf.bytesused = 0; |
662 | len -= (sof - pos); | 776 | len -= (sof - pos); |
663 | pos = sof; | 777 | pos = sof; |
778 | if (cam->sensor.pix_format.pixelformat == | ||
779 | V4L2_PIX_FMT_JPEG) | ||
780 | sn9c102_write_jpegheader(cam, (*f)); | ||
664 | DBG(3, "SOF detected: new video frame"); | 781 | DBG(3, "SOF detected: new video frame"); |
665 | if (len) | 782 | if (len) |
666 | goto redo; | 783 | goto redo; |
@@ -671,7 +788,9 @@ start_of_frame: | |||
671 | goto end_of_frame; /* (1) */ | 788 | goto end_of_frame; /* (1) */ |
672 | else { | 789 | else { |
673 | if (cam->sensor.pix_format.pixelformat == | 790 | if (cam->sensor.pix_format.pixelformat == |
674 | V4L2_PIX_FMT_SN9C10X) { | 791 | V4L2_PIX_FMT_SN9C10X || |
792 | cam->sensor.pix_format.pixelformat == | ||
793 | V4L2_PIX_FMT_JPEG) { | ||
675 | eof = sof - soflen; | 794 | eof = sof - soflen; |
676 | goto end_of_frame; | 795 | goto end_of_frame; |
677 | } else { | 796 | } else { |
@@ -701,13 +820,11 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam) | |||
701 | { | 820 | { |
702 | struct usb_device *udev = cam->usbdev; | 821 | struct usb_device *udev = cam->usbdev; |
703 | struct urb* urb; | 822 | struct urb* urb; |
704 | const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512, | 823 | struct usb_host_interface* altsetting = usb_altnum_to_altsetting( |
705 | 680, 800, 900, 1023}; | 824 | usb_ifnum_to_if(udev, 0), |
706 | const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512, | 825 | SN9C102_ALTERNATE_SETTING); |
707 | 680, 800, 900, 1003}; | 826 | const unsigned int psz = le16_to_cpu(altsetting-> |
708 | const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ? | 827 | endpoint[0].desc.wMaxPacketSize); |
709 | sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] : | ||
710 | sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING]; | ||
711 | s8 i, j; | 828 | s8 i, j; |
712 | int err = 0; | 829 | int err = 0; |
713 | 830 | ||
@@ -775,7 +892,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam) | |||
775 | return 0; | 892 | return 0; |
776 | 893 | ||
777 | free_urbs: | 894 | free_urbs: |
778 | for (i = 0; i < SN9C102_URBS; i++) | 895 | for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) |
779 | usb_free_urb(cam->urb[i]); | 896 | usb_free_urb(cam->urb[i]); |
780 | 897 | ||
781 | free_buffers: | 898 | free_buffers: |
@@ -834,29 +951,29 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam) | |||
834 | /*****************************************************************************/ | 951 | /*****************************************************************************/ |
835 | 952 | ||
836 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 953 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
837 | static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count) | 954 | static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) |
838 | { | 955 | { |
839 | char str[5]; | 956 | char str[7]; |
840 | char* endp; | 957 | char* endp; |
841 | unsigned long val; | 958 | unsigned long val; |
842 | 959 | ||
843 | if (len < 4) { | 960 | if (len < 6) { |
844 | strncpy(str, buff, len); | 961 | strncpy(str, buff, len); |
845 | str[len+1] = '\0'; | 962 | str[len+1] = '\0'; |
846 | } else { | 963 | } else { |
847 | strncpy(str, buff, 4); | 964 | strncpy(str, buff, 4); |
848 | str[4] = '\0'; | 965 | str[6] = '\0'; |
849 | } | 966 | } |
850 | 967 | ||
851 | val = simple_strtoul(str, &endp, 0); | 968 | val = simple_strtoul(str, &endp, 0); |
852 | 969 | ||
853 | *count = 0; | 970 | *count = 0; |
854 | if (val <= 0xff) | 971 | if (val <= 0xffff) |
855 | *count = (ssize_t)(endp - str); | 972 | *count = (ssize_t)(endp - str); |
856 | if ((*count) && (len == *count+1) && (buff[*count] == '\n')) | 973 | if ((*count) && (len == *count+1) && (buff[*count] == '\n')) |
857 | *count += 1; | 974 | *count += 1; |
858 | 975 | ||
859 | return (u8)val; | 976 | return (u16)val; |
860 | } | 977 | } |
861 | 978 | ||
862 | /* | 979 | /* |
@@ -873,7 +990,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) | |||
873 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | 990 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) |
874 | return -ERESTARTSYS; | 991 | return -ERESTARTSYS; |
875 | 992 | ||
876 | cam = video_get_drvdata(to_video_device(cd)); | 993 | cam = video_get_drvdata(container_of(cd, struct video_device, |
994 | class_dev)); | ||
877 | if (!cam) { | 995 | if (!cam) { |
878 | mutex_unlock(&sn9c102_sysfs_lock); | 996 | mutex_unlock(&sn9c102_sysfs_lock); |
879 | return -ENODEV; | 997 | return -ENODEV; |
@@ -891,27 +1009,28 @@ static ssize_t | |||
891 | sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) | 1009 | sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) |
892 | { | 1010 | { |
893 | struct sn9c102_device* cam; | 1011 | struct sn9c102_device* cam; |
894 | u8 index; | 1012 | u16 index; |
895 | ssize_t count; | 1013 | ssize_t count; |
896 | 1014 | ||
897 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | 1015 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) |
898 | return -ERESTARTSYS; | 1016 | return -ERESTARTSYS; |
899 | 1017 | ||
900 | cam = video_get_drvdata(to_video_device(cd)); | 1018 | cam = video_get_drvdata(container_of(cd, struct video_device, |
1019 | class_dev)); | ||
901 | if (!cam) { | 1020 | if (!cam) { |
902 | mutex_unlock(&sn9c102_sysfs_lock); | 1021 | mutex_unlock(&sn9c102_sysfs_lock); |
903 | return -ENODEV; | 1022 | return -ENODEV; |
904 | } | 1023 | } |
905 | 1024 | ||
906 | index = sn9c102_strtou8(buf, len, &count); | 1025 | index = sn9c102_strtou16(buf, len, &count); |
907 | if (index > 0x1f || !count) { | 1026 | if (index >= ARRAY_SIZE(cam->reg) || !count) { |
908 | mutex_unlock(&sn9c102_sysfs_lock); | 1027 | mutex_unlock(&sn9c102_sysfs_lock); |
909 | return -EINVAL; | 1028 | return -EINVAL; |
910 | } | 1029 | } |
911 | 1030 | ||
912 | cam->sysfs.reg = index; | 1031 | cam->sysfs.reg = index; |
913 | 1032 | ||
914 | DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg); | 1033 | DBG(2, "Moved SN9C1XX register index to 0x%02X", cam->sysfs.reg); |
915 | DBG(3, "Written bytes: %zd", count); | 1034 | DBG(3, "Written bytes: %zd", count); |
916 | 1035 | ||
917 | mutex_unlock(&sn9c102_sysfs_lock); | 1036 | mutex_unlock(&sn9c102_sysfs_lock); |
@@ -929,7 +1048,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) | |||
929 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | 1048 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) |
930 | return -ERESTARTSYS; | 1049 | return -ERESTARTSYS; |
931 | 1050 | ||
932 | cam = video_get_drvdata(to_video_device(cd)); | 1051 | cam = video_get_drvdata(container_of(cd, struct video_device, |
1052 | class_dev)); | ||
933 | if (!cam) { | 1053 | if (!cam) { |
934 | mutex_unlock(&sn9c102_sysfs_lock); | 1054 | mutex_unlock(&sn9c102_sysfs_lock); |
935 | return -ENODEV; | 1055 | return -ENODEV; |
@@ -954,20 +1074,21 @@ static ssize_t | |||
954 | sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) | 1074 | sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) |
955 | { | 1075 | { |
956 | struct sn9c102_device* cam; | 1076 | struct sn9c102_device* cam; |
957 | u8 value; | 1077 | u16 value; |
958 | ssize_t count; | 1078 | ssize_t count; |
959 | int err; | 1079 | int err; |
960 | 1080 | ||
961 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | 1081 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) |
962 | return -ERESTARTSYS; | 1082 | return -ERESTARTSYS; |
963 | 1083 | ||
964 | cam = video_get_drvdata(to_video_device(cd)); | 1084 | cam = video_get_drvdata(container_of(cd, struct video_device, |
1085 | class_dev)); | ||
965 | if (!cam) { | 1086 | if (!cam) { |
966 | mutex_unlock(&sn9c102_sysfs_lock); | 1087 | mutex_unlock(&sn9c102_sysfs_lock); |
967 | return -ENODEV; | 1088 | return -ENODEV; |
968 | } | 1089 | } |
969 | 1090 | ||
970 | value = sn9c102_strtou8(buf, len, &count); | 1091 | value = sn9c102_strtou16(buf, len, &count); |
971 | if (!count) { | 1092 | if (!count) { |
972 | mutex_unlock(&sn9c102_sysfs_lock); | 1093 | mutex_unlock(&sn9c102_sysfs_lock); |
973 | return -EINVAL; | 1094 | return -EINVAL; |
@@ -979,7 +1100,7 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) | |||
979 | return -EIO; | 1100 | return -EIO; |
980 | } | 1101 | } |
981 | 1102 | ||
982 | DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X", | 1103 | DBG(2, "Written SN9C1XX reg. 0x%02X, val. 0x%02X", |
983 | cam->sysfs.reg, value); | 1104 | cam->sysfs.reg, value); |
984 | DBG(3, "Written bytes: %zd", count); | 1105 | DBG(3, "Written bytes: %zd", count); |
985 | 1106 | ||
@@ -997,7 +1118,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) | |||
997 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | 1118 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) |
998 | return -ERESTARTSYS; | 1119 | return -ERESTARTSYS; |
999 | 1120 | ||
1000 | cam = video_get_drvdata(to_video_device(cd)); | 1121 | cam = video_get_drvdata(container_of(cd, struct video_device, |
1122 | class_dev)); | ||
1001 | if (!cam) { | 1123 | if (!cam) { |
1002 | mutex_unlock(&sn9c102_sysfs_lock); | 1124 | mutex_unlock(&sn9c102_sysfs_lock); |
1003 | return -ENODEV; | 1125 | return -ENODEV; |
@@ -1017,19 +1139,20 @@ static ssize_t | |||
1017 | sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) | 1139 | sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) |
1018 | { | 1140 | { |
1019 | struct sn9c102_device* cam; | 1141 | struct sn9c102_device* cam; |
1020 | u8 index; | 1142 | u16 index; |
1021 | ssize_t count; | 1143 | ssize_t count; |
1022 | 1144 | ||
1023 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | 1145 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) |
1024 | return -ERESTARTSYS; | 1146 | return -ERESTARTSYS; |
1025 | 1147 | ||
1026 | cam = video_get_drvdata(to_video_device(cd)); | 1148 | cam = video_get_drvdata(container_of(cd, struct video_device, |
1149 | class_dev)); | ||
1027 | if (!cam) { | 1150 | if (!cam) { |
1028 | mutex_unlock(&sn9c102_sysfs_lock); | 1151 | mutex_unlock(&sn9c102_sysfs_lock); |
1029 | return -ENODEV; | 1152 | return -ENODEV; |
1030 | } | 1153 | } |
1031 | 1154 | ||
1032 | index = sn9c102_strtou8(buf, len, &count); | 1155 | index = sn9c102_strtou16(buf, len, &count); |
1033 | if (!count) { | 1156 | if (!count) { |
1034 | mutex_unlock(&sn9c102_sysfs_lock); | 1157 | mutex_unlock(&sn9c102_sysfs_lock); |
1035 | return -EINVAL; | 1158 | return -EINVAL; |
@@ -1055,7 +1178,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) | |||
1055 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | 1178 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) |
1056 | return -ERESTARTSYS; | 1179 | return -ERESTARTSYS; |
1057 | 1180 | ||
1058 | cam = video_get_drvdata(to_video_device(cd)); | 1181 | cam = video_get_drvdata(container_of(cd, struct video_device, |
1182 | class_dev)); | ||
1059 | if (!cam) { | 1183 | if (!cam) { |
1060 | mutex_unlock(&sn9c102_sysfs_lock); | 1184 | mutex_unlock(&sn9c102_sysfs_lock); |
1061 | return -ENODEV; | 1185 | return -ENODEV; |
@@ -1085,14 +1209,15 @@ static ssize_t | |||
1085 | sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) | 1209 | sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) |
1086 | { | 1210 | { |
1087 | struct sn9c102_device* cam; | 1211 | struct sn9c102_device* cam; |
1088 | u8 value; | 1212 | u16 value; |
1089 | ssize_t count; | 1213 | ssize_t count; |
1090 | int err; | 1214 | int err; |
1091 | 1215 | ||
1092 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | 1216 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) |
1093 | return -ERESTARTSYS; | 1217 | return -ERESTARTSYS; |
1094 | 1218 | ||
1095 | cam = video_get_drvdata(to_video_device(cd)); | 1219 | cam = video_get_drvdata(container_of(cd, struct video_device, |
1220 | class_dev)); | ||
1096 | if (!cam) { | 1221 | if (!cam) { |
1097 | mutex_unlock(&sn9c102_sysfs_lock); | 1222 | mutex_unlock(&sn9c102_sysfs_lock); |
1098 | return -ENODEV; | 1223 | return -ENODEV; |
@@ -1103,7 +1228,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) | |||
1103 | return -ENOSYS; | 1228 | return -ENOSYS; |
1104 | } | 1229 | } |
1105 | 1230 | ||
1106 | value = sn9c102_strtou8(buf, len, &count); | 1231 | value = sn9c102_strtou16(buf, len, &count); |
1107 | if (!count) { | 1232 | if (!count) { |
1108 | mutex_unlock(&sn9c102_sysfs_lock); | 1233 | mutex_unlock(&sn9c102_sysfs_lock); |
1109 | return -EINVAL; | 1234 | return -EINVAL; |
@@ -1131,13 +1256,14 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) | |||
1131 | struct sn9c102_device* cam; | 1256 | struct sn9c102_device* cam; |
1132 | enum sn9c102_bridge bridge; | 1257 | enum sn9c102_bridge bridge; |
1133 | ssize_t res = 0; | 1258 | ssize_t res = 0; |
1134 | u8 value; | 1259 | u16 value; |
1135 | ssize_t count; | 1260 | ssize_t count; |
1136 | 1261 | ||
1137 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | 1262 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) |
1138 | return -ERESTARTSYS; | 1263 | return -ERESTARTSYS; |
1139 | 1264 | ||
1140 | cam = video_get_drvdata(to_video_device(cd)); | 1265 | cam = video_get_drvdata(container_of(cd, struct video_device, |
1266 | class_dev)); | ||
1141 | if (!cam) { | 1267 | if (!cam) { |
1142 | mutex_unlock(&sn9c102_sysfs_lock); | 1268 | mutex_unlock(&sn9c102_sysfs_lock); |
1143 | return -ENODEV; | 1269 | return -ENODEV; |
@@ -1147,7 +1273,7 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) | |||
1147 | 1273 | ||
1148 | mutex_unlock(&sn9c102_sysfs_lock); | 1274 | mutex_unlock(&sn9c102_sysfs_lock); |
1149 | 1275 | ||
1150 | value = sn9c102_strtou8(buf, len, &count); | 1276 | value = sn9c102_strtou16(buf, len, &count); |
1151 | if (!count) | 1277 | if (!count) |
1152 | return -EINVAL; | 1278 | return -EINVAL; |
1153 | 1279 | ||
@@ -1160,9 +1286,11 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) | |||
1160 | res = sn9c102_store_val(cd, buf, len); | 1286 | res = sn9c102_store_val(cd, buf, len); |
1161 | break; | 1287 | break; |
1162 | case BRIDGE_SN9C103: | 1288 | case BRIDGE_SN9C103: |
1289 | case BRIDGE_SN9C105: | ||
1290 | case BRIDGE_SN9C120: | ||
1163 | if (value > 0x7f) | 1291 | if (value > 0x7f) |
1164 | return -EINVAL; | 1292 | return -EINVAL; |
1165 | if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0) | 1293 | if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0) |
1166 | res = sn9c102_store_val(cd, buf, len); | 1294 | res = sn9c102_store_val(cd, buf, len); |
1167 | break; | 1295 | break; |
1168 | } | 1296 | } |
@@ -1175,10 +1303,10 @@ static ssize_t | |||
1175 | sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) | 1303 | sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) |
1176 | { | 1304 | { |
1177 | ssize_t res = 0; | 1305 | ssize_t res = 0; |
1178 | u8 value; | 1306 | u16 value; |
1179 | ssize_t count; | 1307 | ssize_t count; |
1180 | 1308 | ||
1181 | value = sn9c102_strtou8(buf, len, &count); | 1309 | value = sn9c102_strtou16(buf, len, &count); |
1182 | if (!count || value > 0x7f) | 1310 | if (!count || value > 0x7f) |
1183 | return -EINVAL; | 1311 | return -EINVAL; |
1184 | 1312 | ||
@@ -1193,10 +1321,10 @@ static ssize_t | |||
1193 | sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) | 1321 | sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) |
1194 | { | 1322 | { |
1195 | ssize_t res = 0; | 1323 | ssize_t res = 0; |
1196 | u8 value; | 1324 | u16 value; |
1197 | ssize_t count; | 1325 | ssize_t count; |
1198 | 1326 | ||
1199 | value = sn9c102_strtou8(buf, len, &count); | 1327 | value = sn9c102_strtou16(buf, len, &count); |
1200 | if (!count || value > 0x7f) | 1328 | if (!count || value > 0x7f) |
1201 | return -EINVAL; | 1329 | return -EINVAL; |
1202 | 1330 | ||
@@ -1212,7 +1340,8 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) | |||
1212 | struct sn9c102_device* cam; | 1340 | struct sn9c102_device* cam; |
1213 | ssize_t count; | 1341 | ssize_t count; |
1214 | 1342 | ||
1215 | cam = video_get_drvdata(to_video_device(cd)); | 1343 | cam = video_get_drvdata(container_of(cd, struct video_device, |
1344 | class_dev)); | ||
1216 | if (!cam) | 1345 | if (!cam) |
1217 | return -ENODEV; | 1346 | return -ENODEV; |
1218 | 1347 | ||
@@ -1243,30 +1372,36 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, | |||
1243 | static int sn9c102_create_sysfs(struct sn9c102_device* cam) | 1372 | static int sn9c102_create_sysfs(struct sn9c102_device* cam) |
1244 | { | 1373 | { |
1245 | struct video_device *v4ldev = cam->v4ldev; | 1374 | struct video_device *v4ldev = cam->v4ldev; |
1246 | int rc; | 1375 | int err = 0; |
1247 | 1376 | ||
1248 | rc = video_device_create_file(v4ldev, &class_device_attr_reg); | 1377 | if ((err = video_device_create_file(v4ldev, &class_device_attr_reg))) |
1249 | if (rc) goto err; | 1378 | goto err_out; |
1250 | rc = video_device_create_file(v4ldev, &class_device_attr_val); | 1379 | if ((err = video_device_create_file(v4ldev, &class_device_attr_val))) |
1251 | if (rc) goto err_reg; | 1380 | goto err_reg; |
1252 | rc = video_device_create_file(v4ldev, &class_device_attr_frame_header); | 1381 | if ((err = video_device_create_file(v4ldev, |
1253 | if (rc) goto err_val; | 1382 | &class_device_attr_frame_header))) |
1383 | goto err_val; | ||
1254 | 1384 | ||
1255 | if (cam->sensor.sysfs_ops) { | 1385 | if (cam->sensor.sysfs_ops) { |
1256 | rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg); | 1386 | if ((err = video_device_create_file(v4ldev, |
1257 | if (rc) goto err_frhead; | 1387 | &class_device_attr_i2c_reg))) |
1258 | rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val); | 1388 | goto err_frame_header; |
1259 | if (rc) goto err_i2c_reg; | 1389 | if ((err = video_device_create_file(v4ldev, |
1390 | &class_device_attr_i2c_val))) | ||
1391 | goto err_i2c_reg; | ||
1260 | } | 1392 | } |
1261 | 1393 | ||
1262 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { | 1394 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { |
1263 | rc = video_device_create_file(v4ldev, &class_device_attr_green); | 1395 | if ((err = video_device_create_file(v4ldev, |
1264 | if (rc) goto err_i2c_val; | 1396 | &class_device_attr_green))) |
1265 | } else if (cam->bridge == BRIDGE_SN9C103) { | 1397 | goto err_i2c_val; |
1266 | rc = video_device_create_file(v4ldev, &class_device_attr_blue); | 1398 | } else { |
1267 | if (rc) goto err_i2c_val; | 1399 | if ((err = video_device_create_file(v4ldev, |
1268 | rc = video_device_create_file(v4ldev, &class_device_attr_red); | 1400 | &class_device_attr_blue))) |
1269 | if (rc) goto err_blue; | 1401 | goto err_i2c_val; |
1402 | if ((err = video_device_create_file(v4ldev, | ||
1403 | &class_device_attr_red))) | ||
1404 | goto err_blue; | ||
1270 | } | 1405 | } |
1271 | 1406 | ||
1272 | return 0; | 1407 | return 0; |
@@ -1279,14 +1414,14 @@ err_i2c_val: | |||
1279 | err_i2c_reg: | 1414 | err_i2c_reg: |
1280 | if (cam->sensor.sysfs_ops) | 1415 | if (cam->sensor.sysfs_ops) |
1281 | video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); | 1416 | video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); |
1282 | err_frhead: | 1417 | err_frame_header: |
1283 | video_device_remove_file(v4ldev, &class_device_attr_frame_header); | 1418 | video_device_remove_file(v4ldev, &class_device_attr_frame_header); |
1284 | err_val: | 1419 | err_val: |
1285 | video_device_remove_file(v4ldev, &class_device_attr_val); | 1420 | video_device_remove_file(v4ldev, &class_device_attr_val); |
1286 | err_reg: | 1421 | err_reg: |
1287 | video_device_remove_file(v4ldev, &class_device_attr_reg); | 1422 | video_device_remove_file(v4ldev, &class_device_attr_reg); |
1288 | err: | 1423 | err_out: |
1289 | return rc; | 1424 | return err; |
1290 | } | 1425 | } |
1291 | #endif /* CONFIG_VIDEO_ADV_DEBUG */ | 1426 | #endif /* CONFIG_VIDEO_ADV_DEBUG */ |
1292 | 1427 | ||
@@ -1297,10 +1432,36 @@ sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix) | |||
1297 | { | 1432 | { |
1298 | int err = 0; | 1433 | int err = 0; |
1299 | 1434 | ||
1300 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | 1435 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || |
1301 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18); | 1436 | pix->pixelformat == V4L2_PIX_FMT_JPEG) { |
1302 | else | 1437 | switch (cam->bridge) { |
1303 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18); | 1438 | case BRIDGE_SN9C101: |
1439 | case BRIDGE_SN9C102: | ||
1440 | case BRIDGE_SN9C103: | ||
1441 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, | ||
1442 | 0x18); | ||
1443 | break; | ||
1444 | case BRIDGE_SN9C105: | ||
1445 | case BRIDGE_SN9C120: | ||
1446 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, | ||
1447 | 0x18); | ||
1448 | break; | ||
1449 | } | ||
1450 | } else { | ||
1451 | switch (cam->bridge) { | ||
1452 | case BRIDGE_SN9C101: | ||
1453 | case BRIDGE_SN9C102: | ||
1454 | case BRIDGE_SN9C103: | ||
1455 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, | ||
1456 | 0x18); | ||
1457 | break; | ||
1458 | case BRIDGE_SN9C105: | ||
1459 | case BRIDGE_SN9C120: | ||
1460 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, | ||
1461 | 0x18); | ||
1462 | break; | ||
1463 | } | ||
1464 | } | ||
1304 | 1465 | ||
1305 | return err ? -EIO : 0; | 1466 | return err ? -EIO : 0; |
1306 | } | 1467 | } |
@@ -1310,12 +1471,46 @@ static int | |||
1310 | sn9c102_set_compression(struct sn9c102_device* cam, | 1471 | sn9c102_set_compression(struct sn9c102_device* cam, |
1311 | struct v4l2_jpegcompression* compression) | 1472 | struct v4l2_jpegcompression* compression) |
1312 | { | 1473 | { |
1313 | int err = 0; | 1474 | int i, err = 0; |
1314 | 1475 | ||
1476 | switch (cam->bridge) { | ||
1477 | case BRIDGE_SN9C101: | ||
1478 | case BRIDGE_SN9C102: | ||
1479 | case BRIDGE_SN9C103: | ||
1315 | if (compression->quality == 0) | 1480 | if (compression->quality == 0) |
1316 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17); | 1481 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, |
1482 | 0x17); | ||
1317 | else if (compression->quality == 1) | 1483 | else if (compression->quality == 1) |
1318 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17); | 1484 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, |
1485 | 0x17); | ||
1486 | break; | ||
1487 | case BRIDGE_SN9C105: | ||
1488 | case BRIDGE_SN9C120: | ||
1489 | if (compression->quality == 0) { | ||
1490 | for (i = 0; i <= 63; i++) { | ||
1491 | err += sn9c102_write_reg(cam, | ||
1492 | SN9C102_Y_QTABLE0[i], | ||
1493 | 0x100 + i); | ||
1494 | err += sn9c102_write_reg(cam, | ||
1495 | SN9C102_UV_QTABLE0[i], | ||
1496 | 0x140 + i); | ||
1497 | } | ||
1498 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, | ||
1499 | 0x18); | ||
1500 | } else if (compression->quality == 1) { | ||
1501 | for (i = 0; i <= 63; i++) { | ||
1502 | err += sn9c102_write_reg(cam, | ||
1503 | SN9C102_Y_QTABLE1[i], | ||
1504 | 0x100 + i); | ||
1505 | err += sn9c102_write_reg(cam, | ||
1506 | SN9C102_UV_QTABLE1[i], | ||
1507 | 0x140 + i); | ||
1508 | } | ||
1509 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40, | ||
1510 | 0x18); | ||
1511 | } | ||
1512 | break; | ||
1513 | } | ||
1319 | 1514 | ||
1320 | return err ? -EIO : 0; | 1515 | return err ? -EIO : 0; |
1321 | } | 1516 | } |
@@ -1399,7 +1594,16 @@ static int sn9c102_init(struct sn9c102_device* cam) | |||
1399 | } | 1594 | } |
1400 | 1595 | ||
1401 | if (!(cam->state & DEV_INITIALIZED)) | 1596 | if (!(cam->state & DEV_INITIALIZED)) |
1402 | cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1; | 1597 | if (cam->bridge == BRIDGE_SN9C101 || |
1598 | cam->bridge == BRIDGE_SN9C102 || | ||
1599 | cam->bridge == BRIDGE_SN9C103) { | ||
1600 | cam->compression.quality = cam->reg[0x17] & 0x01 ? | ||
1601 | 0 : 1; | ||
1602 | } else { | ||
1603 | cam->compression.quality = cam->reg[0x18] & 0x40 ? | ||
1604 | 0 : 1; | ||
1605 | err += sn9c102_set_compression(cam, &cam->compression); | ||
1606 | } | ||
1403 | else | 1607 | else |
1404 | err += sn9c102_set_compression(cam, &cam->compression); | 1608 | err += sn9c102_set_compression(cam, &cam->compression); |
1405 | err += sn9c102_set_pix_format(cam, &s->pix_format); | 1609 | err += sn9c102_set_pix_format(cam, &s->pix_format); |
@@ -1408,7 +1612,8 @@ static int sn9c102_init(struct sn9c102_device* cam) | |||
1408 | if (err) | 1612 | if (err) |
1409 | return err; | 1613 | return err; |
1410 | 1614 | ||
1411 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | 1615 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || |
1616 | s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | ||
1412 | DBG(3, "Compressed video format is active, quality %d", | 1617 | DBG(3, "Compressed video format is active, quality %d", |
1413 | cam->compression.quality); | 1618 | cam->compression.quality); |
1414 | else | 1619 | else |
@@ -1490,6 +1695,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp) | |||
1490 | 1695 | ||
1491 | if (cam->users) { | 1696 | if (cam->users) { |
1492 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); | 1697 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); |
1698 | DBG(3, "Simultaneous opens are not supported"); | ||
1493 | if ((filp->f_flags & O_NONBLOCK) || | 1699 | if ((filp->f_flags & O_NONBLOCK) || |
1494 | (filp->f_flags & O_NDELAY)) { | 1700 | (filp->f_flags & O_NDELAY)) { |
1495 | err = -EWOULDBLOCK; | 1701 | err = -EWOULDBLOCK; |
@@ -1628,6 +1834,17 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
1628 | mutex_unlock(&cam->fileop_mutex); | 1834 | mutex_unlock(&cam->fileop_mutex); |
1629 | return -EAGAIN; | 1835 | return -EAGAIN; |
1630 | } | 1836 | } |
1837 | if (!cam->module_param.frame_timeout) { | ||
1838 | err = wait_event_interruptible | ||
1839 | ( cam->wait_frame, | ||
1840 | (!list_empty(&cam->outqueue)) || | ||
1841 | (cam->state & DEV_DISCONNECTED) || | ||
1842 | (cam->state & DEV_MISCONFIGURED) ); | ||
1843 | if (err) { | ||
1844 | mutex_unlock(&cam->fileop_mutex); | ||
1845 | return err; | ||
1846 | } | ||
1847 | } else { | ||
1631 | timeout = wait_event_interruptible_timeout | 1848 | timeout = wait_event_interruptible_timeout |
1632 | ( cam->wait_frame, | 1849 | ( cam->wait_frame, |
1633 | (!list_empty(&cam->outqueue)) || | 1850 | (!list_empty(&cam->outqueue)) || |
@@ -1638,12 +1855,18 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
1638 | if (timeout < 0) { | 1855 | if (timeout < 0) { |
1639 | mutex_unlock(&cam->fileop_mutex); | 1856 | mutex_unlock(&cam->fileop_mutex); |
1640 | return timeout; | 1857 | return timeout; |
1858 | } else if (timeout == 0 && | ||
1859 | !(cam->state & DEV_DISCONNECTED)) { | ||
1860 | DBG(1, "Video frame timeout elapsed"); | ||
1861 | mutex_unlock(&cam->fileop_mutex); | ||
1862 | return -EIO; | ||
1863 | } | ||
1641 | } | 1864 | } |
1642 | if (cam->state & DEV_DISCONNECTED) { | 1865 | if (cam->state & DEV_DISCONNECTED) { |
1643 | mutex_unlock(&cam->fileop_mutex); | 1866 | mutex_unlock(&cam->fileop_mutex); |
1644 | return -ENODEV; | 1867 | return -ENODEV; |
1645 | } | 1868 | } |
1646 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) { | 1869 | if (cam->state & DEV_MISCONFIGURED) { |
1647 | mutex_unlock(&cam->fileop_mutex); | 1870 | mutex_unlock(&cam->fileop_mutex); |
1648 | return -EIO; | 1871 | return -EIO; |
1649 | } | 1872 | } |
@@ -1940,6 +2163,9 @@ exit: | |||
1940 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) | 2163 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) |
1941 | return -EFAULT; | 2164 | return -EFAULT; |
1942 | 2165 | ||
2166 | PDBGG("VIDIOC_G_CTRL: id %lu, value %lu", | ||
2167 | (unsigned long)ctrl.id, (unsigned long)ctrl.value); | ||
2168 | |||
1943 | return err; | 2169 | return err; |
1944 | } | 2170 | } |
1945 | 2171 | ||
@@ -2127,6 +2353,45 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) | |||
2127 | 2353 | ||
2128 | 2354 | ||
2129 | static int | 2355 | static int |
2356 | sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg) | ||
2357 | { | ||
2358 | struct v4l2_frmsizeenum frmsize; | ||
2359 | |||
2360 | if (copy_from_user(&frmsize, arg, sizeof(frmsize))) | ||
2361 | return -EFAULT; | ||
2362 | |||
2363 | if (frmsize.index != 0) | ||
2364 | return -EINVAL; | ||
2365 | |||
2366 | switch (cam->bridge) { | ||
2367 | case BRIDGE_SN9C101: | ||
2368 | case BRIDGE_SN9C102: | ||
2369 | case BRIDGE_SN9C103: | ||
2370 | if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X && | ||
2371 | frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) | ||
2372 | return -EINVAL; | ||
2373 | case BRIDGE_SN9C105: | ||
2374 | case BRIDGE_SN9C120: | ||
2375 | if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG && | ||
2376 | frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) | ||
2377 | return -EINVAL; | ||
2378 | } | ||
2379 | |||
2380 | frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE; | ||
2381 | frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16; | ||
2382 | frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16; | ||
2383 | frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width; | ||
2384 | frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height; | ||
2385 | memset(&frmsize.reserved, 0, sizeof(frmsize.reserved)); | ||
2386 | |||
2387 | if (copy_to_user(arg, &frmsize, sizeof(frmsize))) | ||
2388 | return -EFAULT; | ||
2389 | |||
2390 | return 0; | ||
2391 | } | ||
2392 | |||
2393 | |||
2394 | static int | ||
2130 | sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) | 2395 | sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) |
2131 | { | 2396 | { |
2132 | struct v4l2_fmtdesc fmtd; | 2397 | struct v4l2_fmtdesc fmtd; |
@@ -2134,12 +2399,26 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) | |||
2134 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) | 2399 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) |
2135 | return -EFAULT; | 2400 | return -EFAULT; |
2136 | 2401 | ||
2402 | if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2403 | return -EINVAL; | ||
2404 | |||
2137 | if (fmtd.index == 0) { | 2405 | if (fmtd.index == 0) { |
2138 | strcpy(fmtd.description, "bayer rgb"); | 2406 | strcpy(fmtd.description, "bayer rgb"); |
2139 | fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; | 2407 | fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; |
2140 | } else if (fmtd.index == 1) { | 2408 | } else if (fmtd.index == 1) { |
2409 | switch (cam->bridge) { | ||
2410 | case BRIDGE_SN9C101: | ||
2411 | case BRIDGE_SN9C102: | ||
2412 | case BRIDGE_SN9C103: | ||
2141 | strcpy(fmtd.description, "compressed"); | 2413 | strcpy(fmtd.description, "compressed"); |
2142 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; | 2414 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; |
2415 | break; | ||
2416 | case BRIDGE_SN9C105: | ||
2417 | case BRIDGE_SN9C120: | ||
2418 | strcpy(fmtd.description, "JPEG"); | ||
2419 | fmtd.pixelformat = V4L2_PIX_FMT_JPEG; | ||
2420 | break; | ||
2421 | } | ||
2143 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; | 2422 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; |
2144 | } else | 2423 | } else |
2145 | return -EINVAL; | 2424 | return -EINVAL; |
@@ -2166,7 +2445,8 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) | |||
2166 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 2445 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
2167 | return -EINVAL; | 2446 | return -EINVAL; |
2168 | 2447 | ||
2169 | pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X) | 2448 | pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X || |
2449 | pfmt->pixelformat==V4L2_PIX_FMT_JPEG) | ||
2170 | ? 0 : (pfmt->width * pfmt->priv) / 8; | 2450 | ? 0 : (pfmt->width * pfmt->priv) / 8; |
2171 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | 2451 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); |
2172 | pfmt->field = V4L2_FIELD_NONE; | 2452 | pfmt->field = V4L2_FIELD_NONE; |
@@ -2237,12 +2517,25 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2237 | pix->width = rect.width / scale; | 2517 | pix->width = rect.width / scale; |
2238 | pix->height = rect.height / scale; | 2518 | pix->height = rect.height / scale; |
2239 | 2519 | ||
2520 | switch (cam->bridge) { | ||
2521 | case BRIDGE_SN9C101: | ||
2522 | case BRIDGE_SN9C102: | ||
2523 | case BRIDGE_SN9C103: | ||
2240 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && | 2524 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && |
2241 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | 2525 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) |
2242 | pix->pixelformat = pfmt->pixelformat; | 2526 | pix->pixelformat = pfmt->pixelformat; |
2527 | break; | ||
2528 | case BRIDGE_SN9C105: | ||
2529 | case BRIDGE_SN9C120: | ||
2530 | if (pix->pixelformat != V4L2_PIX_FMT_JPEG && | ||
2531 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | ||
2532 | pix->pixelformat = pfmt->pixelformat; | ||
2533 | break; | ||
2534 | } | ||
2243 | pix->priv = pfmt->priv; /* bpp */ | 2535 | pix->priv = pfmt->priv; /* bpp */ |
2244 | pix->colorspace = pfmt->colorspace; | 2536 | pix->colorspace = pfmt->colorspace; |
2245 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | 2537 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || |
2538 | pix->pixelformat == V4L2_PIX_FMT_JPEG) | ||
2246 | ? 0 : (pix->width * pix->priv) / 8; | 2539 | ? 0 : (pix->width * pix->priv) / 8; |
2247 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); | 2540 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); |
2248 | pix->field = V4L2_FIELD_NONE; | 2541 | pix->field = V4L2_FIELD_NONE; |
@@ -2315,8 +2608,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2315 | static int | 2608 | static int |
2316 | sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg) | 2609 | sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg) |
2317 | { | 2610 | { |
2318 | if (copy_to_user(arg, &cam->compression, | 2611 | if (copy_to_user(arg, &cam->compression, sizeof(cam->compression))) |
2319 | sizeof(cam->compression))) | ||
2320 | return -EFAULT; | 2612 | return -EFAULT; |
2321 | 2613 | ||
2322 | return 0; | 2614 | return 0; |
@@ -2471,6 +2763,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, | |||
2471 | struct sn9c102_frame_t *f; | 2763 | struct sn9c102_frame_t *f; |
2472 | unsigned long lock_flags; | 2764 | unsigned long lock_flags; |
2473 | long timeout; | 2765 | long timeout; |
2766 | int err = 0; | ||
2474 | 2767 | ||
2475 | if (copy_from_user(&b, arg, sizeof(b))) | 2768 | if (copy_from_user(&b, arg, sizeof(b))) |
2476 | return -EFAULT; | 2769 | return -EFAULT; |
@@ -2483,6 +2776,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, | |||
2483 | return -EINVAL; | 2776 | return -EINVAL; |
2484 | if (filp->f_flags & O_NONBLOCK) | 2777 | if (filp->f_flags & O_NONBLOCK) |
2485 | return -EAGAIN; | 2778 | return -EAGAIN; |
2779 | if (!cam->module_param.frame_timeout) { | ||
2780 | err = wait_event_interruptible | ||
2781 | ( cam->wait_frame, | ||
2782 | (!list_empty(&cam->outqueue)) || | ||
2783 | (cam->state & DEV_DISCONNECTED) || | ||
2784 | (cam->state & DEV_MISCONFIGURED) ); | ||
2785 | if (err) | ||
2786 | return err; | ||
2787 | } else { | ||
2486 | timeout = wait_event_interruptible_timeout | 2788 | timeout = wait_event_interruptible_timeout |
2487 | ( cam->wait_frame, | 2789 | ( cam->wait_frame, |
2488 | (!list_empty(&cam->outqueue)) || | 2790 | (!list_empty(&cam->outqueue)) || |
@@ -2492,9 +2794,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, | |||
2492 | 1000 * msecs_to_jiffies(1) ); | 2794 | 1000 * msecs_to_jiffies(1) ); |
2493 | if (timeout < 0) | 2795 | if (timeout < 0) |
2494 | return timeout; | 2796 | return timeout; |
2797 | else if (timeout == 0 && | ||
2798 | !(cam->state & DEV_DISCONNECTED)) { | ||
2799 | DBG(1, "Video frame timeout elapsed"); | ||
2800 | return -EIO; | ||
2801 | } | ||
2802 | } | ||
2495 | if (cam->state & DEV_DISCONNECTED) | 2803 | if (cam->state & DEV_DISCONNECTED) |
2496 | return -ENODEV; | 2804 | return -ENODEV; |
2497 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) | 2805 | if (cam->state & DEV_MISCONFIGURED) |
2498 | return -EIO; | 2806 | return -EIO; |
2499 | } | 2807 | } |
2500 | 2808 | ||
@@ -2612,6 +2920,70 @@ sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg) | |||
2612 | } | 2920 | } |
2613 | 2921 | ||
2614 | 2922 | ||
2923 | static int | ||
2924 | sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg) | ||
2925 | { | ||
2926 | struct v4l2_audio audio; | ||
2927 | |||
2928 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) | ||
2929 | return -EINVAL; | ||
2930 | |||
2931 | if (copy_from_user(&audio, arg, sizeof(audio))) | ||
2932 | return -EFAULT; | ||
2933 | |||
2934 | if (audio.index != 0) | ||
2935 | return -EINVAL; | ||
2936 | |||
2937 | strcpy(audio.name, "Microphone"); | ||
2938 | audio.capability = 0; | ||
2939 | audio.mode = 0; | ||
2940 | |||
2941 | if (copy_to_user(arg, &audio, sizeof(audio))) | ||
2942 | return -EFAULT; | ||
2943 | |||
2944 | return 0; | ||
2945 | } | ||
2946 | |||
2947 | |||
2948 | static int | ||
2949 | sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg) | ||
2950 | { | ||
2951 | struct v4l2_audio audio; | ||
2952 | |||
2953 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) | ||
2954 | return -EINVAL; | ||
2955 | |||
2956 | if (copy_from_user(&audio, arg, sizeof(audio))) | ||
2957 | return -EFAULT; | ||
2958 | |||
2959 | memset(&audio, 0, sizeof(audio)); | ||
2960 | strcpy(audio.name, "Microphone"); | ||
2961 | |||
2962 | if (copy_to_user(arg, &audio, sizeof(audio))) | ||
2963 | return -EFAULT; | ||
2964 | |||
2965 | return 0; | ||
2966 | } | ||
2967 | |||
2968 | |||
2969 | static int | ||
2970 | sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg) | ||
2971 | { | ||
2972 | struct v4l2_audio audio; | ||
2973 | |||
2974 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) | ||
2975 | return -EINVAL; | ||
2976 | |||
2977 | if (copy_from_user(&audio, arg, sizeof(audio))) | ||
2978 | return -EFAULT; | ||
2979 | |||
2980 | if (audio.index != 0) | ||
2981 | return -EINVAL; | ||
2982 | |||
2983 | return 0; | ||
2984 | } | ||
2985 | |||
2986 | |||
2615 | static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, | 2987 | static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, |
2616 | unsigned int cmd, void __user * arg) | 2988 | unsigned int cmd, void __user * arg) |
2617 | { | 2989 | { |
@@ -2649,6 +3021,9 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, | |||
2649 | case VIDIOC_S_CROP: | 3021 | case VIDIOC_S_CROP: |
2650 | return sn9c102_vidioc_s_crop(cam, arg); | 3022 | return sn9c102_vidioc_s_crop(cam, arg); |
2651 | 3023 | ||
3024 | case VIDIOC_ENUM_FRAMESIZES: | ||
3025 | return sn9c102_vidioc_enum_framesizes(cam, arg); | ||
3026 | |||
2652 | case VIDIOC_ENUM_FMT: | 3027 | case VIDIOC_ENUM_FMT: |
2653 | return sn9c102_vidioc_enum_fmt(cam, arg); | 3028 | return sn9c102_vidioc_enum_fmt(cam, arg); |
2654 | 3029 | ||
@@ -2689,11 +3064,21 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, | |||
2689 | case VIDIOC_S_PARM: | 3064 | case VIDIOC_S_PARM: |
2690 | return sn9c102_vidioc_s_parm(cam, arg); | 3065 | return sn9c102_vidioc_s_parm(cam, arg); |
2691 | 3066 | ||
3067 | case VIDIOC_ENUMAUDIO: | ||
3068 | return sn9c102_vidioc_enumaudio(cam, arg); | ||
3069 | |||
3070 | case VIDIOC_G_AUDIO: | ||
3071 | return sn9c102_vidioc_g_audio(cam, arg); | ||
3072 | |||
3073 | case VIDIOC_S_AUDIO: | ||
3074 | return sn9c102_vidioc_s_audio(cam, arg); | ||
3075 | |||
2692 | case VIDIOC_G_STD: | 3076 | case VIDIOC_G_STD: |
2693 | case VIDIOC_S_STD: | 3077 | case VIDIOC_S_STD: |
2694 | case VIDIOC_QUERYSTD: | 3078 | case VIDIOC_QUERYSTD: |
2695 | case VIDIOC_ENUMSTD: | 3079 | case VIDIOC_ENUMSTD: |
2696 | case VIDIOC_QUERYMENU: | 3080 | case VIDIOC_QUERYMENU: |
3081 | case VIDIOC_ENUM_FRAMEINTERVALS: | ||
2697 | return -EINVAL; | 3082 | return -EINVAL; |
2698 | 3083 | ||
2699 | default: | 3084 | default: |
@@ -2741,6 +3126,7 @@ static const struct file_operations sn9c102_fops = { | |||
2741 | .open = sn9c102_open, | 3126 | .open = sn9c102_open, |
2742 | .release = sn9c102_release, | 3127 | .release = sn9c102_release, |
2743 | .ioctl = sn9c102_ioctl, | 3128 | .ioctl = sn9c102_ioctl, |
3129 | .compat_ioctl = v4l_compat_ioctl32, | ||
2744 | .read = sn9c102_read, | 3130 | .read = sn9c102_read, |
2745 | .poll = sn9c102_poll, | 3131 | .poll = sn9c102_poll, |
2746 | .mmap = sn9c102_mmap, | 3132 | .mmap = sn9c102_mmap, |
@@ -2765,7 +3151,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
2765 | cam->usbdev = udev; | 3151 | cam->usbdev = udev; |
2766 | 3152 | ||
2767 | if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { | 3153 | if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { |
2768 | DBG(1, "kmalloc() failed"); | 3154 | DBG(1, "kzalloc() failed"); |
2769 | err = -ENOMEM; | 3155 | err = -ENOMEM; |
2770 | goto fail; | 3156 | goto fail; |
2771 | } | 3157 | } |
@@ -2779,24 +3165,31 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
2779 | mutex_init(&cam->dev_mutex); | 3165 | mutex_init(&cam->dev_mutex); |
2780 | 3166 | ||
2781 | r = sn9c102_read_reg(cam, 0x00); | 3167 | r = sn9c102_read_reg(cam, 0x00); |
2782 | if (r < 0 || r != 0x10) { | 3168 | if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { |
2783 | DBG(1, "Sorry, this is not a SN9C10x based camera " | 3169 | DBG(1, "Sorry, this is not a SN9C1xx based camera " |
2784 | "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); | 3170 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
2785 | err = -ENODEV; | 3171 | err = -ENODEV; |
2786 | goto fail; | 3172 | goto fail; |
2787 | } | 3173 | } |
2788 | 3174 | ||
2789 | cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ? | 3175 | cam->bridge = id->driver_info; |
2790 | BRIDGE_SN9C103 : BRIDGE_SN9C102; | ||
2791 | switch (cam->bridge) { | 3176 | switch (cam->bridge) { |
2792 | case BRIDGE_SN9C101: | 3177 | case BRIDGE_SN9C101: |
2793 | case BRIDGE_SN9C102: | 3178 | case BRIDGE_SN9C102: |
2794 | DBG(2, "SN9C10[12] PC Camera Controller detected " | 3179 | DBG(2, "SN9C10[12] PC Camera Controller detected " |
2795 | "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); | 3180 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
2796 | break; | 3181 | break; |
2797 | case BRIDGE_SN9C103: | 3182 | case BRIDGE_SN9C103: |
2798 | DBG(2, "SN9C103 PC Camera Controller detected " | 3183 | DBG(2, "SN9C103 PC Camera Controller detected " |
2799 | "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); | 3184 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3185 | break; | ||
3186 | case BRIDGE_SN9C105: | ||
3187 | DBG(2, "SN9C105 PC Camera Controller detected " | ||
3188 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | ||
3189 | break; | ||
3190 | case BRIDGE_SN9C120: | ||
3191 | DBG(2, "SN9C120 PC Camera Controller detected " | ||
3192 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | ||
2800 | break; | 3193 | break; |
2801 | } | 3194 | } |
2802 | 3195 | ||
@@ -2816,12 +3209,18 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
2816 | goto fail; | 3209 | goto fail; |
2817 | } | 3210 | } |
2818 | 3211 | ||
3212 | if (!(cam->bridge & cam->sensor.supported_bridge)) { | ||
3213 | DBG(1, "Bridge not supported"); | ||
3214 | err = -ENODEV; | ||
3215 | goto fail; | ||
3216 | } | ||
3217 | |||
2819 | if (sn9c102_init(cam)) { | 3218 | if (sn9c102_init(cam)) { |
2820 | DBG(1, "Initialization failed. I will retry on open()."); | 3219 | DBG(1, "Initialization failed. I will retry on open()."); |
2821 | cam->state |= DEV_MISCONFIGURED; | 3220 | cam->state |= DEV_MISCONFIGURED; |
2822 | } | 3221 | } |
2823 | 3222 | ||
2824 | strcpy(cam->v4ldev->name, "SN9C10x PC Camera"); | 3223 | strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); |
2825 | cam->v4ldev->owner = THIS_MODULE; | 3224 | cam->v4ldev->owner = THIS_MODULE; |
2826 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | 3225 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; |
2827 | cam->v4ldev->hardware = 0; | 3226 | cam->v4ldev->hardware = 0; |
@@ -2838,7 +3237,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
2838 | DBG(1, "V4L2 device registration failed"); | 3237 | DBG(1, "V4L2 device registration failed"); |
2839 | if (err == -ENFILE && video_nr[dev_nr] == -1) | 3238 | if (err == -ENFILE && video_nr[dev_nr] == -1) |
2840 | DBG(1, "Free /dev/videoX node not found"); | 3239 | DBG(1, "Free /dev/videoX node not found"); |
2841 | goto fail2; | 3240 | video_nr[dev_nr] = -1; |
3241 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
3242 | mutex_unlock(&cam->dev_mutex); | ||
3243 | goto fail; | ||
2842 | } | 3244 | } |
2843 | 3245 | ||
2844 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); | 3246 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); |
@@ -2850,9 +3252,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
2850 | 3252 | ||
2851 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 3253 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
2852 | err = sn9c102_create_sysfs(cam); | 3254 | err = sn9c102_create_sysfs(cam); |
2853 | if (err) | 3255 | if (!err) |
2854 | goto fail3; | 3256 | DBG(2, "Optional device control through 'sysfs' " |
2855 | DBG(2, "Optional device control through 'sysfs' interface ready"); | 3257 | "interface ready"); |
3258 | else | ||
3259 | DBG(2, "Failed to create optional 'sysfs' interface for " | ||
3260 | "device controlling. Error #%d", err); | ||
3261 | #else | ||
3262 | DBG(2, "Optional device control through 'sysfs' interface disabled"); | ||
2856 | #endif | 3263 | #endif |
2857 | 3264 | ||
2858 | usb_set_intfdata(intf, cam); | 3265 | usb_set_intfdata(intf, cam); |
@@ -2861,14 +3268,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
2861 | 3268 | ||
2862 | return 0; | 3269 | return 0; |
2863 | 3270 | ||
2864 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
2865 | fail3: | ||
2866 | video_unregister_device(cam->v4ldev); | ||
2867 | #endif | ||
2868 | fail2: | ||
2869 | video_nr[dev_nr] = -1; | ||
2870 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
2871 | mutex_unlock(&cam->dev_mutex); | ||
2872 | fail: | 3271 | fail: |
2873 | if (cam) { | 3272 | if (cam) { |
2874 | kfree(cam->control_buffer); | 3273 | kfree(cam->control_buffer); |
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h new file mode 100644 index 000000000000..3a682eca6c65 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h | |||
@@ -0,0 +1,142 @@ | |||
1 | /*************************************************************************** | ||
2 | * Table of device identifiers of the SN9C1xx PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program 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 * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _SN9C102_DEVTABLE_H_ | ||
22 | #define _SN9C102_DEVTABLE_H_ | ||
23 | |||
24 | #include <linux/usb.h> | ||
25 | |||
26 | struct sn9c102_device; | ||
27 | |||
28 | /* | ||
29 | Each SN9C1xx camera has proper PID/VID identifiers. | ||
30 | SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to | ||
31 | handle the video class interface. | ||
32 | */ | ||
33 | #define SN9C102_USB_DEVICE(vend, prod, bridge) \ | ||
34 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | ||
35 | USB_DEVICE_ID_MATCH_INT_CLASS, \ | ||
36 | .idVendor = (vend), \ | ||
37 | .idProduct = (prod), \ | ||
38 | .bInterfaceClass = 0xff, \ | ||
39 | .driver_info = (bridge) | ||
40 | |||
41 | static const struct usb_device_id sn9c102_id_table[] = { | ||
42 | /* SN9C101 and SN9C102 */ | ||
43 | { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), }, | ||
44 | { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), }, | ||
45 | { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), }, | ||
46 | { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), }, | ||
47 | { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, | ||
48 | { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), }, | ||
49 | { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), }, | ||
50 | { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), }, | ||
51 | { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), }, | ||
52 | { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), }, | ||
53 | { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), }, | ||
54 | { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, | ||
55 | { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, | ||
56 | { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, | ||
57 | { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, | ||
58 | { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, | ||
59 | { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, | ||
60 | { SN9C102_USB_DEVICE(0x0c45, 0x603f, BRIDGE_SN9C102), }, | ||
61 | /* SN9C103 */ | ||
62 | { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, | ||
63 | { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, | ||
64 | { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, | ||
65 | { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, | ||
66 | { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, | ||
67 | { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, | ||
68 | { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), }, | ||
69 | { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, | ||
70 | { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), }, | ||
71 | { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, | ||
72 | { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, | ||
73 | { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, | ||
74 | { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, | ||
75 | { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, | ||
76 | { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, | ||
77 | { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, | ||
78 | { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, | ||
79 | { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), }, | ||
80 | { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), }, | ||
81 | { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, | ||
82 | { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, | ||
83 | { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, | ||
84 | { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, | ||
85 | { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, | ||
86 | { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, | ||
87 | { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, | ||
88 | /* SN9C105 */ | ||
89 | { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, | ||
90 | { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, | ||
91 | { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, | ||
92 | { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, | ||
93 | { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, | ||
94 | { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, | ||
95 | { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, | ||
96 | { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, | ||
97 | { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, | ||
98 | { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, | ||
99 | { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, | ||
100 | /* SN9C120 */ | ||
101 | { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, | ||
102 | { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, | ||
103 | { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, | ||
104 | { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, | ||
105 | { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), }, | ||
106 | { } | ||
107 | }; | ||
108 | |||
109 | /* | ||
110 | Probing functions: on success, you must attach the sensor to the camera | ||
111 | by calling sn9c102_attach_sensor(). | ||
112 | To enable the I2C communication, you might need to perform a really basic | ||
113 | initialization of the SN9C1XX chip. | ||
114 | Functions must return 0 on success, the appropriate error otherwise. | ||
115 | */ | ||
116 | extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); | ||
117 | extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); | ||
118 | extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); | ||
119 | extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); | ||
120 | extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); | ||
121 | extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); | ||
122 | extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); | ||
123 | extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); | ||
124 | |||
125 | /* | ||
126 | Add the above entries to this table. Be sure to add the entry in the right | ||
127 | place, since, on failure, the next probing routine is called according to | ||
128 | the order of the list below, from top to bottom. | ||
129 | */ | ||
130 | static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { | ||
131 | &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ | ||
132 | &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ | ||
133 | &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ | ||
134 | &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ | ||
135 | &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ | ||
136 | &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ | ||
137 | &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ | ||
138 | &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ | ||
139 | NULL, | ||
140 | }; | ||
141 | |||
142 | #endif /* _SN9C102_DEVTABLE_H_ */ | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c index c4117bf64b69..7ae368f60d89 100644 --- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c +++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera * | 2 | * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera * |
3 | * Controllers * | 3 | * Controllers * |
4 | * * | 4 | * * |
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | 5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * |
6 | * * | 6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * | 7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * | 8 | * it under the terms of the GNU General Public License as published by * |
@@ -124,7 +124,7 @@ static int hv7131d_set_ctrl(struct sn9c102_device* cam, | |||
124 | static int hv7131d_set_crop(struct sn9c102_device* cam, | 124 | static int hv7131d_set_crop(struct sn9c102_device* cam, |
125 | const struct v4l2_rect* rect) | 125 | const struct v4l2_rect* rect) |
126 | { | 126 | { |
127 | struct sn9c102_sensor* s = &hv7131d; | 127 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); |
128 | int err = 0; | 128 | int err = 0; |
129 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2, | 129 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2, |
130 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; | 130 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; |
@@ -153,6 +153,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam, | |||
153 | static struct sn9c102_sensor hv7131d = { | 153 | static struct sn9c102_sensor hv7131d = { |
154 | .name = "HV7131D", | 154 | .name = "HV7131D", |
155 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 155 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
156 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | ||
156 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | 157 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, |
157 | .frequency = SN9C102_I2C_100KHZ, | 158 | .frequency = SN9C102_I2C_100KHZ, |
158 | .interface = SN9C102_I2C_2WIRES, | 159 | .interface = SN9C102_I2C_2WIRES, |
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c index 4169ea4a2e20..a33d1bc10f90 100644 --- a/drivers/media/video/sn9c102/sn9c102_mi0343.c +++ b/drivers/media/video/sn9c102/sn9c102_mi0343.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera * | 2 | * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera * |
3 | * Controllers * | 3 | * Controllers * |
4 | * * | 4 | * * |
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | 5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * |
6 | * * | 6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * | 7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * | 8 | * it under the terms of the GNU General Public License as published by * |
@@ -201,7 +201,7 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam, | |||
201 | static int mi0343_set_crop(struct sn9c102_device* cam, | 201 | static int mi0343_set_crop(struct sn9c102_device* cam, |
202 | const struct v4l2_rect* rect) | 202 | const struct v4l2_rect* rect) |
203 | { | 203 | { |
204 | struct sn9c102_sensor* s = &mi0343; | 204 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); |
205 | int err = 0; | 205 | int err = 0; |
206 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, | 206 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, |
207 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; | 207 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; |
@@ -237,6 +237,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam, | |||
237 | static struct sn9c102_sensor mi0343 = { | 237 | static struct sn9c102_sensor mi0343 = { |
238 | .name = "MI-0343", | 238 | .name = "MI-0343", |
239 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 239 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
240 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | ||
240 | .frequency = SN9C102_I2C_100KHZ, | 241 | .frequency = SN9C102_I2C_100KHZ, |
241 | .interface = SN9C102_I2C_2WIRES, | 242 | .interface = SN9C102_I2C_2WIRES, |
242 | .i2c_slave_id = 0x5d, | 243 | .i2c_slave_id = 0x5d, |
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c index 3da042021787..7df09ff38e63 100644 --- a/drivers/media/video/sn9c102/sn9c102_ov7630.c +++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera * | 2 | * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera * |
3 | * Controllers * | 3 | * Controllers * |
4 | * * | 4 | * * |
5 | * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | 5 | * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * |
6 | * * | 6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * | 7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * | 8 | * it under the terms of the GNU General Public License as published by * |
@@ -29,13 +29,17 @@ static int ov7630_init(struct sn9c102_device* cam) | |||
29 | { | 29 | { |
30 | int err = 0; | 30 | int err = 0; |
31 | 31 | ||
32 | switch (sn9c102_get_bridge(cam)) { | ||
33 | case BRIDGE_SN9C101: | ||
34 | case BRIDGE_SN9C102: | ||
32 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 35 | err += sn9c102_write_reg(cam, 0x00, 0x14); |
33 | err += sn9c102_write_reg(cam, 0x60, 0x17); | 36 | err += sn9c102_write_reg(cam, 0x60, 0x17); |
34 | err += sn9c102_write_reg(cam, 0x0f, 0x18); | 37 | err += sn9c102_write_reg(cam, 0x0f, 0x18); |
35 | err += sn9c102_write_reg(cam, 0x50, 0x19); | 38 | err += sn9c102_write_reg(cam, 0x50, 0x19); |
36 | 39 | ||
37 | err += sn9c102_i2c_write(cam, 0x12, 0x80); | 40 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); |
38 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | 41 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); |
42 | err += sn9c102_i2c_write(cam, 0x11, 0x00); | ||
39 | err += sn9c102_i2c_write(cam, 0x15, 0x34); | 43 | err += sn9c102_i2c_write(cam, 0x15, 0x34); |
40 | err += sn9c102_i2c_write(cam, 0x16, 0x03); | 44 | err += sn9c102_i2c_write(cam, 0x16, 0x03); |
41 | err += sn9c102_i2c_write(cam, 0x17, 0x1c); | 45 | err += sn9c102_i2c_write(cam, 0x17, 0x1c); |
@@ -43,14 +47,72 @@ static int ov7630_init(struct sn9c102_device* cam) | |||
43 | err += sn9c102_i2c_write(cam, 0x19, 0x06); | 47 | err += sn9c102_i2c_write(cam, 0x19, 0x06); |
44 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); | 48 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); |
45 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | 49 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); |
46 | err += sn9c102_i2c_write(cam, 0x20, 0xf6); | 50 | err += sn9c102_i2c_write(cam, 0x20, 0x44); |
51 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | ||
52 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | ||
53 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); | ||
54 | err += sn9c102_i2c_write(cam, 0x28, 0x20); | ||
55 | err += sn9c102_i2c_write(cam, 0x29, 0x30); | ||
56 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); | ||
57 | err += sn9c102_i2c_write(cam, 0x30, 0x24); | ||
58 | err += sn9c102_i2c_write(cam, 0x32, 0x86); | ||
59 | err += sn9c102_i2c_write(cam, 0x60, 0xa9); | ||
60 | err += sn9c102_i2c_write(cam, 0x61, 0x42); | ||
61 | err += sn9c102_i2c_write(cam, 0x65, 0x00); | ||
62 | err += sn9c102_i2c_write(cam, 0x69, 0x38); | ||
63 | err += sn9c102_i2c_write(cam, 0x6f, 0x88); | ||
64 | err += sn9c102_i2c_write(cam, 0x70, 0x0b); | ||
65 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | ||
66 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | ||
67 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | ||
68 | break; | ||
69 | case BRIDGE_SN9C103: | ||
70 | err += sn9c102_write_reg(cam, 0x00, 0x02); | ||
71 | err += sn9c102_write_reg(cam, 0x00, 0x03); | ||
72 | err += sn9c102_write_reg(cam, 0x1a, 0x04); | ||
73 | err += sn9c102_write_reg(cam, 0x20, 0x05); | ||
74 | err += sn9c102_write_reg(cam, 0x20, 0x06); | ||
75 | err += sn9c102_write_reg(cam, 0x20, 0x07); | ||
76 | err += sn9c102_write_reg(cam, 0x03, 0x10); | ||
77 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | ||
78 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
79 | err += sn9c102_write_reg(cam, 0x0f, 0x18); | ||
80 | err += sn9c102_write_reg(cam, 0x50, 0x19); | ||
81 | err += sn9c102_write_reg(cam, 0x1d, 0x1a); | ||
82 | err += sn9c102_write_reg(cam, 0x10, 0x1b); | ||
83 | err += sn9c102_write_reg(cam, 0x02, 0x1c); | ||
84 | err += sn9c102_write_reg(cam, 0x03, 0x1d); | ||
85 | err += sn9c102_write_reg(cam, 0x0f, 0x1e); | ||
86 | err += sn9c102_write_reg(cam, 0x0c, 0x1f); | ||
87 | err += sn9c102_write_reg(cam, 0x00, 0x20); | ||
88 | err += sn9c102_write_reg(cam, 0x10, 0x21); | ||
89 | err += sn9c102_write_reg(cam, 0x20, 0x22); | ||
90 | err += sn9c102_write_reg(cam, 0x30, 0x23); | ||
91 | err += sn9c102_write_reg(cam, 0x40, 0x24); | ||
92 | err += sn9c102_write_reg(cam, 0x50, 0x25); | ||
93 | err += sn9c102_write_reg(cam, 0x60, 0x26); | ||
94 | err += sn9c102_write_reg(cam, 0x70, 0x27); | ||
95 | err += sn9c102_write_reg(cam, 0x80, 0x28); | ||
96 | err += sn9c102_write_reg(cam, 0x90, 0x29); | ||
97 | err += sn9c102_write_reg(cam, 0xa0, 0x2a); | ||
98 | err += sn9c102_write_reg(cam, 0xb0, 0x2b); | ||
99 | err += sn9c102_write_reg(cam, 0xc0, 0x2c); | ||
100 | err += sn9c102_write_reg(cam, 0xd0, 0x2d); | ||
101 | err += sn9c102_write_reg(cam, 0xe0, 0x2e); | ||
102 | err += sn9c102_write_reg(cam, 0xf0, 0x2f); | ||
103 | err += sn9c102_write_reg(cam, 0xff, 0x30); | ||
104 | |||
105 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); | ||
106 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); | ||
107 | err += sn9c102_i2c_write(cam, 0x15, 0x34); | ||
108 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
109 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | ||
110 | err += sn9c102_i2c_write(cam, 0x20, 0x44); | ||
47 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | 111 | err += sn9c102_i2c_write(cam, 0x23, 0xee); |
48 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | 112 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); |
49 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); | 113 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); |
50 | err += sn9c102_i2c_write(cam, 0x28, 0xa0); | 114 | err += sn9c102_i2c_write(cam, 0x28, 0x20); |
51 | err += sn9c102_i2c_write(cam, 0x29, 0x30); | 115 | err += sn9c102_i2c_write(cam, 0x29, 0x30); |
52 | err += sn9c102_i2c_write(cam, 0x2a, 0xa0); | ||
53 | err += sn9c102_i2c_write(cam, 0x2b, 0x1f); | ||
54 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); | 116 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); |
55 | err += sn9c102_i2c_write(cam, 0x30, 0x24); | 117 | err += sn9c102_i2c_write(cam, 0x30, 0x24); |
56 | err += sn9c102_i2c_write(cam, 0x32, 0x86); | 118 | err += sn9c102_i2c_write(cam, 0x32, 0x86); |
@@ -63,45 +125,97 @@ static int ov7630_init(struct sn9c102_device* cam) | |||
63 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | 125 | err += sn9c102_i2c_write(cam, 0x71, 0x00); |
64 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | 126 | err += sn9c102_i2c_write(cam, 0x74, 0x21); |
65 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | 127 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); |
128 | break; | ||
129 | default: | ||
130 | break; | ||
131 | } | ||
66 | 132 | ||
67 | return err; | 133 | return err; |
68 | } | 134 | } |
69 | 135 | ||
70 | 136 | ||
71 | static int ov7630_set_ctrl(struct sn9c102_device* cam, | 137 | static int ov7630_get_ctrl(struct sn9c102_device* cam, |
72 | const struct v4l2_control* ctrl) | 138 | struct v4l2_control* ctrl) |
73 | { | 139 | { |
74 | int err = 0; | 140 | int err = 0; |
75 | 141 | ||
76 | switch (ctrl->id) { | 142 | switch (ctrl->id) { |
77 | case V4L2_CID_EXPOSURE: | 143 | case V4L2_CID_EXPOSURE: |
78 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2); | 144 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) |
79 | err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03); | 145 | return -EIO; |
80 | break; | 146 | break; |
81 | case V4L2_CID_RED_BALANCE: | 147 | case V4L2_CID_RED_BALANCE: |
82 | err += sn9c102_i2c_write(cam, 0x02, ctrl->value); | 148 | ctrl->value = sn9c102_pread_reg(cam, 0x07); |
83 | break; | 149 | break; |
84 | case V4L2_CID_BLUE_BALANCE: | 150 | case V4L2_CID_BLUE_BALANCE: |
85 | err += sn9c102_i2c_write(cam, 0x01, ctrl->value); | 151 | ctrl->value = sn9c102_pread_reg(cam, 0x06); |
152 | break; | ||
153 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
154 | ctrl->value = sn9c102_pread_reg(cam, 0x05); | ||
86 | break; | 155 | break; |
87 | case V4L2_CID_GAIN: | 156 | case V4L2_CID_GAIN: |
88 | err += sn9c102_i2c_write(cam, 0x00, ctrl->value); | 157 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0) |
158 | return -EIO; | ||
159 | ctrl->value &= 0x3f; | ||
160 | break; | ||
161 | case V4L2_CID_DO_WHITE_BALANCE: | ||
162 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) | ||
163 | return -EIO; | ||
164 | ctrl->value &= 0x3f; | ||
165 | break; | ||
166 | case V4L2_CID_WHITENESS: | ||
167 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0) | ||
168 | return -EIO; | ||
169 | ctrl->value &= 0x3f; | ||
170 | break; | ||
171 | case V4L2_CID_AUTOGAIN: | ||
172 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0) | ||
173 | return -EIO; | ||
174 | ctrl->value &= 0x01; | ||
175 | break; | ||
176 | case V4L2_CID_VFLIP: | ||
177 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0) | ||
178 | return -EIO; | ||
179 | ctrl->value = (ctrl->value & 0x80) ? 1 : 0; | ||
180 | break; | ||
181 | case SN9C102_V4L2_CID_GAMMA: | ||
182 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0) | ||
183 | return -EIO; | ||
184 | ctrl->value = (ctrl->value & 0x02) ? 1 : 0; | ||
185 | break; | ||
186 | case SN9C102_V4L2_CID_BAND_FILTER: | ||
187 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0) | ||
188 | return -EIO; | ||
189 | ctrl->value = (ctrl->value & 0x02) ? 1 : 0; | ||
190 | break; | ||
191 | default: | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | return err ? -EIO : 0; | ||
196 | } | ||
197 | |||
198 | |||
199 | static int ov7630_set_ctrl(struct sn9c102_device* cam, | ||
200 | const struct v4l2_control* ctrl) | ||
201 | { | ||
202 | int err = 0; | ||
203 | |||
204 | switch (ctrl->id) { | ||
205 | case V4L2_CID_EXPOSURE: | ||
206 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value); | ||
89 | break; | 207 | break; |
90 | case V4L2_CID_CONTRAST: | 208 | case V4L2_CID_RED_BALANCE: |
91 | err += ctrl->value ? sn9c102_i2c_write(cam, 0x05, | 209 | err += sn9c102_write_reg(cam, ctrl->value, 0x07); |
92 | (ctrl->value-1) | 0x20) | ||
93 | : sn9c102_i2c_write(cam, 0x05, 0x00); | ||
94 | break; | 210 | break; |
95 | case V4L2_CID_BRIGHTNESS: | 211 | case V4L2_CID_BLUE_BALANCE: |
96 | err += sn9c102_i2c_write(cam, 0x06, ctrl->value); | 212 | err += sn9c102_write_reg(cam, ctrl->value, 0x06); |
97 | break; | 213 | break; |
98 | case V4L2_CID_SATURATION: | 214 | case SN9C102_V4L2_CID_GREEN_BALANCE: |
99 | err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4); | 215 | err += sn9c102_write_reg(cam, ctrl->value, 0x05); |
100 | break; | 216 | break; |
101 | case V4L2_CID_HUE: | 217 | case V4L2_CID_GAIN: |
102 | err += ctrl->value ? sn9c102_i2c_write(cam, 0x04, | 218 | err += sn9c102_i2c_write(cam, 0x00, ctrl->value); |
103 | (ctrl->value-1) | 0x20) | ||
104 | : sn9c102_i2c_write(cam, 0x04, 0x00); | ||
105 | break; | 219 | break; |
106 | case V4L2_CID_DO_WHITE_BALANCE: | 220 | case V4L2_CID_DO_WHITE_BALANCE: |
107 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | 221 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); |
@@ -109,23 +223,15 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam, | |||
109 | case V4L2_CID_WHITENESS: | 223 | case V4L2_CID_WHITENESS: |
110 | err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); | 224 | err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); |
111 | break; | 225 | break; |
112 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
113 | err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78); | ||
114 | break; | ||
115 | case V4L2_CID_AUTOGAIN: | 226 | case V4L2_CID_AUTOGAIN: |
116 | err += sn9c102_i2c_write(cam, 0x13, ctrl->value); | 227 | err += sn9c102_i2c_write(cam, 0x13, ctrl->value | |
228 | (ctrl->value << 1)); | ||
117 | break; | 229 | break; |
118 | case V4L2_CID_VFLIP: | 230 | case V4L2_CID_VFLIP: |
119 | err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); | 231 | err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); |
120 | break; | 232 | break; |
121 | case V4L2_CID_BLACK_LEVEL: | ||
122 | err += sn9c102_i2c_write(cam, 0x25, ctrl->value); | ||
123 | break; | ||
124 | case SN9C102_V4L2_CID_BRIGHT_LEVEL: | ||
125 | err += sn9c102_i2c_write(cam, 0x24, ctrl->value); | ||
126 | break; | ||
127 | case SN9C102_V4L2_CID_GAMMA: | 233 | case SN9C102_V4L2_CID_GAMMA: |
128 | err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80); | 234 | err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2); |
129 | break; | 235 | break; |
130 | case SN9C102_V4L2_CID_BAND_FILTER: | 236 | case SN9C102_V4L2_CID_BAND_FILTER: |
131 | err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); | 237 | err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); |
@@ -141,10 +247,12 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam, | |||
141 | static int ov7630_set_crop(struct sn9c102_device* cam, | 247 | static int ov7630_set_crop(struct sn9c102_device* cam, |
142 | const struct v4l2_rect* rect) | 248 | const struct v4l2_rect* rect) |
143 | { | 249 | { |
144 | struct sn9c102_sensor* s = &ov7630; | 250 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); |
145 | int err = 0; | 251 | int err = 0; |
146 | u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | 252 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, |
253 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
147 | 254 | ||
255 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
148 | err += sn9c102_write_reg(cam, v_start, 0x13); | 256 | err += sn9c102_write_reg(cam, v_start, 0x13); |
149 | 257 | ||
150 | return err; | 258 | return err; |
@@ -168,7 +276,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam, | |||
168 | static struct sn9c102_sensor ov7630 = { | 276 | static struct sn9c102_sensor ov7630 = { |
169 | .name = "OV7630", | 277 | .name = "OV7630", |
170 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 278 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
171 | .sysfs_ops = SN9C102_I2C_WRITE, | 279 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, |
280 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
172 | .frequency = SN9C102_I2C_100KHZ, | 281 | .frequency = SN9C102_I2C_100KHZ, |
173 | .interface = SN9C102_I2C_2WIRES, | 282 | .interface = SN9C102_I2C_2WIRES, |
174 | .i2c_slave_id = 0x21, | 283 | .i2c_slave_id = 0x21, |
@@ -185,73 +294,23 @@ static struct sn9c102_sensor ov7630 = { | |||
185 | .flags = 0, | 294 | .flags = 0, |
186 | }, | 295 | }, |
187 | { | 296 | { |
188 | .id = V4L2_CID_HUE, | ||
189 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
190 | .name = "hue", | ||
191 | .minimum = 0x00, | ||
192 | .maximum = 0x1f+1, | ||
193 | .step = 0x01, | ||
194 | .default_value = 0x00, | ||
195 | .flags = 0, | ||
196 | }, | ||
197 | { | ||
198 | .id = V4L2_CID_SATURATION, | ||
199 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
200 | .name = "saturation", | ||
201 | .minimum = 0x00, | ||
202 | .maximum = 0x0f, | ||
203 | .step = 0x01, | ||
204 | .default_value = 0x08, | ||
205 | .flags = 0, | ||
206 | }, | ||
207 | { | ||
208 | .id = V4L2_CID_CONTRAST, | ||
209 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
210 | .name = "contrast", | ||
211 | .minimum = 0x00, | ||
212 | .maximum = 0x1f+1, | ||
213 | .step = 0x01, | ||
214 | .default_value = 0x00, | ||
215 | .flags = 0, | ||
216 | }, | ||
217 | { | ||
218 | .id = V4L2_CID_EXPOSURE, | 297 | .id = V4L2_CID_EXPOSURE, |
219 | .type = V4L2_CTRL_TYPE_INTEGER, | 298 | .type = V4L2_CTRL_TYPE_INTEGER, |
220 | .name = "exposure", | 299 | .name = "exposure", |
221 | .minimum = 0x000, | ||
222 | .maximum = 0x3ff, | ||
223 | .step = 0x001, | ||
224 | .default_value = 0x83<<2, | ||
225 | .flags = 0, | ||
226 | }, | ||
227 | { | ||
228 | .id = V4L2_CID_RED_BALANCE, | ||
229 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
230 | .name = "red balance", | ||
231 | .minimum = 0x00, | ||
232 | .maximum = 0xff, | ||
233 | .step = 0x01, | ||
234 | .default_value = 0x3a, | ||
235 | .flags = 0, | ||
236 | }, | ||
237 | { | ||
238 | .id = V4L2_CID_BLUE_BALANCE, | ||
239 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
240 | .name = "blue balance", | ||
241 | .minimum = 0x00, | 300 | .minimum = 0x00, |
242 | .maximum = 0xff, | 301 | .maximum = 0xff, |
243 | .step = 0x01, | 302 | .step = 0x01, |
244 | .default_value = 0x77, | 303 | .default_value = 0x60, |
245 | .flags = 0, | 304 | .flags = 0, |
246 | }, | 305 | }, |
247 | { | 306 | { |
248 | .id = V4L2_CID_BRIGHTNESS, | 307 | .id = V4L2_CID_WHITENESS, |
249 | .type = V4L2_CTRL_TYPE_INTEGER, | 308 | .type = V4L2_CTRL_TYPE_INTEGER, |
250 | .name = "brightness", | 309 | .name = "white balance background: red", |
251 | .minimum = 0x00, | 310 | .minimum = 0x00, |
252 | .maximum = 0xff, | 311 | .maximum = 0x3f, |
253 | .step = 0x01, | 312 | .step = 0x01, |
254 | .default_value = 0xa0, | 313 | .default_value = 0x20, |
255 | .flags = 0, | 314 | .flags = 0, |
256 | }, | 315 | }, |
257 | { | 316 | { |
@@ -265,31 +324,31 @@ static struct sn9c102_sensor ov7630 = { | |||
265 | .flags = 0, | 324 | .flags = 0, |
266 | }, | 325 | }, |
267 | { | 326 | { |
268 | .id = V4L2_CID_WHITENESS, | 327 | .id = V4L2_CID_RED_BALANCE, |
269 | .type = V4L2_CTRL_TYPE_INTEGER, | 328 | .type = V4L2_CTRL_TYPE_INTEGER, |
270 | .name = "white balance background: red", | 329 | .name = "red balance", |
271 | .minimum = 0x00, | 330 | .minimum = 0x00, |
272 | .maximum = 0x3f, | 331 | .maximum = 0x7f, |
273 | .step = 0x01, | 332 | .step = 0x01, |
274 | .default_value = 0x20, | 333 | .default_value = 0x20, |
275 | .flags = 0, | 334 | .flags = 0, |
276 | }, | 335 | }, |
277 | { | 336 | { |
278 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | 337 | .id = V4L2_CID_BLUE_BALANCE, |
279 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 338 | .type = V4L2_CTRL_TYPE_INTEGER, |
280 | .name = "auto white balance", | 339 | .name = "blue balance", |
281 | .minimum = 0x00, | 340 | .minimum = 0x00, |
282 | .maximum = 0x01, | 341 | .maximum = 0x7f, |
283 | .step = 0x01, | 342 | .step = 0x01, |
284 | .default_value = 0x01, | 343 | .default_value = 0x20, |
285 | .flags = 0, | 344 | .flags = 0, |
286 | }, | 345 | }, |
287 | { | 346 | { |
288 | .id = V4L2_CID_AUTOGAIN, | 347 | .id = V4L2_CID_AUTOGAIN, |
289 | .type = V4L2_CTRL_TYPE_INTEGER, | 348 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
290 | .name = "gain & exposure mode", | 349 | .name = "auto adjust", |
291 | .minimum = 0x00, | 350 | .minimum = 0x00, |
292 | .maximum = 0x03, | 351 | .maximum = 0x01, |
293 | .step = 0x01, | 352 | .step = 0x01, |
294 | .default_value = 0x00, | 353 | .default_value = 0x00, |
295 | .flags = 0, | 354 | .flags = 0, |
@@ -305,23 +364,13 @@ static struct sn9c102_sensor ov7630 = { | |||
305 | .flags = 0, | 364 | .flags = 0, |
306 | }, | 365 | }, |
307 | { | 366 | { |
308 | .id = V4L2_CID_BLACK_LEVEL, | 367 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, |
309 | .type = V4L2_CTRL_TYPE_INTEGER, | 368 | .type = V4L2_CTRL_TYPE_INTEGER, |
310 | .name = "black pixel ratio", | 369 | .name = "green balance", |
311 | .minimum = 0x01, | 370 | .minimum = 0x00, |
312 | .maximum = 0x9a, | 371 | .maximum = 0x7f, |
313 | .step = 0x01, | ||
314 | .default_value = 0x8a, | ||
315 | .flags = 0, | ||
316 | }, | ||
317 | { | ||
318 | .id = SN9C102_V4L2_CID_BRIGHT_LEVEL, | ||
319 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
320 | .name = "bright pixel ratio", | ||
321 | .minimum = 0x01, | ||
322 | .maximum = 0x9a, | ||
323 | .step = 0x01, | 372 | .step = 0x01, |
324 | .default_value = 0x10, | 373 | .default_value = 0x20, |
325 | .flags = 0, | 374 | .flags = 0, |
326 | }, | 375 | }, |
327 | { | 376 | { |
@@ -345,6 +394,7 @@ static struct sn9c102_sensor ov7630 = { | |||
345 | .flags = 0, | 394 | .flags = 0, |
346 | }, | 395 | }, |
347 | }, | 396 | }, |
397 | .get_ctrl = &ov7630_get_ctrl, | ||
348 | .set_ctrl = &ov7630_set_ctrl, | 398 | .set_ctrl = &ov7630_set_ctrl, |
349 | .cropcap = { | 399 | .cropcap = { |
350 | .bounds = { | 400 | .bounds = { |
@@ -364,7 +414,7 @@ static struct sn9c102_sensor ov7630 = { | |||
364 | .pix_format = { | 414 | .pix_format = { |
365 | .width = 640, | 415 | .width = 640, |
366 | .height = 480, | 416 | .height = 480, |
367 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | 417 | .pixelformat = V4L2_PIX_FMT_SN9C10X, |
368 | .priv = 8, | 418 | .priv = 8, |
369 | }, | 419 | }, |
370 | .set_pix_format = &ov7630_set_pix_format | 420 | .set_pix_format = &ov7630_set_pix_format |
@@ -373,28 +423,36 @@ static struct sn9c102_sensor ov7630 = { | |||
373 | 423 | ||
374 | int sn9c102_probe_ov7630(struct sn9c102_device* cam) | 424 | int sn9c102_probe_ov7630(struct sn9c102_device* cam) |
375 | { | 425 | { |
376 | const struct usb_device_id ov7630_id_table[] = { | 426 | int pid, ver, err = 0; |
377 | { USB_DEVICE(0x0c45, 0x602c), }, | ||
378 | { USB_DEVICE(0x0c45, 0x602d), }, | ||
379 | { USB_DEVICE(0x0c45, 0x608f), }, | ||
380 | { USB_DEVICE(0x0c45, 0x60b0), }, | ||
381 | { } | ||
382 | }; | ||
383 | int err = 0; | ||
384 | |||
385 | if (!sn9c102_match_id(cam, ov7630_id_table)) | ||
386 | return -ENODEV; | ||
387 | 427 | ||
428 | switch (sn9c102_get_bridge(cam)) { | ||
429 | case BRIDGE_SN9C101: | ||
430 | case BRIDGE_SN9C102: | ||
388 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 431 | err += sn9c102_write_reg(cam, 0x01, 0x01); |
389 | err += sn9c102_write_reg(cam, 0x00, 0x01); | 432 | err += sn9c102_write_reg(cam, 0x00, 0x01); |
390 | err += sn9c102_write_reg(cam, 0x28, 0x17); | 433 | err += sn9c102_write_reg(cam, 0x28, 0x17); |
391 | if (err) | 434 | break; |
392 | return -EIO; | 435 | case BRIDGE_SN9C103: /* do _not_ change anything! */ |
436 | err += sn9c102_write_reg(cam, 0x09, 0x01); | ||
437 | err += sn9c102_write_reg(cam, 0x42, 0x01); | ||
438 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
439 | err += sn9c102_write_reg(cam, 0x44, 0x02); | ||
440 | pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); | ||
441 | if (err || pid < 0) { /* try a different initialization */ | ||
442 | err = sn9c102_write_reg(cam, 0x01, 0x01); | ||
443 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
444 | } | ||
445 | break; | ||
446 | default: | ||
447 | break; | ||
448 | } | ||
393 | 449 | ||
394 | err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0); | 450 | pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); |
395 | if (err) | 451 | ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b); |
452 | if (err || pid < 0 || ver < 0) | ||
453 | return -EIO; | ||
454 | if (pid != 0x76 || ver != 0x31) | ||
396 | return -ENODEV; | 455 | return -ENODEV; |
397 | |||
398 | sn9c102_attach_sensor(cam, &ov7630); | 456 | sn9c102_attach_sensor(cam, &ov7630); |
399 | 457 | ||
400 | return 0; | 458 | return 0; |
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c new file mode 100644 index 000000000000..d670c24d4435 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c | |||
@@ -0,0 +1,592 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static struct sn9c102_sensor ov7660; | ||
26 | |||
27 | |||
28 | static int ov7660_init(struct sn9c102_device* cam) | ||
29 | { | ||
30 | int err = 0; | ||
31 | |||
32 | err += sn9c102_write_reg(cam, 0x40, 0x02); | ||
33 | err += sn9c102_write_reg(cam, 0x00, 0x03); | ||
34 | err += sn9c102_write_reg(cam, 0x1a, 0x04); | ||
35 | err += sn9c102_write_reg(cam, 0x03, 0x10); | ||
36 | err += sn9c102_write_reg(cam, 0x08, 0x14); | ||
37 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
38 | err += sn9c102_write_reg(cam, 0x8b, 0x18); | ||
39 | err += sn9c102_write_reg(cam, 0x00, 0x19); | ||
40 | err += sn9c102_write_reg(cam, 0x1d, 0x1a); | ||
41 | err += sn9c102_write_reg(cam, 0x10, 0x1b); | ||
42 | err += sn9c102_write_reg(cam, 0x02, 0x1c); | ||
43 | err += sn9c102_write_reg(cam, 0x03, 0x1d); | ||
44 | err += sn9c102_write_reg(cam, 0x0f, 0x1e); | ||
45 | err += sn9c102_write_reg(cam, 0x0c, 0x1f); | ||
46 | err += sn9c102_write_reg(cam, 0x00, 0x20); | ||
47 | err += sn9c102_write_reg(cam, 0x29, 0x21); | ||
48 | err += sn9c102_write_reg(cam, 0x40, 0x22); | ||
49 | err += sn9c102_write_reg(cam, 0x54, 0x23); | ||
50 | err += sn9c102_write_reg(cam, 0x66, 0x24); | ||
51 | err += sn9c102_write_reg(cam, 0x76, 0x25); | ||
52 | err += sn9c102_write_reg(cam, 0x85, 0x26); | ||
53 | err += sn9c102_write_reg(cam, 0x94, 0x27); | ||
54 | err += sn9c102_write_reg(cam, 0xa1, 0x28); | ||
55 | err += sn9c102_write_reg(cam, 0xae, 0x29); | ||
56 | err += sn9c102_write_reg(cam, 0xbb, 0x2a); | ||
57 | err += sn9c102_write_reg(cam, 0xc7, 0x2b); | ||
58 | err += sn9c102_write_reg(cam, 0xd3, 0x2c); | ||
59 | err += sn9c102_write_reg(cam, 0xde, 0x2d); | ||
60 | err += sn9c102_write_reg(cam, 0xea, 0x2e); | ||
61 | err += sn9c102_write_reg(cam, 0xf4, 0x2f); | ||
62 | err += sn9c102_write_reg(cam, 0xff, 0x30); | ||
63 | err += sn9c102_write_reg(cam, 0x00, 0x3F); | ||
64 | err += sn9c102_write_reg(cam, 0xC7, 0x40); | ||
65 | err += sn9c102_write_reg(cam, 0x01, 0x41); | ||
66 | err += sn9c102_write_reg(cam, 0x44, 0x42); | ||
67 | err += sn9c102_write_reg(cam, 0x00, 0x43); | ||
68 | err += sn9c102_write_reg(cam, 0x44, 0x44); | ||
69 | err += sn9c102_write_reg(cam, 0x00, 0x45); | ||
70 | err += sn9c102_write_reg(cam, 0x44, 0x46); | ||
71 | err += sn9c102_write_reg(cam, 0x00, 0x47); | ||
72 | err += sn9c102_write_reg(cam, 0xC7, 0x48); | ||
73 | err += sn9c102_write_reg(cam, 0x01, 0x49); | ||
74 | err += sn9c102_write_reg(cam, 0xC7, 0x4A); | ||
75 | err += sn9c102_write_reg(cam, 0x01, 0x4B); | ||
76 | err += sn9c102_write_reg(cam, 0xC7, 0x4C); | ||
77 | err += sn9c102_write_reg(cam, 0x01, 0x4D); | ||
78 | err += sn9c102_write_reg(cam, 0x44, 0x4E); | ||
79 | err += sn9c102_write_reg(cam, 0x00, 0x4F); | ||
80 | err += sn9c102_write_reg(cam, 0x44, 0x50); | ||
81 | err += sn9c102_write_reg(cam, 0x00, 0x51); | ||
82 | err += sn9c102_write_reg(cam, 0x44, 0x52); | ||
83 | err += sn9c102_write_reg(cam, 0x00, 0x53); | ||
84 | err += sn9c102_write_reg(cam, 0xC7, 0x54); | ||
85 | err += sn9c102_write_reg(cam, 0x01, 0x55); | ||
86 | err += sn9c102_write_reg(cam, 0xC7, 0x56); | ||
87 | err += sn9c102_write_reg(cam, 0x01, 0x57); | ||
88 | err += sn9c102_write_reg(cam, 0xC7, 0x58); | ||
89 | err += sn9c102_write_reg(cam, 0x01, 0x59); | ||
90 | err += sn9c102_write_reg(cam, 0x44, 0x5A); | ||
91 | err += sn9c102_write_reg(cam, 0x00, 0x5B); | ||
92 | err += sn9c102_write_reg(cam, 0x44, 0x5C); | ||
93 | err += sn9c102_write_reg(cam, 0x00, 0x5D); | ||
94 | err += sn9c102_write_reg(cam, 0x44, 0x5E); | ||
95 | err += sn9c102_write_reg(cam, 0x00, 0x5F); | ||
96 | err += sn9c102_write_reg(cam, 0xC7, 0x60); | ||
97 | err += sn9c102_write_reg(cam, 0x01, 0x61); | ||
98 | err += sn9c102_write_reg(cam, 0xC7, 0x62); | ||
99 | err += sn9c102_write_reg(cam, 0x01, 0x63); | ||
100 | err += sn9c102_write_reg(cam, 0xC7, 0x64); | ||
101 | err += sn9c102_write_reg(cam, 0x01, 0x65); | ||
102 | err += sn9c102_write_reg(cam, 0x44, 0x66); | ||
103 | err += sn9c102_write_reg(cam, 0x00, 0x67); | ||
104 | err += sn9c102_write_reg(cam, 0x44, 0x68); | ||
105 | err += sn9c102_write_reg(cam, 0x00, 0x69); | ||
106 | err += sn9c102_write_reg(cam, 0x44, 0x6A); | ||
107 | err += sn9c102_write_reg(cam, 0x00, 0x6B); | ||
108 | err += sn9c102_write_reg(cam, 0xC7, 0x6C); | ||
109 | err += sn9c102_write_reg(cam, 0x01, 0x6D); | ||
110 | err += sn9c102_write_reg(cam, 0xC7, 0x6E); | ||
111 | err += sn9c102_write_reg(cam, 0x01, 0x6F); | ||
112 | err += sn9c102_write_reg(cam, 0xC7, 0x70); | ||
113 | err += sn9c102_write_reg(cam, 0x01, 0x71); | ||
114 | err += sn9c102_write_reg(cam, 0x44, 0x72); | ||
115 | err += sn9c102_write_reg(cam, 0x00, 0x73); | ||
116 | err += sn9c102_write_reg(cam, 0x44, 0x74); | ||
117 | err += sn9c102_write_reg(cam, 0x00, 0x75); | ||
118 | err += sn9c102_write_reg(cam, 0x44, 0x76); | ||
119 | err += sn9c102_write_reg(cam, 0x00, 0x77); | ||
120 | err += sn9c102_write_reg(cam, 0xC7, 0x78); | ||
121 | err += sn9c102_write_reg(cam, 0x01, 0x79); | ||
122 | err += sn9c102_write_reg(cam, 0xC7, 0x7A); | ||
123 | err += sn9c102_write_reg(cam, 0x01, 0x7B); | ||
124 | err += sn9c102_write_reg(cam, 0xC7, 0x7C); | ||
125 | err += sn9c102_write_reg(cam, 0x01, 0x7D); | ||
126 | err += sn9c102_write_reg(cam, 0x44, 0x7E); | ||
127 | err += sn9c102_write_reg(cam, 0x00, 0x7F); | ||
128 | err += sn9c102_write_reg(cam, 0x14, 0x84); | ||
129 | err += sn9c102_write_reg(cam, 0x00, 0x85); | ||
130 | err += sn9c102_write_reg(cam, 0x27, 0x86); | ||
131 | err += sn9c102_write_reg(cam, 0x00, 0x87); | ||
132 | err += sn9c102_write_reg(cam, 0x07, 0x88); | ||
133 | err += sn9c102_write_reg(cam, 0x00, 0x89); | ||
134 | err += sn9c102_write_reg(cam, 0xEC, 0x8A); | ||
135 | err += sn9c102_write_reg(cam, 0x0f, 0x8B); | ||
136 | err += sn9c102_write_reg(cam, 0xD8, 0x8C); | ||
137 | err += sn9c102_write_reg(cam, 0x0f, 0x8D); | ||
138 | err += sn9c102_write_reg(cam, 0x3D, 0x8E); | ||
139 | err += sn9c102_write_reg(cam, 0x00, 0x8F); | ||
140 | err += sn9c102_write_reg(cam, 0x3D, 0x90); | ||
141 | err += sn9c102_write_reg(cam, 0x00, 0x91); | ||
142 | err += sn9c102_write_reg(cam, 0xCD, 0x92); | ||
143 | err += sn9c102_write_reg(cam, 0x0f, 0x93); | ||
144 | err += sn9c102_write_reg(cam, 0xf7, 0x94); | ||
145 | err += sn9c102_write_reg(cam, 0x0f, 0x95); | ||
146 | err += sn9c102_write_reg(cam, 0x0C, 0x96); | ||
147 | err += sn9c102_write_reg(cam, 0x00, 0x97); | ||
148 | err += sn9c102_write_reg(cam, 0x00, 0x98); | ||
149 | err += sn9c102_write_reg(cam, 0x66, 0x99); | ||
150 | err += sn9c102_write_reg(cam, 0x05, 0x9A); | ||
151 | err += sn9c102_write_reg(cam, 0x00, 0x9B); | ||
152 | err += sn9c102_write_reg(cam, 0x04, 0x9C); | ||
153 | err += sn9c102_write_reg(cam, 0x00, 0x9D); | ||
154 | err += sn9c102_write_reg(cam, 0x08, 0x9E); | ||
155 | err += sn9c102_write_reg(cam, 0x00, 0x9F); | ||
156 | err += sn9c102_write_reg(cam, 0x2D, 0xC0); | ||
157 | err += sn9c102_write_reg(cam, 0x2D, 0xC1); | ||
158 | err += sn9c102_write_reg(cam, 0x3A, 0xC2); | ||
159 | err += sn9c102_write_reg(cam, 0x05, 0xC3); | ||
160 | err += sn9c102_write_reg(cam, 0x04, 0xC4); | ||
161 | err += sn9c102_write_reg(cam, 0x3F, 0xC5); | ||
162 | err += sn9c102_write_reg(cam, 0x00, 0xC6); | ||
163 | err += sn9c102_write_reg(cam, 0x00, 0xC7); | ||
164 | err += sn9c102_write_reg(cam, 0x50, 0xC8); | ||
165 | err += sn9c102_write_reg(cam, 0x3C, 0xC9); | ||
166 | err += sn9c102_write_reg(cam, 0x28, 0xCA); | ||
167 | err += sn9c102_write_reg(cam, 0xD8, 0xCB); | ||
168 | err += sn9c102_write_reg(cam, 0x14, 0xCC); | ||
169 | err += sn9c102_write_reg(cam, 0xEC, 0xCD); | ||
170 | err += sn9c102_write_reg(cam, 0x32, 0xCE); | ||
171 | err += sn9c102_write_reg(cam, 0xDD, 0xCF); | ||
172 | err += sn9c102_write_reg(cam, 0x32, 0xD0); | ||
173 | err += sn9c102_write_reg(cam, 0xDD, 0xD1); | ||
174 | err += sn9c102_write_reg(cam, 0x6A, 0xD2); | ||
175 | err += sn9c102_write_reg(cam, 0x50, 0xD3); | ||
176 | err += sn9c102_write_reg(cam, 0x00, 0xD4); | ||
177 | err += sn9c102_write_reg(cam, 0x00, 0xD5); | ||
178 | err += sn9c102_write_reg(cam, 0x00, 0xD6); | ||
179 | |||
180 | err += sn9c102_i2c_write(cam, 0x12, 0x80); | ||
181 | err += sn9c102_i2c_write(cam, 0x11, 0x09); | ||
182 | err += sn9c102_i2c_write(cam, 0x00, 0x0A); | ||
183 | err += sn9c102_i2c_write(cam, 0x01, 0x78); | ||
184 | err += sn9c102_i2c_write(cam, 0x02, 0x90); | ||
185 | err += sn9c102_i2c_write(cam, 0x03, 0x00); | ||
186 | err += sn9c102_i2c_write(cam, 0x04, 0x00); | ||
187 | err += sn9c102_i2c_write(cam, 0x05, 0x08); | ||
188 | err += sn9c102_i2c_write(cam, 0x06, 0x0B); | ||
189 | err += sn9c102_i2c_write(cam, 0x07, 0x00); | ||
190 | err += sn9c102_i2c_write(cam, 0x08, 0x1C); | ||
191 | err += sn9c102_i2c_write(cam, 0x09, 0x01); | ||
192 | err += sn9c102_i2c_write(cam, 0x0A, 0x76); | ||
193 | err += sn9c102_i2c_write(cam, 0x0B, 0x60); | ||
194 | err += sn9c102_i2c_write(cam, 0x0C, 0x00); | ||
195 | err += sn9c102_i2c_write(cam, 0x0D, 0x08); | ||
196 | err += sn9c102_i2c_write(cam, 0x0E, 0x04); | ||
197 | err += sn9c102_i2c_write(cam, 0x0F, 0x6F); | ||
198 | err += sn9c102_i2c_write(cam, 0x10, 0x20); | ||
199 | err += sn9c102_i2c_write(cam, 0x11, 0x03); | ||
200 | err += sn9c102_i2c_write(cam, 0x12, 0x05); | ||
201 | err += sn9c102_i2c_write(cam, 0x13, 0xF8); | ||
202 | err += sn9c102_i2c_write(cam, 0x14, 0x2C); | ||
203 | err += sn9c102_i2c_write(cam, 0x15, 0x00); | ||
204 | err += sn9c102_i2c_write(cam, 0x16, 0x02); | ||
205 | err += sn9c102_i2c_write(cam, 0x17, 0x10); | ||
206 | err += sn9c102_i2c_write(cam, 0x18, 0x60); | ||
207 | err += sn9c102_i2c_write(cam, 0x19, 0x02); | ||
208 | err += sn9c102_i2c_write(cam, 0x1A, 0x7B); | ||
209 | err += sn9c102_i2c_write(cam, 0x1B, 0x02); | ||
210 | err += sn9c102_i2c_write(cam, 0x1C, 0x7F); | ||
211 | err += sn9c102_i2c_write(cam, 0x1D, 0xA2); | ||
212 | err += sn9c102_i2c_write(cam, 0x1E, 0x01); | ||
213 | err += sn9c102_i2c_write(cam, 0x1F, 0x0E); | ||
214 | err += sn9c102_i2c_write(cam, 0x20, 0x05); | ||
215 | err += sn9c102_i2c_write(cam, 0x21, 0x05); | ||
216 | err += sn9c102_i2c_write(cam, 0x22, 0x05); | ||
217 | err += sn9c102_i2c_write(cam, 0x23, 0x05); | ||
218 | err += sn9c102_i2c_write(cam, 0x24, 0x68); | ||
219 | err += sn9c102_i2c_write(cam, 0x25, 0x58); | ||
220 | err += sn9c102_i2c_write(cam, 0x26, 0xD4); | ||
221 | err += sn9c102_i2c_write(cam, 0x27, 0x80); | ||
222 | err += sn9c102_i2c_write(cam, 0x28, 0x80); | ||
223 | err += sn9c102_i2c_write(cam, 0x29, 0x30); | ||
224 | err += sn9c102_i2c_write(cam, 0x2A, 0x00); | ||
225 | err += sn9c102_i2c_write(cam, 0x2B, 0x00); | ||
226 | err += sn9c102_i2c_write(cam, 0x2C, 0x80); | ||
227 | err += sn9c102_i2c_write(cam, 0x2D, 0x00); | ||
228 | err += sn9c102_i2c_write(cam, 0x2E, 0x00); | ||
229 | err += sn9c102_i2c_write(cam, 0x2F, 0x0E); | ||
230 | err += sn9c102_i2c_write(cam, 0x30, 0x08); | ||
231 | err += sn9c102_i2c_write(cam, 0x31, 0x30); | ||
232 | err += sn9c102_i2c_write(cam, 0x32, 0xB4); | ||
233 | err += sn9c102_i2c_write(cam, 0x33, 0x00); | ||
234 | err += sn9c102_i2c_write(cam, 0x34, 0x07); | ||
235 | err += sn9c102_i2c_write(cam, 0x35, 0x84); | ||
236 | err += sn9c102_i2c_write(cam, 0x36, 0x00); | ||
237 | err += sn9c102_i2c_write(cam, 0x37, 0x0C); | ||
238 | err += sn9c102_i2c_write(cam, 0x38, 0x02); | ||
239 | err += sn9c102_i2c_write(cam, 0x39, 0x43); | ||
240 | err += sn9c102_i2c_write(cam, 0x3A, 0x00); | ||
241 | err += sn9c102_i2c_write(cam, 0x3B, 0x02); | ||
242 | err += sn9c102_i2c_write(cam, 0x3C, 0x6C); | ||
243 | err += sn9c102_i2c_write(cam, 0x3D, 0x99); | ||
244 | err += sn9c102_i2c_write(cam, 0x3E, 0x0E); | ||
245 | err += sn9c102_i2c_write(cam, 0x3F, 0x41); | ||
246 | err += sn9c102_i2c_write(cam, 0x40, 0xC1); | ||
247 | err += sn9c102_i2c_write(cam, 0x41, 0x22); | ||
248 | err += sn9c102_i2c_write(cam, 0x42, 0x08); | ||
249 | err += sn9c102_i2c_write(cam, 0x43, 0xF0); | ||
250 | err += sn9c102_i2c_write(cam, 0x44, 0x10); | ||
251 | err += sn9c102_i2c_write(cam, 0x45, 0x78); | ||
252 | err += sn9c102_i2c_write(cam, 0x46, 0xA8); | ||
253 | err += sn9c102_i2c_write(cam, 0x47, 0x60); | ||
254 | err += sn9c102_i2c_write(cam, 0x48, 0x80); | ||
255 | err += sn9c102_i2c_write(cam, 0x49, 0x00); | ||
256 | err += sn9c102_i2c_write(cam, 0x4A, 0x00); | ||
257 | err += sn9c102_i2c_write(cam, 0x4B, 0x00); | ||
258 | err += sn9c102_i2c_write(cam, 0x4C, 0x00); | ||
259 | err += sn9c102_i2c_write(cam, 0x4D, 0x00); | ||
260 | err += sn9c102_i2c_write(cam, 0x4E, 0x00); | ||
261 | err += sn9c102_i2c_write(cam, 0x4F, 0x46); | ||
262 | err += sn9c102_i2c_write(cam, 0x50, 0x36); | ||
263 | err += sn9c102_i2c_write(cam, 0x51, 0x0F); | ||
264 | err += sn9c102_i2c_write(cam, 0x52, 0x17); | ||
265 | err += sn9c102_i2c_write(cam, 0x53, 0x7F); | ||
266 | err += sn9c102_i2c_write(cam, 0x54, 0x96); | ||
267 | err += sn9c102_i2c_write(cam, 0x55, 0x40); | ||
268 | err += sn9c102_i2c_write(cam, 0x56, 0x40); | ||
269 | err += sn9c102_i2c_write(cam, 0x57, 0x40); | ||
270 | err += sn9c102_i2c_write(cam, 0x58, 0x0F); | ||
271 | err += sn9c102_i2c_write(cam, 0x59, 0xBA); | ||
272 | err += sn9c102_i2c_write(cam, 0x5A, 0x9A); | ||
273 | err += sn9c102_i2c_write(cam, 0x5B, 0x22); | ||
274 | err += sn9c102_i2c_write(cam, 0x5C, 0xB9); | ||
275 | err += sn9c102_i2c_write(cam, 0x5D, 0x9B); | ||
276 | err += sn9c102_i2c_write(cam, 0x5E, 0x10); | ||
277 | err += sn9c102_i2c_write(cam, 0x5F, 0xF0); | ||
278 | err += sn9c102_i2c_write(cam, 0x60, 0x05); | ||
279 | err += sn9c102_i2c_write(cam, 0x61, 0x60); | ||
280 | err += sn9c102_i2c_write(cam, 0x62, 0x00); | ||
281 | err += sn9c102_i2c_write(cam, 0x63, 0x00); | ||
282 | err += sn9c102_i2c_write(cam, 0x64, 0x50); | ||
283 | err += sn9c102_i2c_write(cam, 0x65, 0x30); | ||
284 | err += sn9c102_i2c_write(cam, 0x66, 0x00); | ||
285 | err += sn9c102_i2c_write(cam, 0x67, 0x80); | ||
286 | err += sn9c102_i2c_write(cam, 0x68, 0x7A); | ||
287 | err += sn9c102_i2c_write(cam, 0x69, 0x90); | ||
288 | err += sn9c102_i2c_write(cam, 0x6A, 0x80); | ||
289 | err += sn9c102_i2c_write(cam, 0x6B, 0x0A); | ||
290 | err += sn9c102_i2c_write(cam, 0x6C, 0x30); | ||
291 | err += sn9c102_i2c_write(cam, 0x6D, 0x48); | ||
292 | err += sn9c102_i2c_write(cam, 0x6E, 0x80); | ||
293 | err += sn9c102_i2c_write(cam, 0x6F, 0x74); | ||
294 | err += sn9c102_i2c_write(cam, 0x70, 0x64); | ||
295 | err += sn9c102_i2c_write(cam, 0x71, 0x60); | ||
296 | err += sn9c102_i2c_write(cam, 0x72, 0x5C); | ||
297 | err += sn9c102_i2c_write(cam, 0x73, 0x58); | ||
298 | err += sn9c102_i2c_write(cam, 0x74, 0x54); | ||
299 | err += sn9c102_i2c_write(cam, 0x75, 0x4C); | ||
300 | err += sn9c102_i2c_write(cam, 0x76, 0x40); | ||
301 | err += sn9c102_i2c_write(cam, 0x77, 0x38); | ||
302 | err += sn9c102_i2c_write(cam, 0x78, 0x34); | ||
303 | err += sn9c102_i2c_write(cam, 0x79, 0x30); | ||
304 | err += sn9c102_i2c_write(cam, 0x7A, 0x2F); | ||
305 | err += sn9c102_i2c_write(cam, 0x7B, 0x2B); | ||
306 | err += sn9c102_i2c_write(cam, 0x7C, 0x03); | ||
307 | err += sn9c102_i2c_write(cam, 0x7D, 0x07); | ||
308 | err += sn9c102_i2c_write(cam, 0x7E, 0x17); | ||
309 | err += sn9c102_i2c_write(cam, 0x7F, 0x34); | ||
310 | err += sn9c102_i2c_write(cam, 0x80, 0x41); | ||
311 | err += sn9c102_i2c_write(cam, 0x81, 0x4D); | ||
312 | err += sn9c102_i2c_write(cam, 0x82, 0x58); | ||
313 | err += sn9c102_i2c_write(cam, 0x83, 0x63); | ||
314 | err += sn9c102_i2c_write(cam, 0x84, 0x6E); | ||
315 | err += sn9c102_i2c_write(cam, 0x85, 0x77); | ||
316 | err += sn9c102_i2c_write(cam, 0x86, 0x87); | ||
317 | err += sn9c102_i2c_write(cam, 0x87, 0x95); | ||
318 | err += sn9c102_i2c_write(cam, 0x88, 0xAF); | ||
319 | err += sn9c102_i2c_write(cam, 0x89, 0xC7); | ||
320 | err += sn9c102_i2c_write(cam, 0x8A, 0xDF); | ||
321 | err += sn9c102_i2c_write(cam, 0x8B, 0x99); | ||
322 | err += sn9c102_i2c_write(cam, 0x8C, 0x99); | ||
323 | err += sn9c102_i2c_write(cam, 0x8D, 0xCF); | ||
324 | err += sn9c102_i2c_write(cam, 0x8E, 0x20); | ||
325 | err += sn9c102_i2c_write(cam, 0x8F, 0x26); | ||
326 | err += sn9c102_i2c_write(cam, 0x90, 0x10); | ||
327 | err += sn9c102_i2c_write(cam, 0x91, 0x0C); | ||
328 | err += sn9c102_i2c_write(cam, 0x92, 0x25); | ||
329 | err += sn9c102_i2c_write(cam, 0x93, 0x00); | ||
330 | err += sn9c102_i2c_write(cam, 0x94, 0x50); | ||
331 | err += sn9c102_i2c_write(cam, 0x95, 0x50); | ||
332 | err += sn9c102_i2c_write(cam, 0x96, 0x00); | ||
333 | err += sn9c102_i2c_write(cam, 0x97, 0x01); | ||
334 | err += sn9c102_i2c_write(cam, 0x98, 0x10); | ||
335 | err += sn9c102_i2c_write(cam, 0x99, 0x40); | ||
336 | err += sn9c102_i2c_write(cam, 0x9A, 0x40); | ||
337 | err += sn9c102_i2c_write(cam, 0x9B, 0x20); | ||
338 | err += sn9c102_i2c_write(cam, 0x9C, 0x00); | ||
339 | err += sn9c102_i2c_write(cam, 0x9D, 0x99); | ||
340 | err += sn9c102_i2c_write(cam, 0x9E, 0x7F); | ||
341 | err += sn9c102_i2c_write(cam, 0x9F, 0x00); | ||
342 | err += sn9c102_i2c_write(cam, 0xA0, 0x00); | ||
343 | err += sn9c102_i2c_write(cam, 0xA1, 0x00); | ||
344 | |||
345 | return err; | ||
346 | } | ||
347 | |||
348 | |||
349 | static int ov7660_get_ctrl(struct sn9c102_device* cam, | ||
350 | struct v4l2_control* ctrl) | ||
351 | { | ||
352 | int err = 0; | ||
353 | |||
354 | switch (ctrl->id) { | ||
355 | case V4L2_CID_EXPOSURE: | ||
356 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) | ||
357 | return -EIO; | ||
358 | break; | ||
359 | case V4L2_CID_DO_WHITE_BALANCE: | ||
360 | ctrl->value = sn9c102_pread_reg(cam, 0x02); | ||
361 | ctrl->value = (ctrl->value & 0x04) ? 1 : 0; | ||
362 | break; | ||
363 | case V4L2_CID_RED_BALANCE: | ||
364 | ctrl->value = sn9c102_pread_reg(cam, 0x05); | ||
365 | ctrl->value &= 0x7f; | ||
366 | break; | ||
367 | case V4L2_CID_BLUE_BALANCE: | ||
368 | ctrl->value = sn9c102_pread_reg(cam, 0x06); | ||
369 | ctrl->value &= 0x7f; | ||
370 | break; | ||
371 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
372 | ctrl->value = sn9c102_pread_reg(cam, 0x07); | ||
373 | ctrl->value &= 0x7f; | ||
374 | break; | ||
375 | case V4L2_CID_GAIN: | ||
376 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0) | ||
377 | return -EIO; | ||
378 | ctrl->value &= 0x7f; | ||
379 | break; | ||
380 | case V4L2_CID_AUTOGAIN: | ||
381 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0) | ||
382 | return -EIO; | ||
383 | ctrl->value &= 0x01; | ||
384 | break; | ||
385 | default: | ||
386 | return -EINVAL; | ||
387 | } | ||
388 | |||
389 | return err ? -EIO : 0; | ||
390 | } | ||
391 | |||
392 | |||
393 | static int ov7660_set_ctrl(struct sn9c102_device* cam, | ||
394 | const struct v4l2_control* ctrl) | ||
395 | { | ||
396 | int err = 0; | ||
397 | |||
398 | switch (ctrl->id) { | ||
399 | case V4L2_CID_EXPOSURE: | ||
400 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value); | ||
401 | break; | ||
402 | case V4L2_CID_DO_WHITE_BALANCE: | ||
403 | err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02); | ||
404 | break; | ||
405 | case V4L2_CID_RED_BALANCE: | ||
406 | err += sn9c102_write_reg(cam, ctrl->value, 0x05); | ||
407 | break; | ||
408 | case V4L2_CID_BLUE_BALANCE: | ||
409 | err += sn9c102_write_reg(cam, ctrl->value, 0x06); | ||
410 | break; | ||
411 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
412 | err += sn9c102_write_reg(cam, ctrl->value, 0x07); | ||
413 | break; | ||
414 | case V4L2_CID_GAIN: | ||
415 | err += sn9c102_i2c_write(cam, 0x00, ctrl->value); | ||
416 | break; | ||
417 | case V4L2_CID_AUTOGAIN: | ||
418 | err += sn9c102_i2c_write(cam, 0x13, 0xf0 | ctrl->value | | ||
419 | (ctrl->value << 1)); | ||
420 | break; | ||
421 | default: | ||
422 | return -EINVAL; | ||
423 | } | ||
424 | |||
425 | return err ? -EIO : 0; | ||
426 | } | ||
427 | |||
428 | |||
429 | static int ov7660_set_crop(struct sn9c102_device* cam, | ||
430 | const struct v4l2_rect* rect) | ||
431 | { | ||
432 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
433 | int err = 0; | ||
434 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, | ||
435 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
436 | |||
437 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
438 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
439 | |||
440 | return err; | ||
441 | } | ||
442 | |||
443 | |||
444 | static int ov7660_set_pix_format(struct sn9c102_device* cam, | ||
445 | const struct v4l2_pix_format* pix) | ||
446 | { | ||
447 | int r0, err = 0; | ||
448 | |||
449 | r0 = sn9c102_pread_reg(cam, 0x01); | ||
450 | |||
451 | if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { | ||
452 | err += sn9c102_write_reg(cam, r0 | 0x40, 0x01); | ||
453 | err += sn9c102_write_reg(cam, 0xa2, 0x17); | ||
454 | err += sn9c102_i2c_write(cam, 0x11, 0x00); | ||
455 | } else { | ||
456 | err += sn9c102_write_reg(cam, r0 | 0x40, 0x01); | ||
457 | err += sn9c102_write_reg(cam, 0xa2, 0x17); | ||
458 | err += sn9c102_i2c_write(cam, 0x11, 0x0d); | ||
459 | } | ||
460 | |||
461 | return err; | ||
462 | } | ||
463 | |||
464 | |||
465 | static struct sn9c102_sensor ov7660 = { | ||
466 | .name = "OV7660", | ||
467 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
468 | .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, | ||
469 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
470 | .frequency = SN9C102_I2C_100KHZ, | ||
471 | .interface = SN9C102_I2C_2WIRES, | ||
472 | .i2c_slave_id = 0x21, | ||
473 | .init = &ov7660_init, | ||
474 | .qctrl = { | ||
475 | { | ||
476 | .id = V4L2_CID_GAIN, | ||
477 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
478 | .name = "global gain", | ||
479 | .minimum = 0x00, | ||
480 | .maximum = 0x7f, | ||
481 | .step = 0x01, | ||
482 | .default_value = 0x0a, | ||
483 | .flags = 0, | ||
484 | }, | ||
485 | { | ||
486 | .id = V4L2_CID_EXPOSURE, | ||
487 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
488 | .name = "exposure", | ||
489 | .minimum = 0x00, | ||
490 | .maximum = 0xff, | ||
491 | .step = 0x01, | ||
492 | .default_value = 0x50, | ||
493 | .flags = 0, | ||
494 | }, | ||
495 | { | ||
496 | .id = V4L2_CID_DO_WHITE_BALANCE, | ||
497 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
498 | .name = "night mode", | ||
499 | .minimum = 0x00, | ||
500 | .maximum = 0x01, | ||
501 | .step = 0x01, | ||
502 | .default_value = 0x00, | ||
503 | .flags = 0, | ||
504 | }, | ||
505 | { | ||
506 | .id = V4L2_CID_RED_BALANCE, | ||
507 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
508 | .name = "red balance", | ||
509 | .minimum = 0x00, | ||
510 | .maximum = 0x7f, | ||
511 | .step = 0x01, | ||
512 | .default_value = 0x1f, | ||
513 | .flags = 0, | ||
514 | }, | ||
515 | { | ||
516 | .id = V4L2_CID_BLUE_BALANCE, | ||
517 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
518 | .name = "blue balance", | ||
519 | .minimum = 0x00, | ||
520 | .maximum = 0x7f, | ||
521 | .step = 0x01, | ||
522 | .default_value = 0x1e, | ||
523 | .flags = 0, | ||
524 | }, | ||
525 | { | ||
526 | .id = V4L2_CID_AUTOGAIN, | ||
527 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
528 | .name = "auto adjust", | ||
529 | .minimum = 0x00, | ||
530 | .maximum = 0x01, | ||
531 | .step = 0x01, | ||
532 | .default_value = 0x00, | ||
533 | .flags = 0, | ||
534 | }, | ||
535 | { | ||
536 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
537 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
538 | .name = "green balance", | ||
539 | .minimum = 0x00, | ||
540 | .maximum = 0x7f, | ||
541 | .step = 0x01, | ||
542 | .default_value = 0x20, | ||
543 | .flags = 0, | ||
544 | }, | ||
545 | }, | ||
546 | .get_ctrl = &ov7660_get_ctrl, | ||
547 | .set_ctrl = &ov7660_set_ctrl, | ||
548 | .cropcap = { | ||
549 | .bounds = { | ||
550 | .left = 0, | ||
551 | .top = 0, | ||
552 | .width = 640, | ||
553 | .height = 480, | ||
554 | }, | ||
555 | .defrect = { | ||
556 | .left = 0, | ||
557 | .top = 0, | ||
558 | .width = 640, | ||
559 | .height = 480, | ||
560 | }, | ||
561 | }, | ||
562 | .set_crop = &ov7660_set_crop, | ||
563 | .pix_format = { | ||
564 | .width = 640, | ||
565 | .height = 480, | ||
566 | .pixelformat = V4L2_PIX_FMT_JPEG, | ||
567 | .priv = 8, | ||
568 | }, | ||
569 | .set_pix_format = &ov7660_set_pix_format | ||
570 | }; | ||
571 | |||
572 | |||
573 | int sn9c102_probe_ov7660(struct sn9c102_device* cam) | ||
574 | { | ||
575 | int pid, ver, err = 0; | ||
576 | |||
577 | err += sn9c102_write_reg(cam, 0x01, 0xf1); | ||
578 | err += sn9c102_write_reg(cam, 0x00, 0xf1); | ||
579 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
580 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
581 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
582 | |||
583 | pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a); | ||
584 | ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b); | ||
585 | if (err || pid < 0 || ver < 0) | ||
586 | return -EIO; | ||
587 | if (pid != 0x76 || ver != 0x60) | ||
588 | return -ENODEV; | ||
589 | sn9c102_attach_sensor(cam, &ov7660); | ||
590 | |||
591 | return 0; | ||
592 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c index 9915944235e8..8d79a5fae5de 100644 --- a/drivers/media/video/sn9c102/sn9c102_pas106b.c +++ b/drivers/media/video/sn9c102/sn9c102_pas106b.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera * | 2 | * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera * |
3 | * Controllers * | 3 | * Controllers * |
4 | * * | 4 | * * |
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | 5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * |
6 | * * | 6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * | 7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * | 8 | * it under the terms of the GNU General Public License as published by * |
@@ -143,7 +143,7 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam, | |||
143 | static int pas106b_set_crop(struct sn9c102_device* cam, | 143 | static int pas106b_set_crop(struct sn9c102_device* cam, |
144 | const struct v4l2_rect* rect) | 144 | const struct v4l2_rect* rect) |
145 | { | 145 | { |
146 | struct sn9c102_sensor* s = &pas106b; | 146 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); |
147 | int err = 0; | 147 | int err = 0; |
148 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, | 148 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, |
149 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | 149 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; |
@@ -172,6 +172,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam, | |||
172 | static struct sn9c102_sensor pas106b = { | 172 | static struct sn9c102_sensor pas106b = { |
173 | .name = "PAS106B", | 173 | .name = "PAS106B", |
174 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 174 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
175 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | ||
175 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | 176 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, |
176 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | 177 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, |
177 | .interface = SN9C102_I2C_2WIRES, | 178 | .interface = SN9C102_I2C_2WIRES, |
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bca.c b/drivers/media/video/sn9c102/sn9c102_pas202bca.c deleted file mode 100644 index c8f1ae2152b8..000000000000 --- a/drivers/media/video/sn9c102/sn9c102_pas202bca.c +++ /dev/null | |||
@@ -1,238 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include <linux/delay.h> | ||
23 | #include "sn9c102_sensor.h" | ||
24 | |||
25 | |||
26 | static struct sn9c102_sensor pas202bca; | ||
27 | |||
28 | |||
29 | static int pas202bca_init(struct sn9c102_device* cam) | ||
30 | { | ||
31 | int err = 0; | ||
32 | |||
33 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
34 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
35 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
36 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
37 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
38 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
39 | |||
40 | err += sn9c102_i2c_write(cam, 0x02, 0x14); | ||
41 | err += sn9c102_i2c_write(cam, 0x03, 0x40); | ||
42 | err += sn9c102_i2c_write(cam, 0x0d, 0x2c); | ||
43 | err += sn9c102_i2c_write(cam, 0x0e, 0x01); | ||
44 | err += sn9c102_i2c_write(cam, 0x0f, 0xa9); | ||
45 | err += sn9c102_i2c_write(cam, 0x10, 0x08); | ||
46 | err += sn9c102_i2c_write(cam, 0x13, 0x63); | ||
47 | err += sn9c102_i2c_write(cam, 0x15, 0x70); | ||
48 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
49 | |||
50 | msleep(400); | ||
51 | |||
52 | return err; | ||
53 | } | ||
54 | |||
55 | |||
56 | static int pas202bca_set_pix_format(struct sn9c102_device* cam, | ||
57 | const struct v4l2_pix_format* pix) | ||
58 | { | ||
59 | int err = 0; | ||
60 | |||
61 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
62 | err += sn9c102_write_reg(cam, 0x24, 0x17); | ||
63 | else | ||
64 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
65 | |||
66 | return err; | ||
67 | } | ||
68 | |||
69 | |||
70 | static int pas202bca_set_ctrl(struct sn9c102_device* cam, | ||
71 | const struct v4l2_control* ctrl) | ||
72 | { | ||
73 | int err = 0; | ||
74 | |||
75 | switch (ctrl->id) { | ||
76 | case V4L2_CID_EXPOSURE: | ||
77 | err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); | ||
78 | err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); | ||
79 | break; | ||
80 | case V4L2_CID_RED_BALANCE: | ||
81 | err += sn9c102_i2c_write(cam, 0x09, ctrl->value); | ||
82 | break; | ||
83 | case V4L2_CID_BLUE_BALANCE: | ||
84 | err += sn9c102_i2c_write(cam, 0x07, ctrl->value); | ||
85 | break; | ||
86 | case V4L2_CID_GAIN: | ||
87 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value); | ||
88 | break; | ||
89 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
90 | err += sn9c102_i2c_write(cam, 0x08, ctrl->value); | ||
91 | break; | ||
92 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
93 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
94 | break; | ||
95 | default: | ||
96 | return -EINVAL; | ||
97 | } | ||
98 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
99 | |||
100 | return err ? -EIO : 0; | ||
101 | } | ||
102 | |||
103 | |||
104 | static int pas202bca_set_crop(struct sn9c102_device* cam, | ||
105 | const struct v4l2_rect* rect) | ||
106 | { | ||
107 | struct sn9c102_sensor* s = &pas202bca; | ||
108 | int err = 0; | ||
109 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3, | ||
110 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | ||
111 | |||
112 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
113 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
114 | |||
115 | return err; | ||
116 | } | ||
117 | |||
118 | |||
119 | static struct sn9c102_sensor pas202bca = { | ||
120 | .name = "PAS202BCA", | ||
121 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
122 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
123 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | ||
124 | .interface = SN9C102_I2C_2WIRES, | ||
125 | .i2c_slave_id = 0x40, | ||
126 | .init = &pas202bca_init, | ||
127 | .qctrl = { | ||
128 | { | ||
129 | .id = V4L2_CID_EXPOSURE, | ||
130 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
131 | .name = "exposure", | ||
132 | .minimum = 0x01e5, | ||
133 | .maximum = 0x3fff, | ||
134 | .step = 0x0001, | ||
135 | .default_value = 0x01e5, | ||
136 | .flags = 0, | ||
137 | }, | ||
138 | { | ||
139 | .id = V4L2_CID_GAIN, | ||
140 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
141 | .name = "global gain", | ||
142 | .minimum = 0x00, | ||
143 | .maximum = 0x1f, | ||
144 | .step = 0x01, | ||
145 | .default_value = 0x0c, | ||
146 | .flags = 0, | ||
147 | }, | ||
148 | { | ||
149 | .id = V4L2_CID_RED_BALANCE, | ||
150 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
151 | .name = "red balance", | ||
152 | .minimum = 0x00, | ||
153 | .maximum = 0x0f, | ||
154 | .step = 0x01, | ||
155 | .default_value = 0x01, | ||
156 | .flags = 0, | ||
157 | }, | ||
158 | { | ||
159 | .id = V4L2_CID_BLUE_BALANCE, | ||
160 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
161 | .name = "blue balance", | ||
162 | .minimum = 0x00, | ||
163 | .maximum = 0x0f, | ||
164 | .step = 0x01, | ||
165 | .default_value = 0x05, | ||
166 | .flags = 0, | ||
167 | }, | ||
168 | { | ||
169 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
170 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
171 | .name = "green balance", | ||
172 | .minimum = 0x00, | ||
173 | .maximum = 0x0f, | ||
174 | .step = 0x01, | ||
175 | .default_value = 0x00, | ||
176 | .flags = 0, | ||
177 | }, | ||
178 | { | ||
179 | .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, | ||
180 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
181 | .name = "DAC magnitude", | ||
182 | .minimum = 0x00, | ||
183 | .maximum = 0xff, | ||
184 | .step = 0x01, | ||
185 | .default_value = 0x04, | ||
186 | .flags = 0, | ||
187 | }, | ||
188 | }, | ||
189 | .set_ctrl = &pas202bca_set_ctrl, | ||
190 | .cropcap = { | ||
191 | .bounds = { | ||
192 | .left = 0, | ||
193 | .top = 0, | ||
194 | .width = 640, | ||
195 | .height = 480, | ||
196 | }, | ||
197 | .defrect = { | ||
198 | .left = 0, | ||
199 | .top = 0, | ||
200 | .width = 640, | ||
201 | .height = 480, | ||
202 | }, | ||
203 | }, | ||
204 | .set_crop = &pas202bca_set_crop, | ||
205 | .pix_format = { | ||
206 | .width = 640, | ||
207 | .height = 480, | ||
208 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
209 | .priv = 8, | ||
210 | }, | ||
211 | .set_pix_format = &pas202bca_set_pix_format | ||
212 | }; | ||
213 | |||
214 | |||
215 | int sn9c102_probe_pas202bca(struct sn9c102_device* cam) | ||
216 | { | ||
217 | const struct usb_device_id pas202bca_id_table[] = { | ||
218 | { USB_DEVICE(0x0c45, 0x60af), }, | ||
219 | { } | ||
220 | }; | ||
221 | int err = 0; | ||
222 | |||
223 | if (!sn9c102_match_id(cam,pas202bca_id_table)) | ||
224 | return -ENODEV; | ||
225 | |||
226 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
227 | err += sn9c102_write_reg(cam, 0x40, 0x01); | ||
228 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
229 | if (err) | ||
230 | return -EIO; | ||
231 | |||
232 | if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */ | ||
233 | return -ENODEV; | ||
234 | |||
235 | sn9c102_attach_sensor(cam, &pas202bca); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c index e3c1178e339c..7894f01b56e8 100644 --- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c +++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c | |||
@@ -1,13 +1,13 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera * | 2 | * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera * |
3 | * Controllers * | 3 | * Controllers * |
4 | * * | 4 | * * |
5 | * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * | 5 | * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * |
6 | * <medaglia@undl.org.br> * | 6 | * <medaglia@undl.org.br> * |
7 | * http://cadu.homelinux.com:8080/ * | 7 | * http://cadu.homelinux.com:8080/ * |
8 | * * | 8 | * * |
9 | * DAC Magnitude, exposure and green gain controls added by * | 9 | * Support for SN9C103, DAC Magnitude, exposure and green gain controls * |
10 | * Luca Risolia <luca.risolia@studio.unibo.it> * | 10 | * added by Luca Risolia <luca.risolia@studio.unibo.it> * |
11 | * * | 11 | * * |
12 | * This program is free software; you can redistribute it and/or modify * | 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 * | 13 | * it under the terms of the GNU General Public License as published by * |
@@ -35,12 +35,54 @@ static int pas202bcb_init(struct sn9c102_device* cam) | |||
35 | { | 35 | { |
36 | int err = 0; | 36 | int err = 0; |
37 | 37 | ||
38 | switch (sn9c102_get_bridge(cam)) { | ||
39 | case BRIDGE_SN9C101: | ||
40 | case BRIDGE_SN9C102: | ||
38 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 41 | err += sn9c102_write_reg(cam, 0x00, 0x10); |
39 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 42 | err += sn9c102_write_reg(cam, 0x00, 0x11); |
40 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 43 | err += sn9c102_write_reg(cam, 0x00, 0x14); |
41 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 44 | err += sn9c102_write_reg(cam, 0x20, 0x17); |
42 | err += sn9c102_write_reg(cam, 0x30, 0x19); | 45 | err += sn9c102_write_reg(cam, 0x30, 0x19); |
43 | err += sn9c102_write_reg(cam, 0x09, 0x18); | 46 | err += sn9c102_write_reg(cam, 0x09, 0x18); |
47 | break; | ||
48 | case BRIDGE_SN9C103: | ||
49 | err += sn9c102_write_reg(cam, 0x00, 0x02); | ||
50 | err += sn9c102_write_reg(cam, 0x00, 0x03); | ||
51 | err += sn9c102_write_reg(cam, 0x1a, 0x04); | ||
52 | err += sn9c102_write_reg(cam, 0x20, 0x05); | ||
53 | err += sn9c102_write_reg(cam, 0x20, 0x06); | ||
54 | err += sn9c102_write_reg(cam, 0x20, 0x07); | ||
55 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
56 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
57 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
58 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
59 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
60 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
61 | err += sn9c102_write_reg(cam, 0x02, 0x1c); | ||
62 | err += sn9c102_write_reg(cam, 0x03, 0x1d); | ||
63 | err += sn9c102_write_reg(cam, 0x0f, 0x1e); | ||
64 | err += sn9c102_write_reg(cam, 0x0c, 0x1f); | ||
65 | err += sn9c102_write_reg(cam, 0x00, 0x20); | ||
66 | err += sn9c102_write_reg(cam, 0x10, 0x21); | ||
67 | err += sn9c102_write_reg(cam, 0x20, 0x22); | ||
68 | err += sn9c102_write_reg(cam, 0x30, 0x23); | ||
69 | err += sn9c102_write_reg(cam, 0x40, 0x24); | ||
70 | err += sn9c102_write_reg(cam, 0x50, 0x25); | ||
71 | err += sn9c102_write_reg(cam, 0x60, 0x26); | ||
72 | err += sn9c102_write_reg(cam, 0x70, 0x27); | ||
73 | err += sn9c102_write_reg(cam, 0x80, 0x28); | ||
74 | err += sn9c102_write_reg(cam, 0x90, 0x29); | ||
75 | err += sn9c102_write_reg(cam, 0xa0, 0x2a); | ||
76 | err += sn9c102_write_reg(cam, 0xb0, 0x2b); | ||
77 | err += sn9c102_write_reg(cam, 0xc0, 0x2c); | ||
78 | err += sn9c102_write_reg(cam, 0xd0, 0x2d); | ||
79 | err += sn9c102_write_reg(cam, 0xe0, 0x2e); | ||
80 | err += sn9c102_write_reg(cam, 0xf0, 0x2f); | ||
81 | err += sn9c102_write_reg(cam, 0xff, 0x30); | ||
82 | break; | ||
83 | default: | ||
84 | break; | ||
85 | } | ||
44 | 86 | ||
45 | err += sn9c102_i2c_write(cam, 0x02, 0x14); | 87 | err += sn9c102_i2c_write(cam, 0x02, 0x14); |
46 | err += sn9c102_i2c_write(cam, 0x03, 0x40); | 88 | err += sn9c102_i2c_write(cam, 0x03, 0x40); |
@@ -107,7 +149,7 @@ static int pas202bcb_set_pix_format(struct sn9c102_device* cam, | |||
107 | int err = 0; | 149 | int err = 0; |
108 | 150 | ||
109 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | 151 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) |
110 | err += sn9c102_write_reg(cam, 0x24, 0x17); | 152 | err += sn9c102_write_reg(cam, 0x28, 0x17); |
111 | else | 153 | else |
112 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 154 | err += sn9c102_write_reg(cam, 0x20, 0x17); |
113 | 155 | ||
@@ -152,11 +194,23 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam, | |||
152 | static int pas202bcb_set_crop(struct sn9c102_device* cam, | 194 | static int pas202bcb_set_crop(struct sn9c102_device* cam, |
153 | const struct v4l2_rect* rect) | 195 | const struct v4l2_rect* rect) |
154 | { | 196 | { |
155 | struct sn9c102_sensor* s = &pas202bcb; | 197 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); |
156 | int err = 0; | 198 | int err = 0; |
157 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, | 199 | u8 h_start = 0, |
158 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | 200 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; |
159 | 201 | ||
202 | switch (sn9c102_get_bridge(cam)) { | ||
203 | case BRIDGE_SN9C101: | ||
204 | case BRIDGE_SN9C102: | ||
205 | h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4; | ||
206 | break; | ||
207 | case BRIDGE_SN9C103: | ||
208 | h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3; | ||
209 | break; | ||
210 | default: | ||
211 | break; | ||
212 | } | ||
213 | |||
160 | err += sn9c102_write_reg(cam, h_start, 0x12); | 214 | err += sn9c102_write_reg(cam, h_start, 0x12); |
161 | err += sn9c102_write_reg(cam, v_start, 0x13); | 215 | err += sn9c102_write_reg(cam, v_start, 0x13); |
162 | 216 | ||
@@ -166,8 +220,8 @@ static int pas202bcb_set_crop(struct sn9c102_device* cam, | |||
166 | 220 | ||
167 | static struct sn9c102_sensor pas202bcb = { | 221 | static struct sn9c102_sensor pas202bcb = { |
168 | .name = "PAS202BCB", | 222 | .name = "PAS202BCB", |
169 | .maintainer = "Carlos Eduardo Medaglia Dyonisio " | 223 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
170 | "<medaglia@undl.org.br>", | 224 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, |
171 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | 225 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, |
172 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | 226 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, |
173 | .interface = SN9C102_I2C_2WIRES, | 227 | .interface = SN9C102_I2C_2WIRES, |
@@ -191,7 +245,7 @@ static struct sn9c102_sensor pas202bcb = { | |||
191 | .minimum = 0x00, | 245 | .minimum = 0x00, |
192 | .maximum = 0x1f, | 246 | .maximum = 0x1f, |
193 | .step = 0x01, | 247 | .step = 0x01, |
194 | .default_value = 0x0c, | 248 | .default_value = 0x0b, |
195 | .flags = 0, | 249 | .flags = 0, |
196 | }, | 250 | }, |
197 | { | 251 | { |
@@ -201,7 +255,7 @@ static struct sn9c102_sensor pas202bcb = { | |||
201 | .minimum = 0x00, | 255 | .minimum = 0x00, |
202 | .maximum = 0x0f, | 256 | .maximum = 0x0f, |
203 | .step = 0x01, | 257 | .step = 0x01, |
204 | .default_value = 0x01, | 258 | .default_value = 0x00, |
205 | .flags = 0, | 259 | .flags = 0, |
206 | }, | 260 | }, |
207 | { | 261 | { |
@@ -271,16 +325,27 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) | |||
271 | * Minimal initialization to enable the I2C communication | 325 | * Minimal initialization to enable the I2C communication |
272 | * NOTE: do NOT change the values! | 326 | * NOTE: do NOT change the values! |
273 | */ | 327 | */ |
274 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ | 328 | switch (sn9c102_get_bridge(cam)) { |
275 | err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */ | 329 | case BRIDGE_SN9C101: |
276 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ | 330 | case BRIDGE_SN9C102: |
277 | if (err) | 331 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */ |
278 | return -EIO; | 332 | err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */ |
333 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */ | ||
334 | break; | ||
335 | case BRIDGE_SN9C103: /* do _not_ change anything! */ | ||
336 | err += sn9c102_write_reg(cam, 0x09, 0x01); | ||
337 | err += sn9c102_write_reg(cam, 0x44, 0x01); | ||
338 | err += sn9c102_write_reg(cam, 0x44, 0x02); | ||
339 | err += sn9c102_write_reg(cam, 0x29, 0x17); | ||
340 | break; | ||
341 | default: | ||
342 | break; | ||
343 | } | ||
279 | 344 | ||
280 | r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); | 345 | r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); |
281 | r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); | 346 | r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); |
282 | 347 | ||
283 | if (r0 < 0 || r1 < 0) | 348 | if (err || r0 < 0 || r1 < 0) |
284 | return -EIO; | 349 | return -EIO; |
285 | 350 | ||
286 | pid = (r0 << 4) | ((r1 & 0xf0) >> 4); | 351 | pid = (r0 << 4) | ((r1 & 0xf0) >> 4); |
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h index 2a874ee6f9f5..05f2942639c3 100644 --- a/drivers/media/video/sn9c102/sn9c102_sensor.h +++ b/drivers/media/video/sn9c102/sn9c102_sensor.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * API for image sensors connected to the SN9C10x PC Camera Controllers * | 2 | * API for image sensors connected to the SN9C1xx PC Camera Controllers * |
3 | * * | 3 | * * |
4 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | 4 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * |
5 | * * | 5 | * * |
6 | * This program is free software; you can redistribute it and/or modify * | 6 | * This program is free software; you can redistribute it and/or modify * |
7 | * it under the terms of the GNU General Public License as published by * | 7 | * it under the terms of the GNU General Public License as published by * |
@@ -36,14 +36,13 @@ struct sn9c102_sensor; | |||
36 | /* | 36 | /* |
37 | OVERVIEW. | 37 | OVERVIEW. |
38 | This is a small interface that allows you to add support for any CCD/CMOS | 38 | This is a small interface that allows you to add support for any CCD/CMOS |
39 | image sensors connected to the SN9C10X bridges. The entire API is documented | 39 | image sensors connected to the SN9C1XX bridges. The entire API is documented |
40 | below. In the most general case, to support a sensor there are three steps | 40 | below. In the most general case, to support a sensor there are three steps |
41 | you have to follow: | 41 | you have to follow: |
42 | 1) define the main "sn9c102_sensor" structure by setting the basic fields; | 42 | 1) define the main "sn9c102_sensor" structure by setting the basic fields; |
43 | 2) write a probing function to be called by the core module when the USB | 43 | 2) write a probing function to be called by the core module when the USB |
44 | camera is recognized, then add both the USB ids and the name of that | 44 | camera is recognized, then add both the USB ids and the name of that |
45 | function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see | 45 | function to the two corresponding tables in sn9c102_devtable.h; |
46 | below); | ||
47 | 3) implement the methods that you want/need (and fill the rest of the main | 46 | 3) implement the methods that you want/need (and fill the rest of the main |
48 | structure accordingly). | 47 | structure accordingly). |
49 | "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do | 48 | "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do |
@@ -54,42 +53,21 @@ struct sn9c102_sensor; | |||
54 | 53 | ||
55 | /*****************************************************************************/ | 54 | /*****************************************************************************/ |
56 | 55 | ||
57 | /* | 56 | enum sn9c102_bridge { |
58 | Probing functions: on success, you must attach the sensor to the camera | 57 | BRIDGE_SN9C101 = 0x01, |
59 | by calling sn9c102_attach_sensor() provided below. | 58 | BRIDGE_SN9C102 = 0x02, |
60 | To enable the I2C communication, you might need to perform a really basic | 59 | BRIDGE_SN9C103 = 0x04, |
61 | initialization of the SN9C10X chip by using the write function declared | 60 | BRIDGE_SN9C105 = 0x08, |
62 | ahead. | 61 | BRIDGE_SN9C120 = 0x10, |
63 | Functions must return 0 on success, the appropriate error otherwise. | ||
64 | */ | ||
65 | extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); | ||
66 | extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); | ||
67 | extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); | ||
68 | extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); | ||
69 | extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam); | ||
70 | extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); | ||
71 | extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); | ||
72 | extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); | ||
73 | |||
74 | /* | ||
75 | Add the above entries to this table. Be sure to add the entry in the right | ||
76 | place, since, on failure, the next probing routine is called according to | ||
77 | the order of the list below, from top to bottom. | ||
78 | */ | ||
79 | #define SN9C102_SENSOR_TABLE \ | ||
80 | static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ | ||
81 | &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ \ | ||
82 | &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ | ||
83 | &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ | ||
84 | &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \ | ||
85 | &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \ | ||
86 | &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \ | ||
87 | &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ | ||
88 | &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ | ||
89 | NULL, \ | ||
90 | }; | 62 | }; |
91 | 63 | ||
92 | /* Device identification */ | 64 | /* Return the bridge name */ |
65 | enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam); | ||
66 | |||
67 | /* Return a pointer the sensor struct attached to the camera */ | ||
68 | struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam); | ||
69 | |||
70 | /* Identify a device */ | ||
93 | extern struct sn9c102_device* | 71 | extern struct sn9c102_device* |
94 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id); | 72 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id); |
95 | 73 | ||
@@ -99,68 +77,8 @@ sn9c102_attach_sensor(struct sn9c102_device* cam, | |||
99 | struct sn9c102_sensor* sensor); | 77 | struct sn9c102_sensor* sensor); |
100 | 78 | ||
101 | /* | 79 | /* |
102 | Each SN9C10x camera has proper PID/VID identifiers. | ||
103 | SN9C103 supports multiple interfaces, but we only handle the video class | ||
104 | interface. | ||
105 | */ | ||
106 | #define SN9C102_USB_DEVICE(vend, prod, intclass) \ | ||
107 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | ||
108 | USB_DEVICE_ID_MATCH_INT_CLASS, \ | ||
109 | .idVendor = (vend), \ | ||
110 | .idProduct = (prod), \ | ||
111 | .bInterfaceClass = (intclass) | ||
112 | |||
113 | #define SN9C102_ID_TABLE \ | ||
114 | static const struct usb_device_id sn9c102_id_table[] = { \ | ||
115 | { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \ | ||
116 | { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \ | ||
117 | { USB_DEVICE(0x0c45, 0x6007), }, \ | ||
118 | { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \ | ||
119 | { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \ | ||
120 | { USB_DEVICE(0x0c45, 0x6024), }, \ | ||
121 | { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \ | ||
122 | { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \ | ||
123 | { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \ | ||
124 | { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \ | ||
125 | { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \ | ||
126 | { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \ | ||
127 | { USB_DEVICE(0x0c45, 0x602d), }, \ | ||
128 | { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */ \ | ||
129 | { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \ | ||
130 | { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), }, \ | ||
131 | { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */ \ | ||
132 | { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */ \ | ||
133 | { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \ | ||
134 | { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \ | ||
135 | { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \ | ||
136 | { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */ \ | ||
137 | { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \ | ||
138 | { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \ | ||
139 | { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \ | ||
140 | { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), }, \ | ||
141 | { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), }, \ | ||
142 | { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */ \ | ||
143 | { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */ \ | ||
144 | { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */ \ | ||
145 | { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), }, \ | ||
146 | { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), }, \ | ||
147 | { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */ \ | ||
148 | { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */ \ | ||
149 | { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), }, \ | ||
150 | { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), }, \ | ||
151 | { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), }, \ | ||
152 | { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), }, \ | ||
153 | { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), }, \ | ||
154 | { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), }, \ | ||
155 | { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), }, \ | ||
156 | { } \ | ||
157 | }; | ||
158 | |||
159 | /*****************************************************************************/ | ||
160 | |||
161 | /* | ||
162 | Read/write routines: they always return -1 on error, 0 or the read value | 80 | Read/write routines: they always return -1 on error, 0 or the read value |
163 | otherwise. NOTE that a real read operation is not supported by the SN9C10X | 81 | otherwise. NOTE that a real read operation is not supported by the SN9C1XX |
164 | chip for some of its registers. To work around this problem, a pseudo-read | 82 | chip for some of its registers. To work around this problem, a pseudo-read |
165 | call is provided instead: it returns the last successfully written value | 83 | call is provided instead: it returns the last successfully written value |
166 | on the register (0 if it has never been written), the usual -1 on error. | 84 | on the register (0 if it has never been written), the usual -1 on error. |
@@ -176,7 +94,7 @@ extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, | |||
176 | These must be used if and only if the sensor doesn't implement the standard | 94 | These must be used if and only if the sensor doesn't implement the standard |
177 | I2C protocol. There are a number of good reasons why you must use the | 95 | I2C protocol. There are a number of good reasons why you must use the |
178 | single-byte versions of these functions: do not abuse. The first function | 96 | single-byte versions of these functions: do not abuse. The first function |
179 | writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X | 97 | writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX |
180 | chip. The second one programs the registers 0x09 and 0x10 with data0 and | 98 | chip. The second one programs the registers 0x09 and 0x10 with data0 and |
181 | data1, and places the n bytes read from the sensor register table in the | 99 | data1, and places the n bytes read from the sensor register table in the |
182 | buffer pointed by 'buffer'. Both the functions return -1 on error; the write | 100 | buffer pointed by 'buffer'. Both the functions return -1 on error; the write |
@@ -200,16 +118,6 @@ extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index); | |||
200 | extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); | 118 | extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); |
201 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); | 119 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); |
202 | 120 | ||
203 | /* | ||
204 | NOTE: there are no exported debugging functions. To uniform the output you | ||
205 | must use the dev_info()/dev_warn()/dev_err() macros defined in device.h, | ||
206 | already included here, the argument being the struct device '&usbdev->dev' | ||
207 | of the sensor structure. Do NOT use these macros before the sensor is | ||
208 | attached or the kernel will crash! However, you should not need to notify | ||
209 | the user about common errors or other messages, since this is done by the | ||
210 | master module. | ||
211 | */ | ||
212 | |||
213 | /*****************************************************************************/ | 121 | /*****************************************************************************/ |
214 | 122 | ||
215 | enum sn9c102_i2c_sysfs_ops { | 123 | enum sn9c102_i2c_sysfs_ops { |
@@ -227,17 +135,19 @@ enum sn9c102_i2c_interface { | |||
227 | SN9C102_I2C_3WIRES, | 135 | SN9C102_I2C_3WIRES, |
228 | }; | 136 | }; |
229 | 137 | ||
230 | #define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 | 138 | #define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10) |
231 | 139 | ||
232 | struct sn9c102_sensor { | 140 | struct sn9c102_sensor { |
233 | char name[32], /* sensor name */ | 141 | char name[32], /* sensor name */ |
234 | maintainer[64]; /* name of the mantainer <email> */ | 142 | maintainer[64]; /* name of the mantainer <email> */ |
235 | 143 | ||
144 | enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */ | ||
145 | |||
236 | /* Supported operations through the 'sysfs' interface */ | 146 | /* Supported operations through the 'sysfs' interface */ |
237 | enum sn9c102_i2c_sysfs_ops sysfs_ops; | 147 | enum sn9c102_i2c_sysfs_ops sysfs_ops; |
238 | 148 | ||
239 | /* | 149 | /* |
240 | These sensor capabilities must be provided if the SN9C10X controller | 150 | These sensor capabilities must be provided if the SN9C1XX controller |
241 | needs to communicate through the sensor serial interface by using | 151 | needs to communicate through the sensor serial interface by using |
242 | at least one of the i2c functions available. | 152 | at least one of the i2c functions available. |
243 | */ | 153 | */ |
@@ -260,7 +170,7 @@ struct sn9c102_sensor { | |||
260 | /* | 170 | /* |
261 | This function will be called after the sensor has been attached. | 171 | This function will be called after the sensor has been attached. |
262 | It should be used to initialize the sensor only, but may also | 172 | It should be used to initialize the sensor only, but may also |
263 | configure part of the SN9C10X chip if necessary. You don't need to | 173 | configure part of the SN9C1XX chip if necessary. You don't need to |
264 | setup picture settings like brightness, contrast, etc.. here, if | 174 | setup picture settings like brightness, contrast, etc.. here, if |
265 | the corrisponding controls are implemented (see below), since | 175 | the corrisponding controls are implemented (see below), since |
266 | they are adjusted in the core driver by calling the set_ctrl() | 176 | they are adjusted in the core driver by calling the set_ctrl() |
@@ -300,7 +210,7 @@ struct sn9c102_sensor { | |||
300 | It is not always true that the largest achievable active window can | 210 | It is not always true that the largest achievable active window can |
301 | cover the whole array of pixels. The V4L2 API defines another | 211 | cover the whole array of pixels. The V4L2 API defines another |
302 | area called "source rectangle", which, in turn, is a subrectangle of | 212 | area called "source rectangle", which, in turn, is a subrectangle of |
303 | the active window. The SN9C10X chip is always programmed to read the | 213 | the active window. The SN9C1XX chip is always programmed to read the |
304 | source rectangle. | 214 | source rectangle. |
305 | The bounds of both the active window and the source rectangle are | 215 | The bounds of both the active window and the source rectangle are |
306 | specified in the cropcap substructures 'bounds' and 'defrect'. | 216 | specified in the cropcap substructures 'bounds' and 'defrect'. |
@@ -326,13 +236,13 @@ struct sn9c102_sensor { | |||
326 | const struct v4l2_rect* rect); | 236 | const struct v4l2_rect* rect); |
327 | /* | 237 | /* |
328 | To be called on VIDIOC_C_SETCROP. The core module always calls a | 238 | To be called on VIDIOC_C_SETCROP. The core module always calls a |
329 | default routine which configures the appropriate SN9C10X regs (also | 239 | default routine which configures the appropriate SN9C1XX regs (also |
330 | scaling), but you may need to override/adjust specific stuff. | 240 | scaling), but you may need to override/adjust specific stuff. |
331 | 'rect' contains width and height values that are multiple of 16: in | 241 | 'rect' contains width and height values that are multiple of 16: in |
332 | case you override the default function, you always have to program | 242 | case you override the default function, you always have to program |
333 | the chip to match those values; on error return the corresponding | 243 | the chip to match those values; on error return the corresponding |
334 | error code without rolling back. | 244 | error code without rolling back. |
335 | NOTE: in case, you must program the SN9C10X chip to get rid of | 245 | NOTE: in case, you must program the SN9C1XX chip to get rid of |
336 | blank pixels or blank lines at the _start_ of each line or | 246 | blank pixels or blank lines at the _start_ of each line or |
337 | frame after each HSYNC or VSYNC, so that the image starts with | 247 | frame after each HSYNC or VSYNC, so that the image starts with |
338 | real RGB data (see regs 0x12, 0x13) (having set H_SIZE and, | 248 | real RGB data (see regs 0x12, 0x13) (having set H_SIZE and, |
@@ -344,16 +254,16 @@ struct sn9c102_sensor { | |||
344 | /* | 254 | /* |
345 | What you have to define here are: 1) initial 'width' and 'height' of | 255 | What you have to define here are: 1) initial 'width' and 'height' of |
346 | the target rectangle 2) the initial 'pixelformat', which can be | 256 | the target rectangle 2) the initial 'pixelformat', which can be |
347 | either V4L2_PIX_FMT_SN9C10X (for compressed video) or | 257 | either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video) |
348 | V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the | 258 | or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate |
349 | number of bits per pixel for uncompressed video, 8 or 9 (despite the | 259 | the number of bits per pixel for uncompressed video, 8 or 9 (despite |
350 | current value of 'pixelformat'). | 260 | the current value of 'pixelformat'). |
351 | NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4 | 261 | NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4 |
352 | of cropcap.defrect.width and cropcap.defrect.height. I | 262 | of cropcap.defrect.width and cropcap.defrect.height. I |
353 | suggest 1/1. | 263 | suggest 1/1. |
354 | NOTE 2: The initial compression quality is defined by the first bit | 264 | NOTE 2: The initial compression quality is defined by the first bit |
355 | of reg 0x17 during the initialization of the image sensor. | 265 | of reg 0x17 during the initialization of the image sensor. |
356 | NOTE 3: as said above, you have to program the SN9C10X chip to get | 266 | NOTE 3: as said above, you have to program the SN9C1XX chip to get |
357 | rid of any blank pixels, so that the output of the sensor | 267 | rid of any blank pixels, so that the output of the sensor |
358 | matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). | 268 | matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). |
359 | */ | 269 | */ |
@@ -378,12 +288,12 @@ struct sn9c102_sensor { | |||
378 | /*****************************************************************************/ | 288 | /*****************************************************************************/ |
379 | 289 | ||
380 | /* Private ioctl's for control settings supported by some image sensors */ | 290 | /* Private ioctl's for control settings supported by some image sensors */ |
381 | #define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE | 291 | #define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0) |
382 | #define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 | 292 | #define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1) |
383 | #define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2 | 293 | #define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2) |
384 | #define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3 | 294 | #define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3) |
385 | #define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4 | 295 | #define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4) |
386 | #define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5 | 296 | #define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5) |
387 | #define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6 | 297 | #define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6) |
388 | 298 | ||
389 | #endif /* _SN9C102_SENSOR_H_ */ | 299 | #endif /* _SN9C102_SENSOR_H_ */ |
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c index 294eb02fbd88..90023ad63adc 100644 --- a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c +++ b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera * | 2 | * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera * |
3 | * Controllers * | 3 | * Controllers * |
4 | * * | 4 | * * |
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | 5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * |
6 | * * | 6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * | 7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * | 8 | * it under the terms of the GNU General Public License as published by * |
@@ -64,7 +64,7 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, | |||
64 | static int tas5110c1b_set_crop(struct sn9c102_device* cam, | 64 | static int tas5110c1b_set_crop(struct sn9c102_device* cam, |
65 | const struct v4l2_rect* rect) | 65 | const struct v4l2_rect* rect) |
66 | { | 66 | { |
67 | struct sn9c102_sensor* s = &tas5110c1b; | 67 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); |
68 | int err = 0; | 68 | int err = 0; |
69 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, | 69 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, |
70 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; | 70 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; |
@@ -98,6 +98,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, | |||
98 | static struct sn9c102_sensor tas5110c1b = { | 98 | static struct sn9c102_sensor tas5110c1b = { |
99 | .name = "TAS5110C1B", | 99 | .name = "TAS5110C1B", |
100 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 100 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
101 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | ||
101 | .sysfs_ops = SN9C102_I2C_WRITE, | 102 | .sysfs_ops = SN9C102_I2C_WRITE, |
102 | .frequency = SN9C102_I2C_100KHZ, | 103 | .frequency = SN9C102_I2C_100KHZ, |
103 | .interface = SN9C102_I2C_3WIRES, | 104 | .interface = SN9C102_I2C_3WIRES, |
@@ -145,6 +146,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) | |||
145 | const struct usb_device_id tas5110c1b_id_table[] = { | 146 | const struct usb_device_id tas5110c1b_id_table[] = { |
146 | { USB_DEVICE(0x0c45, 0x6001), }, | 147 | { USB_DEVICE(0x0c45, 0x6001), }, |
147 | { USB_DEVICE(0x0c45, 0x6005), }, | 148 | { USB_DEVICE(0x0c45, 0x6005), }, |
149 | { USB_DEVICE(0x0c45, 0x6007), }, | ||
148 | { USB_DEVICE(0x0c45, 0x60ab), }, | 150 | { USB_DEVICE(0x0c45, 0x60ab), }, |
149 | { } | 151 | { } |
150 | }; | 152 | }; |
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c index 9ecb09032b68..cb1b318bc1ff 100644 --- a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c +++ b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera * | 2 | * Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera * |
3 | * Controllers * | 3 | * Controllers * |
4 | * * | 4 | * * |
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | 5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * |
6 | * * | 6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * | 7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * | 8 | * it under the terms of the GNU General Public License as published by * |
@@ -65,7 +65,7 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, | |||
65 | static int tas5130d1b_set_crop(struct sn9c102_device* cam, | 65 | static int tas5130d1b_set_crop(struct sn9c102_device* cam, |
66 | const struct v4l2_rect* rect) | 66 | const struct v4l2_rect* rect) |
67 | { | 67 | { |
68 | struct sn9c102_sensor* s = &tas5130d1b; | 68 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); |
69 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, | 69 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, |
70 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; | 70 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; |
71 | int err = 0; | 71 | int err = 0; |
@@ -99,6 +99,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, | |||
99 | static struct sn9c102_sensor tas5130d1b = { | 99 | static struct sn9c102_sensor tas5130d1b = { |
100 | .name = "TAS5130D1B", | 100 | .name = "TAS5130D1B", |
101 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 101 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
102 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | ||
102 | .sysfs_ops = SN9C102_I2C_WRITE, | 103 | .sysfs_ops = SN9C102_I2C_WRITE, |
103 | .frequency = SN9C102_I2C_100KHZ, | 104 | .frequency = SN9C102_I2C_100KHZ, |
104 | .interface = SN9C102_I2C_3WIRES, | 105 | .interface = SN9C102_I2C_3WIRES, |
@@ -154,6 +155,7 @@ static struct sn9c102_sensor tas5130d1b = { | |||
154 | int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) | 155 | int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) |
155 | { | 156 | { |
156 | const struct usb_device_id tas5130d1b_id_table[] = { | 157 | const struct usb_device_id tas5130d1b_id_table[] = { |
158 | { USB_DEVICE(0x0c45, 0x6024), }, | ||
157 | { USB_DEVICE(0x0c45, 0x6025), }, | 159 | { USB_DEVICE(0x0c45, 0x6025), }, |
158 | { USB_DEVICE(0x0c45, 0x60aa), }, | 160 | { USB_DEVICE(0x0c45, 0x60aa), }, |
159 | { } | 161 | { } |