diff options
Diffstat (limited to 'drivers/usb')
57 files changed, 0 insertions, 43970 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index b1222cd4aa46..7fdbc5dad5fd 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig | |||
| @@ -87,8 +87,6 @@ source "drivers/usb/input/Kconfig" | |||
| 87 | 87 | ||
| 88 | source "drivers/usb/image/Kconfig" | 88 | source "drivers/usb/image/Kconfig" |
| 89 | 89 | ||
| 90 | source "drivers/usb/media/Kconfig" | ||
| 91 | |||
| 92 | source "drivers/usb/net/Kconfig" | 90 | source "drivers/usb/net/Kconfig" |
| 93 | 91 | ||
| 94 | source "drivers/usb/mon/Kconfig" | 92 | source "drivers/usb/mon/Kconfig" |
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index bb36a1c1dbb3..9b7d9769fdcc 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile | |||
| @@ -35,20 +35,6 @@ obj-$(CONFIG_USB_WACOM) += input/ | |||
| 35 | obj-$(CONFIG_USB_ACECAD) += input/ | 35 | obj-$(CONFIG_USB_ACECAD) += input/ |
| 36 | obj-$(CONFIG_USB_XPAD) += input/ | 36 | obj-$(CONFIG_USB_XPAD) += input/ |
| 37 | 37 | ||
| 38 | obj-$(CONFIG_USB_DABUSB) += media/ | ||
| 39 | obj-$(CONFIG_USB_DSBR) += media/ | ||
| 40 | obj-$(CONFIG_USB_ET61X251) += media/ | ||
| 41 | obj-$(CONFIG_USB_IBMCAM) += media/ | ||
| 42 | obj-$(CONFIG_USB_KONICAWC) += media/ | ||
| 43 | obj-$(CONFIG_USB_OV511) += media/ | ||
| 44 | obj-$(CONFIG_USB_PWC) += media/ | ||
| 45 | obj-$(CONFIG_USB_SE401) += media/ | ||
| 46 | obj-$(CONFIG_USB_SN9C102) += media/ | ||
| 47 | obj-$(CONFIG_USB_STV680) += media/ | ||
| 48 | obj-$(CONFIG_USB_VICAM) += media/ | ||
| 49 | obj-$(CONFIG_USB_W9968CF) += media/ | ||
| 50 | obj-$(CONFIG_USB_ZC0301) += media/ | ||
| 51 | |||
| 52 | obj-$(CONFIG_USB_CATC) += net/ | 38 | obj-$(CONFIG_USB_CATC) += net/ |
| 53 | obj-$(CONFIG_USB_KAWETH) += net/ | 39 | obj-$(CONFIG_USB_KAWETH) += net/ |
| 54 | obj-$(CONFIG_USB_PEGASUS) += net/ | 40 | obj-$(CONFIG_USB_PEGASUS) += net/ |
diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig deleted file mode 100644 index 189d40f96be5..000000000000 --- a/drivers/usb/media/Kconfig +++ /dev/null | |||
| @@ -1,241 +0,0 @@ | |||
| 1 | # | ||
| 2 | # USB Multimedia device configuration | ||
| 3 | # | ||
| 4 | comment "USB Multimedia devices" | ||
| 5 | depends on USB | ||
| 6 | |||
| 7 | config USB_DABUSB | ||
| 8 | tristate "DABUSB driver" | ||
| 9 | depends on USB | ||
| 10 | ---help--- | ||
| 11 | A Digital Audio Broadcasting (DAB) Receiver for USB and Linux | ||
| 12 | brought to you by the DAB-Team | ||
| 13 | <http://wwwbode.cs.tum.edu/Par/arch/dab/>. This driver can be taken | ||
| 14 | as an example for URB-based bulk, control, and isochronous | ||
| 15 | transactions. URB's are explained in | ||
| 16 | <file:Documentation/usb/URB.txt>. | ||
| 17 | |||
| 18 | To compile this driver as a module, choose M here: the | ||
| 19 | module will be called dabusb. | ||
| 20 | |||
| 21 | comment "Video4Linux support is needed for USB Multimedia device support" | ||
| 22 | depends on USB && VIDEO_DEV=n | ||
| 23 | |||
| 24 | config USB_VICAM | ||
| 25 | tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)" | ||
| 26 | depends on USB && VIDEO_DEV && EXPERIMENTAL | ||
| 27 | ---help--- | ||
| 28 | Say Y here if you have 3com homeconnect camera (vicam). | ||
| 29 | |||
| 30 | This driver uses the Video For Linux API. You must say Y or M to | ||
| 31 | "Video For Linux" (under Multimedia Devices) to use this driver. | ||
| 32 | Information on this API and pointers to "v4l" programs may be found | ||
| 33 | at <file:Documentation/video4linux/API.html>. | ||
| 34 | |||
| 35 | To compile this driver as a module, choose M here: the | ||
| 36 | module will be called vicam. | ||
| 37 | |||
| 38 | config USB_DSBR | ||
| 39 | tristate "D-Link USB FM radio support (EXPERIMENTAL)" | ||
| 40 | depends on USB && VIDEO_DEV && EXPERIMENTAL | ||
| 41 | ---help--- | ||
| 42 | Say Y here if you want to connect this type of radio to your | ||
| 43 | computer's USB port. Note that the audio is not digital, and | ||
| 44 | you must connect the line out connector to a sound card or a | ||
| 45 | set of speakers. | ||
| 46 | |||
| 47 | This driver uses the Video For Linux API. You must enable | ||
| 48 | (Y or M in config) Video For Linux (under Character Devices) | ||
| 49 | to use this driver. Information on this API and pointers to | ||
| 50 | "v4l" programs may be found at | ||
| 51 | <file:Documentation/video4linux/API.html>. | ||
| 52 | |||
| 53 | To compile this driver as a module, choose M here: the | ||
| 54 | module will be called dsbr100. | ||
| 55 | |||
| 56 | config USB_ET61X251 | ||
| 57 | tristate "USB ET61X[12]51 PC Camera Controller support" | ||
| 58 | depends on USB && VIDEO_DEV | ||
| 59 | ---help--- | ||
| 60 | Say Y here if you want support for cameras based on Etoms ET61X151 | ||
| 61 | or ET61X251 PC Camera Controllers. | ||
| 62 | |||
| 63 | See <file:Documentation/usb/et61x251.txt> for more informations. | ||
| 64 | |||
| 65 | This driver uses the Video For Linux API. You must say Y or M to | ||
| 66 | "Video For Linux" to use this driver. | ||
| 67 | |||
| 68 | To compile this driver as a module, choose M here: the | ||
| 69 | module will be called et61x251. | ||
| 70 | |||
| 71 | config USB_IBMCAM | ||
| 72 | tristate "USB IBM (Xirlink) C-it Camera support" | ||
| 73 | depends on USB && VIDEO_DEV | ||
| 74 | ---help--- | ||
| 75 | Say Y here if you want to connect a IBM "C-It" camera, also known as | ||
| 76 | "Xirlink PC Camera" to your computer's USB port. For more | ||
| 77 | information, read <file:Documentation/usb/ibmcam.txt>. | ||
| 78 | |||
| 79 | This driver uses the Video For Linux API. You must enable | ||
| 80 | (Y or M in config) Video For Linux (under Character Devices) | ||
| 81 | to use this driver. Information on this API and pointers to | ||
| 82 | "v4l" programs may be found at | ||
| 83 | <file:Documentation/video4linux/API.html>. | ||
| 84 | |||
| 85 | To compile this driver as a module, choose M here: the | ||
| 86 | module will be called ibmcam. | ||
| 87 | |||
| 88 | This camera has several configuration options which | ||
| 89 | can be specified when you load the module. Read | ||
| 90 | <file:Documentation/usb/ibmcam.txt> to learn more. | ||
| 91 | |||
| 92 | config USB_KONICAWC | ||
| 93 | tristate "USB Konica Webcam support" | ||
| 94 | depends on USB && VIDEO_DEV | ||
| 95 | ---help--- | ||
| 96 | Say Y here if you want support for webcams based on a Konica | ||
| 97 | chipset. This is known to work with the Intel YC76 webcam. | ||
| 98 | |||
| 99 | This driver uses the Video For Linux API. You must enable | ||
| 100 | (Y or M in config) Video For Linux (under Character Devices) | ||
| 101 | to use this driver. Information on this API and pointers to | ||
| 102 | "v4l" programs may be found at | ||
| 103 | <file:Documentation/video4linux/API.html>. | ||
| 104 | |||
| 105 | To compile this driver as a module, choose M here: the | ||
| 106 | module will be called konicawc. | ||
| 107 | |||
| 108 | config USB_OV511 | ||
| 109 | tristate "USB OV511 Camera support" | ||
| 110 | depends on USB && VIDEO_DEV | ||
| 111 | ---help--- | ||
| 112 | Say Y here if you want to connect this type of camera to your | ||
| 113 | computer's USB port. See <file:Documentation/usb/ov511.txt> for more | ||
| 114 | information and for a list of supported cameras. | ||
| 115 | |||
| 116 | This driver uses the Video For Linux API. You must say Y or M to | ||
| 117 | "Video For Linux" (under Character Devices) to use this driver. | ||
| 118 | Information on this API and pointers to "v4l" programs may be found | ||
| 119 | at <file:Documentation/video4linux/API.html>. | ||
| 120 | |||
| 121 | To compile this driver as a module, choose M here: the | ||
| 122 | module will be called ov511. | ||
| 123 | |||
| 124 | config USB_SE401 | ||
| 125 | tristate "USB SE401 Camera support" | ||
| 126 | depends on USB && VIDEO_DEV | ||
| 127 | ---help--- | ||
| 128 | Say Y here if you want to connect this type of camera to your | ||
| 129 | computer's USB port. See <file:Documentation/usb/se401.txt> for more | ||
| 130 | information and for a list of supported cameras. | ||
| 131 | |||
| 132 | This driver uses the Video For Linux API. You must say Y or M to | ||
| 133 | "Video For Linux" (under Multimedia Devices) to use this driver. | ||
| 134 | Information on this API and pointers to "v4l" programs may be found | ||
| 135 | at <file:Documentation/video4linux/API.html>. | ||
| 136 | |||
| 137 | To compile this driver as a module, choose M here: the | ||
| 138 | module will be called se401. | ||
| 139 | |||
| 140 | config USB_SN9C102 | ||
| 141 | tristate "USB SN9C10x PC Camera Controller support" | ||
| 142 | depends on USB && VIDEO_DEV | ||
| 143 | ---help--- | ||
| 144 | Say Y here if you want support for cameras based on SONiX SN9C101, | ||
| 145 | SN9C102 or SN9C103 PC Camera Controllers. | ||
| 146 | |||
| 147 | See <file:Documentation/usb/sn9c102.txt> for more informations. | ||
| 148 | |||
| 149 | This driver uses the Video For Linux API. You must say Y or M to | ||
| 150 | "Video For Linux" to use this driver. | ||
| 151 | |||
| 152 | To compile this driver as a module, choose M here: the | ||
| 153 | module will be called sn9c102. | ||
| 154 | |||
| 155 | config USB_STV680 | ||
| 156 | tristate "USB STV680 (Pencam) Camera support" | ||
| 157 | depends on USB && VIDEO_DEV | ||
| 158 | ---help--- | ||
| 159 | Say Y here if you want to connect this type of camera to your | ||
| 160 | computer's USB port. This includes the Pencam line of cameras. | ||
| 161 | See <file:Documentation/usb/stv680.txt> for more information and for | ||
| 162 | a list of supported cameras. | ||
| 163 | |||
| 164 | This driver uses the Video For Linux API. You must say Y or M to | ||
| 165 | "Video For Linux" (under Multimedia Devices) to use this driver. | ||
| 166 | Information on this API and pointers to "v4l" programs may be found | ||
| 167 | at <file:Documentation/video4linux/API.html>. | ||
| 168 | |||
| 169 | To compile this driver as a module, choose M here: the | ||
| 170 | module will be called stv680. | ||
| 171 | |||
| 172 | config USB_W9968CF | ||
| 173 | tristate "USB W996[87]CF JPEG Dual Mode Camera support" | ||
| 174 | depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP | ||
| 175 | ---help--- | ||
| 176 | Say Y here if you want support for cameras based on OV681 or | ||
| 177 | Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips. | ||
| 178 | |||
| 179 | This driver has an optional plugin, which is distributed as a | ||
| 180 | separate module only (released under GPL). It allows to use higher | ||
| 181 | resolutions and framerates, but cannot be included in the official | ||
| 182 | Linux kernel for performance purposes. | ||
| 183 | |||
| 184 | See <file:Documentation/usb/w9968cf.txt> for more informations. | ||
| 185 | |||
| 186 | This driver uses the Video For Linux and the I2C APIs. It needs the | ||
| 187 | OmniVision Camera Chip support as well. You must say Y or M to | ||
| 188 | "Video For Linux", "I2C Support" and "OmniVision Camera Chip | ||
| 189 | support" to use this driver. | ||
| 190 | |||
| 191 | To compile this driver as a module, choose M here: the | ||
| 192 | module will be called w9968cf. | ||
| 193 | |||
| 194 | config USB_ZC0301 | ||
| 195 | tristate "USB ZC0301 Image Processor and Control Chip support" | ||
| 196 | depends on USB && VIDEO_DEV | ||
| 197 | ---help--- | ||
| 198 | Say Y here if you want support for cameras based on the ZC0301 | ||
| 199 | Image Processor and Control Chip. | ||
| 200 | |||
| 201 | See <file:Documentation/usb/zc0301.txt> for more informations. | ||
| 202 | |||
| 203 | This driver uses the Video For Linux API. You must say Y or M to | ||
| 204 | "Video For Linux" to use this driver. | ||
| 205 | |||
| 206 | To compile this driver as a module, choose M here: the | ||
| 207 | module will be called zc0301. | ||
| 208 | |||
| 209 | config USB_PWC | ||
| 210 | tristate "USB Philips Cameras" | ||
| 211 | depends on USB && VIDEO_DEV | ||
| 212 | ---help--- | ||
| 213 | Say Y or M here if you want to use one of these Philips & OEM | ||
| 214 | webcams: | ||
| 215 | * Philips PCA645, PCA646 | ||
| 216 | * Philips PCVC675, PCVC680, PCVC690 | ||
| 217 | * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 | ||
| 218 | * Askey VC010 | ||
| 219 | * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' | ||
| 220 | and 'Orbit'/'Sphere' | ||
| 221 | * Samsung MPC-C10, MPC-C30 | ||
| 222 | * Creative Webcam 5, Pro Ex | ||
| 223 | * SOTEC Afina Eye | ||
| 224 | * Visionite VCS-UC300, VCS-UM100 | ||
| 225 | |||
| 226 | The PCA635, PCVC665 and PCVC720/20 are not supported by this driver | ||
| 227 | and never will be, but the 665 and 720/20 are supported by other | ||
| 228 | drivers. | ||
| 229 | |||
| 230 | See <file:Documentation/usb/philips.txt> for more information and | ||
| 231 | installation instructions. | ||
| 232 | |||
| 233 | The built-in microphone is enabled by selecting USB Audio support. | ||
| 234 | |||
| 235 | This driver uses the Video For Linux API. You must say Y or M to | ||
| 236 | "Video For Linux" (under Character Devices) to use this driver. | ||
| 237 | Information on this API and pointers to "v4l" programs may be found | ||
| 238 | at <file:Documentation/video4linux/API.html>. | ||
| 239 | |||
| 240 | To compile this driver as a module, choose M here: the | ||
| 241 | module will be called pwc. | ||
diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile deleted file mode 100644 index 50e89a33b85e..000000000000 --- a/drivers/usb/media/Makefile +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Makefile for USB Media drivers | ||
| 3 | # | ||
| 4 | |||
| 5 | sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ | ||
| 6 | sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \ | ||
| 7 | sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ | ||
| 8 | sn9c102_tas5130d1b.o | ||
| 9 | et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o | ||
| 10 | zc0301-objs := zc0301_core.o zc0301_pas202bcb.o | ||
| 11 | |||
| 12 | obj-$(CONFIG_USB_DABUSB) += dabusb.o | ||
| 13 | obj-$(CONFIG_USB_DSBR) += dsbr100.o | ||
| 14 | obj-$(CONFIG_USB_ET61X251) += et61x251.o | ||
| 15 | obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o | ||
| 16 | obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o | ||
| 17 | obj-$(CONFIG_USB_OV511) += ov511.o | ||
| 18 | obj-$(CONFIG_USB_SE401) += se401.o | ||
| 19 | obj-$(CONFIG_USB_SN9C102) += sn9c102.o | ||
| 20 | obj-$(CONFIG_USB_STV680) += stv680.o | ||
| 21 | obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o | ||
| 22 | obj-$(CONFIG_USB_W9968CF) += w9968cf.o | ||
| 23 | obj-$(CONFIG_USB_ZC0301) += zc0301.o | ||
| 24 | obj-$(CONFIG_USB_PWC) += pwc/ | ||
diff --git a/drivers/usb/media/dabfirmware.h b/drivers/usb/media/dabfirmware.h deleted file mode 100644 index d14d803566a3..000000000000 --- a/drivers/usb/media/dabfirmware.h +++ /dev/null | |||
| @@ -1,1408 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * dabdata.h - dab usb firmware and bitstream data | ||
| 3 | */ | ||
| 4 | |||
| 5 | static INTEL_HEX_RECORD firmware[] = { | ||
| 6 | |||
| 7 | { 2, 0x0000, 0, {0x21,0x57} }, | ||
| 8 | { 3, 0x0003, 0, {0x02,0x01,0x66} }, | ||
| 9 | { 3, 0x000b, 0, {0x02,0x01,0x66} }, | ||
| 10 | { 3, 0x0013, 0, {0x02,0x01,0x66} }, | ||
| 11 | { 3, 0x001b, 0, {0x02,0x01,0x66} }, | ||
| 12 | { 3, 0x0023, 0, {0x02,0x01,0x66} }, | ||
| 13 | { 3, 0x002b, 0, {0x02,0x01,0x66} }, | ||
| 14 | { 3, 0x0033, 0, {0x02,0x03,0x0f} }, | ||
| 15 | { 3, 0x003b, 0, {0x02,0x01,0x66} }, | ||
| 16 | { 3, 0x0043, 0, {0x02,0x01,0x00} }, | ||
| 17 | { 3, 0x004b, 0, {0x02,0x01,0x66} }, | ||
| 18 | { 3, 0x0053, 0, {0x02,0x01,0x66} }, | ||
| 19 | { 3, 0x005b, 0, {0x02,0x04,0xbd} }, | ||
| 20 | { 3, 0x0063, 0, {0x02,0x01,0x67} }, | ||
| 21 | { 3, 0x0100, 0, {0x02,0x0c,0x5a} }, | ||
| 22 | { 3, 0x0104, 0, {0x02,0x01,0xed} }, | ||
| 23 | { 3, 0x0108, 0, {0x02,0x02,0x51} }, | ||
| 24 | { 3, 0x010c, 0, {0x02,0x02,0x7c} }, | ||
| 25 | { 3, 0x0110, 0, {0x02,0x02,0xe4} }, | ||
| 26 | { 1, 0x0114, 0, {0x32} }, | ||
| 27 | { 1, 0x0118, 0, {0x32} }, | ||
| 28 | { 3, 0x011c, 0, {0x02,0x05,0xfd} }, | ||
| 29 | { 3, 0x0120, 0, {0x02,0x00,0x00} }, | ||
| 30 | { 3, 0x0124, 0, {0x02,0x00,0x00} }, | ||
| 31 | { 3, 0x0128, 0, {0x02,0x04,0x3c} }, | ||
| 32 | { 3, 0x012c, 0, {0x02,0x04,0x6a} }, | ||
| 33 | { 3, 0x0130, 0, {0x02,0x00,0x00} }, | ||
| 34 | { 3, 0x0134, 0, {0x02,0x00,0x00} }, | ||
| 35 | { 3, 0x0138, 0, {0x02,0x00,0x00} }, | ||
| 36 | { 3, 0x013c, 0, {0x02,0x00,0x00} }, | ||
| 37 | { 3, 0x0140, 0, {0x02,0x00,0x00} }, | ||
| 38 | { 3, 0x0144, 0, {0x02,0x00,0x00} }, | ||
| 39 | { 3, 0x0148, 0, {0x02,0x00,0x00} }, | ||
| 40 | { 3, 0x014c, 0, {0x02,0x00,0x00} }, | ||
| 41 | { 3, 0x0150, 0, {0x02,0x00,0x00} }, | ||
| 42 | { 3, 0x0154, 0, {0x02,0x00,0x00} }, | ||
| 43 | { 10, 0x0157, 0, {0x75,0x81,0x7f,0xe5,0x82,0x60,0x03,0x02,0x01,0x61} }, | ||
| 44 | { 5, 0x0161, 0, {0x12,0x07,0x6f,0x21,0x64} }, | ||
| 45 | { 1, 0x0166, 0, {0x32} }, | ||
| 46 | { 14, 0x0167, 0, {0xc0,0xd0,0xc0,0x86,0xc0,0x82,0xc0,0x83,0xc0,0xe0,0x90,0x7f,0x97,0xe0} }, | ||
| 47 | { 14, 0x0175, 0, {0x44,0x80,0xf0,0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, | ||
| 48 | { 14, 0x0183, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, | ||
| 49 | { 14, 0x0191, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x90,0x7f,0x97,0xe0} }, | ||
| 50 | { 3, 0x019f, 0, {0x55,0x7f,0xf0} }, | ||
| 51 | { 14, 0x01a2, 0, {0x90,0x7f,0x9a,0xe0,0x30,0xe4,0x23,0x90,0x7f,0x68,0xf0,0xf0,0xf0,0xf0} }, | ||
| 52 | { 14, 0x01b0, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, | ||
| 53 | { 14, 0x01be, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, | ||
| 54 | { 14, 0x01cc, 0, {0xe5,0xd8,0xc2,0xe3,0xf5,0xd8,0xd0,0xe0,0xd0,0x83,0xd0,0x82,0xd0,0x86} }, | ||
| 55 | { 3, 0x01da, 0, {0xd0,0xd0,0x32} }, | ||
| 56 | { 8, 0x01dd, 0, {0x75,0x86,0x00,0x90,0xff,0xc3,0x7c,0x05} }, | ||
| 57 | { 7, 0x01e5, 0, {0xa3,0xe5,0x82,0x45,0x83,0x70,0xf9} }, | ||
| 58 | { 1, 0x01ec, 0, {0x22} }, | ||
| 59 | { 14, 0x01ed, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0xd0} }, | ||
| 60 | { 14, 0x01fb, 0, {0x75,0xd0,0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91} }, | ||
| 61 | { 13, 0x0209, 0, {0x90,0x88,0x00,0xe0,0xf5,0x41,0x90,0x7f,0xab,0x74,0x02,0xf0,0x90} }, | ||
| 62 | { 9, 0x0216, 0, {0x7f,0xab,0x74,0x02,0xf0,0xe5,0x32,0x60,0x21} }, | ||
| 63 | { 4, 0x021f, 0, {0x7a,0x00,0x7b,0x00} }, | ||
| 64 | { 11, 0x0223, 0, {0xc3,0xea,0x94,0x18,0xeb,0x64,0x80,0x94,0x80,0x50,0x12} }, | ||
| 65 | { 14, 0x022e, 0, {0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0a,0xba,0x00} }, | ||
| 66 | { 2, 0x023c, 0, {0x01,0x0b} }, | ||
| 67 | { 2, 0x023e, 0, {0x80,0xe3} }, | ||
| 68 | { 2, 0x0240, 0, {0xd0,0x86} }, | ||
| 69 | { 14, 0x0242, 0, {0xd0,0xd0,0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0} }, | ||
| 70 | { 1, 0x0250, 0, {0x32} }, | ||
| 71 | { 14, 0x0251, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
| 72 | { 14, 0x025f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} }, | ||
| 73 | { 4, 0x026d, 0, {0x04,0xf0,0xd0,0x86} }, | ||
| 74 | { 11, 0x0271, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 75 | { 14, 0x027c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, | ||
| 76 | { 14, 0x028a, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, | ||
| 77 | { 13, 0x0298, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} }, | ||
| 78 | { 12, 0x02a5, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0x6e,0x00,0x75,0x6f,0x02,0x12} }, | ||
| 79 | { 6, 0x02b1, 0, {0x11,0x44,0x75,0x70,0x39,0x75} }, | ||
| 80 | { 6, 0x02b7, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} }, | ||
| 81 | { 12, 0x02bd, 0, {0x11,0x75,0x90,0x7f,0xd6,0xe4,0xf0,0x75,0xd8,0x20,0xd0,0x86} }, | ||
| 82 | { 14, 0x02c9, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, | ||
| 83 | { 13, 0x02d7, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 84 | { 14, 0x02e4, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
| 85 | { 14, 0x02f2, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} }, | ||
| 86 | { 4, 0x0300, 0, {0x10,0xf0,0xd0,0x86} }, | ||
| 87 | { 11, 0x0304, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 88 | { 14, 0x030f, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, | ||
| 89 | { 14, 0x031d, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, | ||
| 90 | { 12, 0x032b, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0x75,0x6e,0x00,0x75,0x6f,0x02} }, | ||
| 91 | { 7, 0x0337, 0, {0x12,0x11,0x44,0x75,0x70,0x40,0x75} }, | ||
| 92 | { 6, 0x033e, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} }, | ||
| 93 | { 14, 0x0344, 0, {0x11,0x75,0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0} }, | ||
| 94 | { 5, 0x0352, 0, {0x75,0xd8,0x10,0xd0,0x86} }, | ||
| 95 | { 14, 0x0357, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, | ||
| 96 | { 13, 0x0365, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 97 | { 13, 0x0372, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} }, | ||
| 98 | { 12, 0x037f, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x42,0xf0,0x12,0x10,0x1b,0x90} }, | ||
| 99 | { 13, 0x038b, 0, {0x7f,0xa6,0xe5,0x43,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40} }, | ||
| 100 | { 1, 0x0398, 0, {0xf0} }, | ||
| 101 | { 1, 0x0399, 0, {0x22} }, | ||
| 102 | { 13, 0x039a, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} }, | ||
| 103 | { 12, 0x03a7, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x44,0xf0,0x12,0x10,0x1b,0x90} }, | ||
| 104 | { 12, 0x03b3, 0, {0x7f,0xa6,0xe5,0x45,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0xe5} }, | ||
| 105 | { 11, 0x03bf, 0, {0x46,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40,0xf0} }, | ||
| 106 | { 1, 0x03ca, 0, {0x22} }, | ||
| 107 | { 10, 0x03cb, 0, {0x75,0x44,0x02,0x75,0x45,0x00,0x75,0x46,0x00,0x12} }, | ||
| 108 | { 9, 0x03d5, 0, {0x03,0x9a,0x75,0x42,0x03,0x75,0x43,0x00,0x12} }, | ||
| 109 | { 2, 0x03de, 0, {0x03,0x72} }, | ||
| 110 | { 1, 0x03e0, 0, {0x22} }, | ||
| 111 | { 12, 0x03e1, 0, {0x90,0x88,0x00,0xe5,0x36,0xf0,0x90,0x88,0x00,0x74,0x10,0x25} }, | ||
| 112 | { 9, 0x03ed, 0, {0x36,0xf0,0x12,0x01,0xdd,0x75,0x42,0x01,0x75} }, | ||
| 113 | { 9, 0x03f6, 0, {0x43,0x18,0x12,0x03,0x72,0x75,0x44,0x02,0x75} }, | ||
| 114 | { 9, 0x03ff, 0,{0x45,0x00,0x75,0x46,0x00,0x12,0x03,0x9a,0x75} }, | ||
| 115 | { 8, 0x0408, 0,{0x42,0x03,0x75,0x43,0x44,0x12,0x03,0x72} }, | ||
| 116 | { 1, 0x0410, 0,{0x22} }, | ||
| 117 | { 14, 0x0411, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
| 118 | { 14, 0x041f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} }, | ||
| 119 | { 4, 0x042d, 0, {0x02,0xf0,0xd0,0x86} }, | ||
| 120 | { 11, 0x0431, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 121 | { 14, 0x043c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
| 122 | { 14, 0x044a, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xa9,0x74} }, | ||
| 123 | { 7, 0x0458, 0, {0x04,0xf0,0x75,0x30,0x01,0xd0,0x86} }, | ||
| 124 | { 11, 0x045f, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 125 | { 14, 0x046a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
| 126 | { 14, 0x0478, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} }, | ||
| 127 | { 7, 0x0486, 0, {0x04,0xf0,0x75,0x31,0x01,0xd0,0x86} }, | ||
| 128 | { 11, 0x048d, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 129 | { 14, 0x0498, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
| 130 | { 12, 0x04a6, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe5,0xf5,0x91,0xd0,0x86} }, | ||
| 131 | { 11, 0x04b2, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 132 | { 14, 0x04bd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
| 133 | { 12, 0x04cb, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe7,0xf5,0x91,0xd0,0x86} }, | ||
| 134 | { 11, 0x04d7, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 135 | { 12, 0x04e2, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x20,0x90,0x7f,0x96,0xe4,0xf0} }, | ||
| 136 | { 1, 0x04ee, 0, {0x22} }, | ||
| 137 | { 7, 0x04ef, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x21} }, | ||
| 138 | { 1, 0x04f6, 0, {0x22} }, | ||
| 139 | { 14, 0x04f7, 0, {0x90,0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xe0,0xfb,0x74,0x80,0x2a,0xfa} }, | ||
| 140 | { 14, 0x0505, 0, {0x74,0x80,0x2b,0xfb,0xea,0x03,0x03,0x54,0x3f,0xfc,0xea,0xc4,0x23,0x54} }, | ||
| 141 | { 14, 0x0513, 0, {0x1f,0xfa,0x2c,0xfa,0xeb,0x03,0x03,0x54,0x3f,0xfc,0xeb,0xc4,0x23,0x54} }, | ||
| 142 | { 11, 0x0521, 0, {0x1f,0xfb,0x2c,0xfb,0x90,0x17,0x0a,0xe0,0xfc,0x60,0x02} }, | ||
| 143 | { 2, 0x052c, 0, {0x7a,0x00} }, | ||
| 144 | { 7, 0x052e, 0, {0x90,0x17,0x0c,0xe0,0xfc,0x60,0x02} }, | ||
| 145 | { 2, 0x0535, 0, {0x7b,0x00} }, | ||
| 146 | { 11, 0x0537, 0, {0xea,0x2b,0xfc,0xc3,0x13,0xf5,0x3a,0x75,0x44,0x02,0x8b} }, | ||
| 147 | { 7, 0x0542, 0, {0x45,0x8a,0x46,0x12,0x03,0x9a,0x75} }, | ||
| 148 | { 9, 0x0549, 0, {0x6e,0x08,0x75,0x6f,0x00,0x12,0x11,0x44,0x75} }, | ||
| 149 | { 4, 0x0552, 0, {0x70,0x47,0x75,0x71} }, | ||
| 150 | { 8, 0x0556, 0, {0x0c,0x75,0x72,0x02,0x12,0x11,0x75,0x85} }, | ||
| 151 | { 5, 0x055e, 0, {0x3a,0x73,0x12,0x11,0xa0} }, | ||
| 152 | { 1, 0x0563, 0, {0x22} }, | ||
| 153 | { 14, 0x0564, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} }, | ||
| 154 | { 14, 0x0572, 0, {0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xef,0xe0,0xfc} }, | ||
| 155 | { 14, 0x0580, 0, {0x33,0x95,0xe0,0xfd,0x8c,0x05,0x7c,0x00,0x90,0x7f,0xee,0xe0,0xfe,0x33} }, | ||
| 156 | { 14, 0x058e, 0, {0x95,0xe0,0xff,0xec,0x2e,0xfc,0xed,0x3f,0xfd,0x90,0x7f,0xe9,0xe0,0xfe} }, | ||
| 157 | { 5, 0x059c, 0, {0xbe,0x01,0x02,0x80,0x03} }, | ||
| 158 | { 3, 0x05a1, 0, {0x02,0x05,0xf9} }, | ||
| 159 | { 6, 0x05a4, 0, {0xbc,0x01,0x21,0xbd,0x00,0x1e} }, | ||
| 160 | { 14, 0x05aa, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfc,0xeb,0x25,0xe0,0xfd,0x2c,0x24,0x00,0xfc} }, | ||
| 161 | { 14, 0x05b8, 0, {0xe4,0x34,0x17,0xfd,0x90,0x7e,0xc0,0xe0,0xfe,0x8c,0x82,0x8d,0x83,0xf0} }, | ||
| 162 | { 2, 0x05c6, 0, {0x80,0x31} }, | ||
| 163 | { 14, 0x05c8, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfa,0xeb,0x25,0xe0,0xfb,0x2a,0xfa,0x24,0x00} }, | ||
| 164 | { 14, 0x05d6, 0, {0xfb,0xe4,0x34,0x17,0xfc,0x90,0x7e,0xc0,0xe0,0xfd,0x8b,0x82,0x8c,0x83} }, | ||
| 165 | { 14, 0x05e4, 0, {0xf0,0x74,0x01,0x2a,0x24,0x00,0xfa,0xe4,0x34,0x17,0xfb,0x90,0x7e,0xc1} }, | ||
| 166 | { 7, 0x05f2, 0, {0xe0,0xfc,0x8a,0x82,0x8b,0x83,0xf0} }, | ||
| 167 | { 3, 0x05f9, 0, {0x75,0x38,0x01} }, | ||
| 168 | { 1, 0x05fc, 0, {0x22} }, | ||
| 169 | { 14, 0x05fd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, | ||
| 170 | { 14, 0x060b, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, | ||
| 171 | { 13, 0x0619, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} }, | ||
| 172 | { 13, 0x0626, 0, {0x7f,0xaa,0x74,0x01,0xf0,0x12,0x05,0x64,0x75,0x37,0x00,0xd0,0x86} }, | ||
| 173 | { 14, 0x0633, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, | ||
| 174 | { 13, 0x0641, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 175 | { 14, 0x064e, 0, {0x90,0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xee,0xe0} }, | ||
| 176 | { 14, 0x065c, 0, {0xfc,0x33,0x95,0xe0,0xfd,0x90,0x7f,0x96,0xe0,0xfe,0x90,0x7f,0x96,0x74} }, | ||
| 177 | { 14, 0x066a, 0, {0x80,0x65,0x06,0xf0,0x90,0x7f,0x00,0x74,0x01,0xf0,0xea,0xc4,0x03,0x54} }, | ||
| 178 | { 14, 0x0678, 0, {0xf8,0xfe,0xeb,0x25,0xe0,0xfb,0x2e,0xfe,0x24,0x00,0xfb,0xe4,0x34,0x17} }, | ||
| 179 | { 14, 0x0686, 0, {0xff,0x8b,0x82,0x8f,0x83,0xe0,0xfb,0x74,0x01,0x2e,0x24,0x00,0xfe,0xe4} }, | ||
| 180 | { 14, 0x0694, 0, {0x34,0x17,0xff,0x8e,0x82,0x8f,0x83,0xe0,0xfe,0x90,0x7f,0xe9,0xe0,0xff} }, | ||
| 181 | { 3, 0x06a2, 0, {0xbf,0x81,0x0a} }, | ||
| 182 | { 10, 0x06a5, 0, {0x90,0x7f,0x00,0xeb,0xf0,0x90,0x7f,0x01,0xee,0xf0} }, | ||
| 183 | { 8, 0x06af, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x82,0x1a} }, | ||
| 184 | { 3, 0x06b7, 0, {0xba,0x01,0x0c} }, | ||
| 185 | { 12, 0x06ba, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} }, | ||
| 186 | { 11, 0x06c6, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0xb5,0xf0} }, | ||
| 187 | { 8, 0x06d1, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x83,0x1b} }, | ||
| 188 | { 3, 0x06d9, 0, {0xba,0x01,0x0d} }, | ||
| 189 | { 13, 0x06dc, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} }, | ||
| 190 | { 11, 0x06e9, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0x12,0xf0} }, | ||
| 191 | { 8, 0x06f4, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x84,0x1c} }, | ||
| 192 | { 3, 0x06fc, 0, {0xba,0x01,0x0d} }, | ||
| 193 | { 13, 0x06ff, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0c} }, | ||
| 194 | { 12, 0x070c, 0, {0x90,0x7f,0x00,0x74,0x80,0xf0,0x90,0x7f,0x01,0x74,0x01,0xf0} }, | ||
| 195 | { 5, 0x0718, 0, {0x90,0x7f,0xb5,0xec,0xf0} }, | ||
| 196 | { 1, 0x071d, 0, {0x22} }, | ||
| 197 | { 12, 0x071e, 0, {0x75,0x36,0x0d,0x90,0x88,0x00,0x74,0x1d,0xf0,0x75,0x6b,0x80} }, | ||
| 198 | { 10, 0x072a, 0, {0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} }, | ||
| 199 | { 9, 0x0734, 0, {0x6c,0x0f,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} }, | ||
| 200 | { 9, 0x073d, 0, {0x6c,0x06,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} }, | ||
| 201 | { 7, 0x0746, 0, {0x6c,0x01,0x12,0x10,0xe2,0x7a,0x00} }, | ||
| 202 | { 3, 0x074d, 0, {0xba,0xff,0x00} }, | ||
| 203 | { 2, 0x0750, 0, {0x50,0x0a} }, | ||
| 204 | { 10, 0x0752, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} }, | ||
| 205 | { 10, 0x075c, 0, {0x75,0x6b,0x80,0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75} }, | ||
| 206 | { 8, 0x0766, 0, {0x6b,0x80,0x75,0x6c,0x0f,0x12,0x10,0xe2} }, | ||
| 207 | { 1, 0x076e, 0, {0x22} }, | ||
| 208 | { 14, 0x076f, 0, {0x90,0x7f,0xa1,0xe4,0xf0,0x90,0x7f,0xaf,0x74,0x01,0xf0,0x90,0x7f,0x92} }, | ||
| 209 | { 14, 0x077d, 0, {0x74,0x02,0xf0,0x75,0x8e,0x31,0x75,0x89,0x21,0x75,0x88,0x00,0x75,0xc8} }, | ||
| 210 | { 14, 0x078b, 0, {0x00,0x75,0x8d,0x40,0x75,0x98,0x40,0x75,0xc0,0x40,0x75,0x87,0x00,0x75} }, | ||
| 211 | { 9, 0x0799, 0, {0x20,0x00,0x75,0x21,0x00,0x75,0x22,0x00,0x75} }, | ||
| 212 | { 5, 0x07a2, 0, {0x23,0x00,0x75,0x47,0x00} }, | ||
| 213 | { 7, 0x07a7, 0, {0xc3,0xe5,0x47,0x94,0x20,0x50,0x11} }, | ||
| 214 | { 13, 0x07ae, 0, {0xe5,0x47,0x24,0x00,0xf5,0x82,0xe4,0x34,0x17,0xf5,0x83,0xe4,0xf0} }, | ||
| 215 | { 4, 0x07bb, 0, {0x05,0x47,0x80,0xe8} }, | ||
| 216 | { 9, 0x07bf, 0, {0xe4,0xf5,0x40,0xf5,0x3f,0xe4,0xf5,0x3c,0xf5} }, | ||
| 217 | { 7, 0x07c8, 0, {0x3b,0xe4,0xf5,0x3e,0xf5,0x3d,0x75} }, | ||
| 218 | { 11, 0x07cf, 0, {0x32,0x00,0x75,0x37,0x00,0x75,0x39,0x00,0x90,0x7f,0x93} }, | ||
| 219 | { 14, 0x07da, 0, {0x74,0x3c,0xf0,0x90,0x7f,0x9c,0x74,0xff,0xf0,0x90,0x7f,0x96,0x74,0x80} }, | ||
| 220 | { 14, 0x07e8, 0, {0xf0,0x90,0x7f,0x94,0x74,0x70,0xf0,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} }, | ||
| 221 | { 14, 0x07f6, 0, {0x7f,0x97,0xe4,0xf0,0x90,0x7f,0x95,0x74,0xc2,0xf0,0x90,0x7f,0x98,0x74} }, | ||
| 222 | { 14, 0x0804, 0, {0x28,0xf0,0x90,0x7f,0x9e,0x74,0x28,0xf0,0x90,0x7f,0xf0,0xe4,0xf0,0x90} }, | ||
| 223 | { 14, 0x0812, 0, {0x7f,0xf1,0xe4,0xf0,0x90,0x7f,0xf2,0xe4,0xf0,0x90,0x7f,0xf3,0xe4,0xf0} }, | ||
| 224 | { 14, 0x0820, 0, {0x90,0x7f,0xf4,0xe4,0xf0,0x90,0x7f,0xf5,0xe4,0xf0,0x90,0x7f,0xf6,0xe4} }, | ||
| 225 | { 14, 0x082e, 0, {0xf0,0x90,0x7f,0xf7,0xe4,0xf0,0x90,0x7f,0xf8,0xe4,0xf0,0x90,0x7f,0xf9} }, | ||
| 226 | { 14, 0x083c, 0, {0x74,0x38,0xf0,0x90,0x7f,0xfa,0x74,0xa0,0xf0,0x90,0x7f,0xfb,0x74,0xa0} }, | ||
| 227 | { 14, 0x084a, 0, {0xf0,0x90,0x7f,0xfc,0x74,0xa0,0xf0,0x90,0x7f,0xfd,0x74,0xa0,0xf0,0x90} }, | ||
| 228 | { 14, 0x0858, 0, {0x7f,0xfe,0x74,0xa0,0xf0,0x90,0x7f,0xff,0x74,0xa0,0xf0,0x90,0x7f,0xe0} }, | ||
| 229 | { 14, 0x0866, 0, {0x74,0x03,0xf0,0x90,0x7f,0xe1,0x74,0x01,0xf0,0x90,0x7f,0xdd,0x74,0x80} }, | ||
| 230 | { 11, 0x0874, 0, {0xf0,0x12,0x12,0x43,0x12,0x07,0x1e,0x7a,0x00,0x7b,0x00} }, | ||
| 231 | { 9, 0x087f, 0, {0xc3,0xea,0x94,0x1e,0xeb,0x94,0x00,0x50,0x17} }, | ||
| 232 | { 12, 0x0888, 0, {0x90,0x88,0x00,0xe0,0xf5,0x47,0x90,0x88,0x0b,0xe0,0xf5,0x47} }, | ||
| 233 | { 9, 0x0894, 0, {0x90,0x7f,0x68,0xf0,0x0a,0xba,0x00,0x01,0x0b} }, | ||
| 234 | { 2, 0x089d, 0, {0x80,0xe0} }, | ||
| 235 | { 12, 0x089f, 0, {0x12,0x03,0xe1,0x90,0x7f,0xd6,0xe4,0xf0,0x7a,0x00,0x7b,0x00} }, | ||
| 236 | { 13, 0x08ab, 0, {0x8a,0x04,0x8b,0x05,0xc3,0xea,0x94,0xe0,0xeb,0x94,0x2e,0x50,0x1a} }, | ||
| 237 | { 14, 0x08b8, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} }, | ||
| 238 | { 10, 0x08c6, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} }, | ||
| 239 | { 2, 0x08d0, 0, {0x80,0xd9} }, | ||
| 240 | { 13, 0x08d2, 0, {0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0,0x90} }, | ||
| 241 | { 14, 0x08df, 0, {0x7f,0xde,0x74,0x05,0xf0,0x90,0x7f,0xdf,0x74,0x05,0xf0,0x90,0x7f,0xac} }, | ||
| 242 | { 14, 0x08ed, 0, {0xe4,0xf0,0x90,0x7f,0xad,0x74,0x05,0xf0,0x75,0xa8,0x80,0x75,0xf8,0x10} }, | ||
| 243 | { 13, 0x08fb, 0, {0x90,0x7f,0xae,0x74,0x0b,0xf0,0x90,0x7f,0xe2,0x74,0x88,0xf0,0x90} }, | ||
| 244 | { 12, 0x0908, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0xe8,0x11,0x75,0x32,0x01,0x75} }, | ||
| 245 | { 12, 0x0914, 0, {0x31,0x00,0x75,0x30,0x00,0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7} }, | ||
| 246 | { 10, 0x0920, 0, {0xd0,0x05,0xd0,0x04,0x75,0x34,0x00,0x75,0x35,0x01} }, | ||
| 247 | { 13, 0x092a, 0, {0x90,0x7f,0xae,0x74,0x03,0xf0,0x8c,0x02,0xba,0x00,0x02,0x80,0x03} }, | ||
| 248 | { 3, 0x0937, 0, {0x02,0x0a,0x3f} }, | ||
| 249 | { 12, 0x093a, 0, {0x85,0x33,0x34,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90,0x7f,0x97} }, | ||
| 250 | { 14, 0x0946, 0, {0x74,0x08,0xf0,0x90,0x7f,0x9d,0x74,0x88,0xf0,0x90,0x7f,0x9a,0xe0,0xfa} }, | ||
| 251 | { 12, 0x0954, 0, {0x74,0x05,0x5a,0xf5,0x33,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} }, | ||
| 252 | { 13, 0x0960, 0, {0x7f,0x97,0x74,0x02,0xf0,0x90,0x7f,0x9d,0x74,0x82,0xf0,0xe5,0x33} }, | ||
| 253 | { 13, 0x096d, 0, {0x25,0xe0,0xfa,0x90,0x7f,0x9a,0xe0,0x54,0x05,0xfb,0x4a,0xf5,0x33} }, | ||
| 254 | { 2, 0x097a, 0, {0x60,0x0c} }, | ||
| 255 | { 12, 0x097c, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x4a,0xf0} }, | ||
| 256 | { 11, 0x0988, 0, {0x75,0x6e,0x00,0x75,0x6f,0x00,0xc0,0x04,0xc0,0x05,0x12} }, | ||
| 257 | { 14, 0x0993, 0, {0x11,0x44,0xd0,0x05,0xd0,0x04,0x90,0x17,0x13,0xe0,0xfa,0x74,0x80,0x2a} }, | ||
| 258 | { 6, 0x09a1, 0, {0xfa,0xe5,0x33,0xb4,0x04,0x29} }, | ||
| 259 | { 3, 0x09a7, 0, {0xba,0xa0,0x00} }, | ||
| 260 | { 2, 0x09aa, 0, {0x50,0x24} }, | ||
| 261 | { 13, 0x09ac, 0, {0x90,0x17,0x13,0xe0,0x04,0xfb,0x0b,0x90,0x17,0x13,0xeb,0xf0,0x90} }, | ||
| 262 | { 14, 0x09b9, 0, {0x17,0x13,0xe0,0xfb,0x90,0x17,0x15,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05} }, | ||
| 263 | { 9, 0x09c7, 0, {0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02} }, | ||
| 264 | { 5, 0x09d0, 0, {0xe5,0x33,0xb4,0x02,0x26} }, | ||
| 265 | { 6, 0x09d5, 0, {0xc3,0x74,0x04,0x9a,0x50,0x20} }, | ||
| 266 | { 13, 0x09db, 0, {0x90,0x17,0x13,0xe0,0xfa,0x1a,0x1a,0x90,0x17,0x13,0xea,0xf0,0x90} }, | ||
| 267 | { 13, 0x09e8, 0, {0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xf0,0xc0,0x04,0xc0,0x05,0x12} }, | ||
| 268 | { 6, 0x09f5, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04} }, | ||
| 269 | { 5, 0x09fb, 0, {0xe5,0x33,0xb4,0x08,0x1d} }, | ||
| 270 | { 4, 0x0a00, 0, {0xe5,0x34,0x70,0x19} }, | ||
| 271 | { 10, 0x0a04, 0, {0x74,0x01,0x25,0x35,0x54,0x0f,0xf5,0x35,0x85,0x35} }, | ||
| 272 | { 12, 0x0a0e, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} }, | ||
| 273 | { 3, 0x0a1a, 0, {0x05,0xd0,0x04} }, | ||
| 274 | { 5, 0x0a1d, 0, {0xe5,0x33,0xb4,0x01,0x1d} }, | ||
| 275 | { 4, 0x0a22, 0, {0xe5,0x34,0x70,0x19} }, | ||
| 276 | { 10, 0x0a26, 0, {0xe5,0x35,0x24,0xff,0x54,0x0f,0xf5,0x35,0x85,0x35} }, | ||
| 277 | { 12, 0x0a30, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} }, | ||
| 278 | { 3, 0x0a3c, 0, {0x05,0xd0,0x04} }, | ||
| 279 | { 14, 0x0a3f, 0, {0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0,0x04,0x90,0x7f,0x96} }, | ||
| 280 | { 14, 0x0a4d, 0, {0xe0,0xfa,0x90,0x7f,0x96,0x74,0x7f,0x5a,0xf0,0x90,0x7f,0x97,0x74,0x08} }, | ||
| 281 | { 10, 0x0a5b, 0, {0xf0,0xc3,0xec,0x94,0x00,0xed,0x94,0x02,0x40,0x08} }, | ||
| 282 | { 8, 0x0a65, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x20,0xe6,0x08} }, | ||
| 283 | { 8, 0x0a6d, 0, {0xc3,0xe4,0x9c,0x74,0x08,0x9d,0x50,0x13} }, | ||
| 284 | { 14, 0x0a75, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x40,0x65,0x02,0xf0,0x7c} }, | ||
| 285 | { 5, 0x0a83, 0, {0x00,0x7d,0x00,0x80,0x05} }, | ||
| 286 | { 5, 0x0a88, 0, {0x0c,0xbc,0x00,0x01,0x0d} }, | ||
| 287 | { 5, 0x0a8d, 0, {0xe5,0x38,0xb4,0x01,0x0e} }, | ||
| 288 | { 13, 0x0a92, 0, {0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0x75,0x38} }, | ||
| 289 | { 1, 0x0a9f, 0, {0x00} }, | ||
| 290 | { 7, 0x0aa0, 0, {0xe5,0x31,0x70,0x03,0x02,0x09,0x2a} }, | ||
| 291 | { 10, 0x0aa7, 0, {0x90,0x7f,0xc9,0xe0,0xfa,0x70,0x03,0x02,0x0c,0x2d} }, | ||
| 292 | { 14, 0x0ab1, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} }, | ||
| 293 | { 9, 0x0abf, 0, {0x7d,0xc0,0xe0,0xfa,0xba,0x2c,0x02,0x80,0x03} }, | ||
| 294 | { 3, 0x0ac8, 0, {0x02,0x0b,0x36} }, | ||
| 295 | { 5, 0x0acb, 0, {0x75,0x32,0x00,0x7b,0x00} }, | ||
| 296 | { 3, 0x0ad0, 0, {0xbb,0x64,0x00} }, | ||
| 297 | { 2, 0x0ad3, 0, {0x50,0x1c} }, | ||
| 298 | { 14, 0x0ad5, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} }, | ||
| 299 | { 13, 0x0ae3, 0, {0x04,0xd0,0x03,0xd0,0x02,0x90,0x88,0x0f,0xe0,0xf5,0x47,0x0b,0x80} }, | ||
| 300 | { 1, 0x0af0, 0, {0xdf} }, | ||
| 301 | { 13, 0x0af1, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x07,0x1e,0x12,0x03,0xe1,0x12} }, | ||
| 302 | { 12, 0x0afe, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x75,0x6e,0x00,0x75} }, | ||
| 303 | { 13, 0x0b0a, 0, {0x6f,0x01,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0x44,0xd0,0x05} }, | ||
| 304 | { 9, 0x0b17, 0, {0xd0,0x04,0xd0,0x02,0x75,0x70,0x4d,0x75,0x71} }, | ||
| 305 | { 11, 0x0b20, 0, {0x0c,0x75,0x72,0x02,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} }, | ||
| 306 | { 11, 0x0b2b, 0, {0x11,0x75,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x02,0x0c,0x2d} }, | ||
| 307 | { 3, 0x0b36, 0, {0xba,0x2a,0x3b} }, | ||
| 308 | { 13, 0x0b39, 0, {0x90,0x7f,0x98,0x74,0x20,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} }, | ||
| 309 | { 14, 0x0b46, 0, {0x01,0xdd,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x90,0x7f,0x98,0x74,0x28,0xf0} }, | ||
| 310 | { 2, 0x0b54, 0, {0x7b,0x00} }, | ||
| 311 | { 3, 0x0b56, 0, {0xbb,0x0a,0x00} }, | ||
| 312 | { 5, 0x0b59, 0, {0x40,0x03,0x02,0x0c,0x2d} }, | ||
| 313 | { 14, 0x0b5e, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} }, | ||
| 314 | { 8, 0x0b6c, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0b,0x80,0xe2} }, | ||
| 315 | { 3, 0x0b74, 0, {0xba,0x2b,0x1a} }, | ||
| 316 | { 8, 0x0b77, 0, {0x90,0x7f,0xc9,0xe0,0xfb,0xbb,0x40,0x12} }, | ||
| 317 | { 14, 0x0b7f, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x12,0x05,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
| 318 | { 4, 0x0b8d, 0, {0x02,0x02,0x0c,0x2d} }, | ||
| 319 | { 3, 0x0b91, 0, {0xba,0x10,0x1f} }, | ||
| 320 | { 14, 0x0b94, 0, {0x90,0x7f,0x96,0xe0,0xfb,0x90,0x7f,0x96,0x74,0x80,0x65,0x03,0xf0,0xc0} }, | ||
| 321 | { 14, 0x0ba2, 0, {0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x3d,0xd0,0x05,0xd0,0x04,0xd0,0x02} }, | ||
| 322 | { 3, 0x0bb0, 0, {0x02,0x0c,0x2d} }, | ||
| 323 | { 3, 0x0bb3, 0, {0xba,0x11,0x12} }, | ||
| 324 | { 14, 0x0bb6, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x6a,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
| 325 | { 4, 0x0bc4, 0, {0x02,0x02,0x0c,0x2d} }, | ||
| 326 | { 3, 0x0bc8, 0, {0xba,0x12,0x12} }, | ||
| 327 | { 14, 0x0bcb, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x8f,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
| 328 | { 4, 0x0bd9, 0, {0x02,0x02,0x0c,0x2d} }, | ||
| 329 | { 3, 0x0bdd, 0, {0xba,0x13,0x0b} }, | ||
| 330 | { 11, 0x0be0, 0, {0x90,0x7d,0xc1,0xe0,0xfb,0x90,0x88,0x00,0xf0,0x80,0x42} }, | ||
| 331 | { 3, 0x0beb, 0, {0xba,0x14,0x11} }, | ||
| 332 | { 14, 0x0bee, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0xdd,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
| 333 | { 3, 0x0bfc, 0, {0x02,0x80,0x2e} }, | ||
| 334 | { 3, 0x0bff, 0, {0xba,0x15,0x1d} }, | ||
| 335 | { 12, 0x0c02, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x75,0x90,0x7d,0xc2,0xe0,0xf5,0x76} }, | ||
| 336 | { 14, 0x0c0e, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
| 337 | { 3, 0x0c1c, 0, {0x02,0x80,0x0e} }, | ||
| 338 | { 3, 0x0c1f, 0, {0xba,0x16,0x0b} }, | ||
| 339 | { 11, 0x0c22, 0, {0xc0,0x04,0xc0,0x05,0x12,0x13,0xa3,0xd0,0x05,0xd0,0x04} }, | ||
| 340 | { 11, 0x0c2d, 0, {0x90,0x7f,0xc9,0xe4,0xf0,0x75,0x31,0x00,0x02,0x09,0x2a} }, | ||
| 341 | { 1, 0x0c38, 0, {0x22} }, | ||
| 342 | { 7, 0x0c39, 0, {0x53,0x55,0x50,0x45,0x4e,0x44,0x00} }, | ||
| 343 | { 7, 0x0c40, 0, {0x52,0x45,0x53,0x55,0x4d,0x45,0x00} }, | ||
| 344 | { 6, 0x0c47, 0, {0x20,0x56,0x6f,0x6c,0x20,0x00} }, | ||
| 345 | { 13, 0x0c4d, 0, {0x44,0x41,0x42,0x55,0x53,0x42,0x20,0x76,0x31,0x2e,0x30,0x30,0x00} }, | ||
| 346 | { 14, 0x0c5a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, | ||
| 347 | { 14, 0x0c68, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, | ||
| 348 | { 13, 0x0c76, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} }, | ||
| 349 | { 14, 0x0c83, 0, {0x7f,0xab,0x74,0x01,0xf0,0x90,0x7f,0xe8,0xe0,0xfa,0x90,0x7f,0xe9,0xe0} }, | ||
| 350 | { 6, 0x0c91, 0, {0xfb,0xbb,0x00,0x02,0x80,0x03} }, | ||
| 351 | { 3, 0x0c97, 0, {0x02,0x0d,0x38} }, | ||
| 352 | { 3, 0x0c9a, 0, {0xba,0x80,0x14} }, | ||
| 353 | { 14, 0x0c9d, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5} }, | ||
| 354 | { 6, 0x0cab, 0, {0x74,0x02,0xf0,0x02,0x0e,0xcd} }, | ||
| 355 | { 5, 0x0cb1, 0, {0xba,0x82,0x02,0x80,0x03} }, | ||
| 356 | { 3, 0x0cb6, 0, {0x02,0x0d,0x1d} }, | ||
| 357 | { 8, 0x0cb9, 0, {0x90,0x7f,0xec,0xe0,0xfc,0xbc,0x01,0x00} }, | ||
| 358 | { 2, 0x0cc1, 0, {0x40,0x21} }, | ||
| 359 | { 6, 0x0cc3, 0, {0xc3,0x74,0x07,0x9c,0x40,0x1b} }, | ||
| 360 | { 14, 0x0cc9, 0, {0xec,0x24,0xff,0x25,0xe0,0xfd,0x24,0xc6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} }, | ||
| 361 | { 13, 0x0cd7, 0, {0x83,0xe0,0xfd,0x53,0x05,0x01,0x90,0x7f,0x00,0xed,0xf0,0x80,0x2b} }, | ||
| 362 | { 3, 0x0ce4, 0, {0xbc,0x81,0x00} }, | ||
| 363 | { 2, 0x0ce7, 0, {0x40,0x21} }, | ||
| 364 | { 6, 0x0ce9, 0, {0xc3,0x74,0x87,0x9c,0x40,0x1b} }, | ||
| 365 | { 14, 0x0cef, 0, {0xec,0x24,0x7f,0x25,0xe0,0xfc,0x24,0xb6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} }, | ||
| 366 | { 13, 0x0cfd, 0, {0x83,0xe0,0xfc,0x53,0x04,0x01,0x90,0x7f,0x00,0xec,0xf0,0x80,0x05} }, | ||
| 367 | { 5, 0x0d0a, 0, {0x90,0x7f,0x00,0xe4,0xf0} }, | ||
| 368 | { 14, 0x0d0f, 0, {0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x02,0x0e,0xcd} }, | ||
| 369 | { 5, 0x0d1d, 0, {0xba,0x81,0x02,0x80,0x03} }, | ||
| 370 | { 3, 0x0d22, 0, {0x02,0x0e,0xc5} }, | ||
| 371 | { 14, 0x0d25, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74} }, | ||
| 372 | { 5, 0x0d33, 0, {0x02,0xf0,0x02,0x0e,0xcd} }, | ||
| 373 | { 3, 0x0d38, 0, {0xbb,0x01,0x2d} }, | ||
| 374 | { 6, 0x0d3b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} }, | ||
| 375 | { 3, 0x0d41, 0, {0xba,0x02,0x11} }, | ||
| 376 | { 13, 0x0d44, 0, {0x75,0x59,0x00,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} }, | ||
| 377 | { 4, 0x0d51, 0, {0x02,0x02,0x0e,0xcd} }, | ||
| 378 | { 5, 0x0d55, 0, {0xba,0x21,0x02,0x80,0x03} }, | ||
| 379 | { 3, 0x0d5a, 0, {0x02,0x0e,0xcd} }, | ||
| 380 | { 11, 0x0d5d, 0, {0x75,0x37,0x01,0x90,0x7f,0xc5,0xe4,0xf0,0x02,0x0e,0xcd} }, | ||
| 381 | { 3, 0x0d68, 0, {0xbb,0x03,0x1f} }, | ||
| 382 | { 6, 0x0d6b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} }, | ||
| 383 | { 5, 0x0d71, 0, {0xba,0x02,0x02,0x80,0x03} }, | ||
| 384 | { 3, 0x0d76, 0, {0x02,0x0e,0xcd} }, | ||
| 385 | { 13, 0x0d79, 0, {0x75,0x59,0x01,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} }, | ||
| 386 | { 4, 0x0d86, 0, {0x02,0x02,0x0e,0xcd} }, | ||
| 387 | { 3, 0x0d8a, 0, {0xbb,0x06,0x54} }, | ||
| 388 | { 5, 0x0d8d, 0, {0xba,0x80,0x02,0x80,0x03} }, | ||
| 389 | { 3, 0x0d92, 0, {0x02,0x0e,0xc5} }, | ||
| 390 | { 8, 0x0d95, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x01,0x15} }, | ||
| 391 | { 12, 0x0d9d, 0, {0x7c,0xfb,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} }, | ||
| 392 | { 9, 0x0da9, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} }, | ||
| 393 | { 10, 0x0db2, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x02,0x02,0x80,0x03} }, | ||
| 394 | { 3, 0x0dbc, 0, {0x02,0x0e,0xc5} }, | ||
| 395 | { 10, 0x0dbf, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x02,0x80,0x03} }, | ||
| 396 | { 3, 0x0dc9, 0, {0x02,0x0e,0xc5} }, | ||
| 397 | { 12, 0x0dcc, 0, {0x7c,0x3b,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} }, | ||
| 398 | { 9, 0x0dd8, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} }, | ||
| 399 | { 6, 0x0de1, 0, {0xbb,0x07,0x03,0x02,0x0e,0xc5} }, | ||
| 400 | { 3, 0x0de7, 0, {0xbb,0x08,0x10} }, | ||
| 401 | { 13, 0x0dea, 0, {0xac,0x48,0x90,0x7f,0x00,0xec,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} }, | ||
| 402 | { 3, 0x0df7, 0, {0x02,0x0e,0xcd} }, | ||
| 403 | { 3, 0x0dfa, 0, {0xbb,0x09,0x31} }, | ||
| 404 | { 5, 0x0dfd, 0, {0xba,0x00,0x02,0x80,0x03} }, | ||
| 405 | { 3, 0x0e02, 0, {0x02,0x0e,0xc5} }, | ||
| 406 | { 14, 0x0e05, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xc3,0x74,0x01,0x9c,0x50,0x03,0x02,0x0e,0xc5} }, | ||
| 407 | { 8, 0x0e13, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x0a} }, | ||
| 408 | { 10, 0x0e1b, 0, {0x90,0x17,0x21,0xe4,0xf0,0x90,0x17,0x22,0xe4,0xf0} }, | ||
| 409 | { 9, 0x0e25, 0, {0x90,0x7f,0xea,0xe0,0xf5,0x48,0x02,0x0e,0xcd} }, | ||
| 410 | { 3, 0x0e2e, 0, {0xbb,0x0a,0x27} }, | ||
| 411 | { 5, 0x0e31, 0, {0xba,0x81,0x02,0x80,0x03} }, | ||
| 412 | { 3, 0x0e36, 0, {0x02,0x0e,0xc5} }, | ||
| 413 | { 14, 0x0e39, 0, {0x90,0x7f,0xec,0xe0,0xfa,0x24,0x20,0xfa,0xe4,0x34,0x17,0xfc,0x8a,0x82} }, | ||
| 414 | { 14, 0x0e47, 0, {0x8c,0x83,0xe0,0xfa,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} }, | ||
| 415 | { 3, 0x0e55, 0, {0x02,0x0e,0xcd} }, | ||
| 416 | { 5, 0x0e58, 0, {0xbb,0x0b,0x02,0x80,0x03} }, | ||
| 417 | { 3, 0x0e5d, 0, {0x02,0x0e,0xa9} }, | ||
| 418 | { 13, 0x0e60, 0, {0x90,0x17,0x20,0xe4,0xf0,0x90,0x7f,0xec,0xe0,0xfa,0xba,0x01,0x1a} }, | ||
| 419 | { 8, 0x0e6d, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x12} }, | ||
| 420 | { 14, 0x0e75, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x90,0x17,0x21,0xf0,0xc0,0x03,0x12,0x04,0xe2} }, | ||
| 421 | { 4, 0x0e83, 0, {0xd0,0x03,0x80,0x46} }, | ||
| 422 | { 8, 0x0e87, 0, {0x90,0x7f,0xec,0xe0,0xfa,0xba,0x02,0x3e} }, | ||
| 423 | { 8, 0x0e8f, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x36} }, | ||
| 424 | { 13, 0x0e97, 0, {0xc0,0x03,0x12,0x04,0xef,0xd0,0x03,0x90,0x7f,0xea,0xe0,0xfa,0x90} }, | ||
| 425 | { 5, 0x0ea4, 0, {0x17,0x22,0xf0,0x80,0x24} }, | ||
| 426 | { 5, 0x0ea9, 0, {0xbb,0x12,0x02,0x80,0x17} }, | ||
| 427 | { 5, 0x0eae, 0, {0xbb,0x81,0x02,0x80,0x0d} }, | ||
| 428 | { 5, 0x0eb3, 0, {0xbb,0x83,0x02,0x80,0x08} }, | ||
| 429 | { 5, 0x0eb8, 0, {0xbb,0x82,0x02,0x80,0x03} }, | ||
| 430 | { 3, 0x0ebd, 0, {0xbb,0x84,0x05} }, | ||
| 431 | { 5, 0x0ec0, 0, {0x12,0x06,0x4e,0x80,0x08} }, | ||
| 432 | { 8, 0x0ec5, 0, {0x90,0x7f,0xb4,0x74,0x03,0xf0,0x80,0x06} }, | ||
| 433 | { 6, 0x0ecd, 0, {0x90,0x7f,0xb4,0x74,0x02,0xf0} }, | ||
| 434 | { 2, 0x0ed3, 0, {0xd0,0x86} }, | ||
| 435 | { 14, 0x0ed5, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, | ||
| 436 | { 13, 0x0ee3, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
| 437 | { 11, 0x0ef0, 0, {0x90,0x7f,0xec,0xe0,0xf5,0x5a,0xc3,0x94,0x01,0x40,0x1d} }, | ||
| 438 | { 7, 0x0efb, 0, {0xc3,0x74,0x07,0x95,0x5a,0x40,0x16} }, | ||
| 439 | { 13, 0x0f02, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xc6,0xf5,0x82,0xe4,0x34} }, | ||
| 440 | { 9, 0x0f0f, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0,0x80,0x22} }, | ||
| 441 | { 7, 0x0f18, 0, {0xc3,0xe5,0x5a,0x94,0x81,0x40,0x1b} }, | ||
| 442 | { 7, 0x0f1f, 0, {0xc3,0x74,0x87,0x95,0x5a,0x40,0x14} }, | ||
| 443 | { 13, 0x0f26, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xb6,0xf5,0x82,0xe4,0x34} }, | ||
| 444 | { 7, 0x0f33, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0} }, | ||
| 445 | { 1, 0x0f3a, 0, {0x22} }, | ||
| 446 | { 14, 0x0f3b, 0, {0x09,0x02,0xba,0x00,0x03,0x01,0x00,0x40,0x00,0x09,0x04,0x00,0x00,0x00} }, | ||
| 447 | { 14, 0x0f49, 0, {0x01,0x01,0x00,0x00,0x09,0x24,0x01,0x00,0x01,0x3d,0x00,0x01,0x01,0x0c} }, | ||
| 448 | { 14, 0x0f57, 0, {0x24,0x02,0x01,0x10,0x07,0x00,0x02,0x03,0x00,0x00,0x00,0x0d,0x24,0x06} }, | ||
| 449 | { 14, 0x0f65, 0, {0x03,0x01,0x02,0x15,0x00,0x03,0x00,0x03,0x00,0x00,0x09,0x24,0x03,0x02} }, | ||
| 450 | { 14, 0x0f73, 0, {0x01,0x01,0x00,0x01,0x00,0x09,0x24,0x03,0x04,0x02,0x03,0x00,0x03,0x00} }, | ||
| 451 | { 14, 0x0f81, 0, {0x09,0x24,0x03,0x05,0x03,0x06,0x00,0x01,0x00,0x09,0x04,0x01,0x00,0x00} }, | ||
| 452 | { 14, 0x0f8f, 0, {0x01,0x02,0x00,0x00,0x09,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00,0x07} }, | ||
| 453 | { 14, 0x0f9d, 0, {0x24,0x01,0x02,0x01,0x01,0x00,0x0b,0x24,0x02,0x01,0x02,0x02,0x10,0x01} }, | ||
| 454 | { 14, 0x0fab, 0, {0x80,0xbb,0x00,0x09,0x05,0x88,0x05,0x00,0x01,0x01,0x00,0x00,0x07,0x25} }, | ||
| 455 | { 14, 0x0fb9, 0, {0x01,0x00,0x00,0x00,0x00,0x09,0x04,0x02,0x00,0x02,0x00,0x00,0x00,0x00} }, | ||
| 456 | { 14, 0x0fc7, 0, {0x07,0x05,0x82,0x02,0x40,0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00} }, | ||
| 457 | { 14, 0x0fd5, 0, {0x09,0x04,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x07,0x05,0x82,0x02,0x40} }, | ||
| 458 | { 14, 0x0fe3, 0, {0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00,0x09,0x05,0x89,0x05,0xa0} }, | ||
| 459 | { 10, 0x0ff1, 0, {0x01,0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00} }, | ||
| 460 | { 14, 0x0ffb, 0, {0x12,0x01,0x00,0x01,0x00,0x00,0x00,0x40,0x47,0x05,0x99,0x99,0x00,0x01} }, | ||
| 461 | { 14, 0x1009, 0, {0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x02,0xba} }, | ||
| 462 | { 4, 0x1017, 0, {0x00,0x03,0x01,0x00} }, | ||
| 463 | { 2, 0x101b, 0, {0x7a,0x00} }, | ||
| 464 | { 3, 0x101d, 0, {0xba,0x05,0x00} }, | ||
| 465 | { 2, 0x1020, 0, {0x50,0x17} }, | ||
| 466 | { 8, 0x1022, 0, {0x90,0x7f,0xa5,0xe0,0xfb,0x30,0xe0,0x05} }, | ||
| 467 | { 5, 0x102a, 0, {0x90,0x00,0x01,0x80,0x0d} }, | ||
| 468 | { 10, 0x102f, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xe4} }, | ||
| 469 | { 3, 0x1039, 0, {0x90,0x00,0x01} }, | ||
| 470 | { 1, 0x103c, 0, {0x22} }, | ||
| 471 | { 14, 0x103d, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0x00,0x7d} }, | ||
| 472 | { 4, 0x104b, 0, {0x7e,0xeb,0x60,0x12} }, | ||
| 473 | { 14, 0x104f, 0, {0x89,0x82,0x8a,0x83,0xe0,0xa3,0xa9,0x82,0xaa,0x83,0x8c,0x82,0x8d,0x83} }, | ||
| 474 | { 4, 0x105d, 0, {0xf0,0x0c,0xdb,0xee} }, | ||
| 475 | { 8, 0x1061, 0, {0x90,0x7d,0xc3,0xe0,0x90,0x7f,0xb9,0xf0} }, | ||
| 476 | { 1, 0x1069, 0, {0x22} }, | ||
| 477 | { 14, 0x106a, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0xc4,0x7d} }, | ||
| 478 | { 4, 0x1078, 0, {0x7d,0xeb,0x60,0xe5} }, | ||
| 479 | { 14, 0x107c, 0, {0x8c,0x82,0x8d,0x83,0xe0,0x0c,0x89,0x82,0x8a,0x83,0xf0,0xa3,0xa9,0x82} }, | ||
| 480 | { 4, 0x108a, 0, {0xaa,0x83,0xdb,0xee} }, | ||
| 481 | { 1, 0x108e, 0, {0x22} }, | ||
| 482 | { 14, 0x108f, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x05,0x86,0x90,0x7d,0xc1,0xe0,0x05,0x86} }, | ||
| 483 | { 14, 0x109d, 0, {0xa3,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0x05,0x86,0xa3,0xa3,0xe0,0xf9} }, | ||
| 484 | { 5, 0x10ab, 0, {0x60,0x16,0xa3,0x05,0x86} }, | ||
| 485 | { 13, 0x10b0, 0, {0x90,0x7f,0xa6,0x05,0x86,0xe0,0xa3,0x05,0x86,0xf0,0xc0,0x01,0x12} }, | ||
| 486 | { 6, 0x10bd, 0, {0x10,0x1b,0xd0,0x01,0xd9,0xed} }, | ||
| 487 | { 6, 0x10c3, 0, {0x90,0x7f,0xa5,0x74,0x40,0xf0} }, | ||
| 488 | { 1, 0x10c9, 0, {0x22} }, | ||
| 489 | { 8, 0x10ca, 0, {0x90,0x88,0x02,0x74,0x01,0xf0,0x7a,0x00} }, | ||
| 490 | { 3, 0x10d2, 0, {0xba,0xff,0x00} }, | ||
| 491 | { 2, 0x10d5, 0, {0x50,0x0a} }, | ||
| 492 | { 10, 0x10d7, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} }, | ||
| 493 | { 1, 0x10e1, 0, {0x22} }, | ||
| 494 | { 5, 0x10e2, 0, {0xe5,0x6b,0xb4,0xc0,0x08} }, | ||
| 495 | { 8, 0x10e7, 0, {0x90,0x88,0x03,0xe5,0x6c,0xf0,0x80,0x06} }, | ||
| 496 | { 6, 0x10ef, 0, {0x90,0x88,0x02,0xe5,0x6c,0xf0} }, | ||
| 497 | { 4, 0x10f5, 0, {0x7a,0x00,0x7b,0x00} }, | ||
| 498 | { 11, 0x10f9, 0, {0xc3,0xea,0x94,0x32,0xeb,0x64,0x80,0x94,0x80,0x50,0x07} }, | ||
| 499 | { 5, 0x1104, 0, {0x0a,0xba,0x00,0x01,0x0b} }, | ||
| 500 | { 2, 0x1109, 0, {0x80,0xee} }, | ||
| 501 | { 1, 0x110b, 0, {0x22} }, | ||
| 502 | { 10, 0x110c, 0, {0x90,0x88,0x03,0xe5,0x6d,0xf0,0x05,0x39,0x7a,0x00} }, | ||
| 503 | { 3, 0x1116, 0, {0xba,0x28,0x00} }, | ||
| 504 | { 2, 0x1119, 0, {0x50,0x03} }, | ||
| 505 | { 3, 0x111b, 0, {0x0a,0x80,0xf8} }, | ||
| 506 | { 5, 0x111e, 0, {0xe5,0x39,0xb4,0x10,0x08} }, | ||
| 507 | { 8, 0x1123, 0, {0x90,0x88,0x02,0x74,0xc0,0xf0,0x80,0x0e} }, | ||
| 508 | { 5, 0x112b, 0, {0xe5,0x39,0xb4,0x20,0x09} }, | ||
| 509 | { 9, 0x1130, 0, {0x90,0x88,0x02,0x74,0x80,0xf0,0x75,0x39,0x00} }, | ||
| 510 | { 2, 0x1139, 0, {0x7a,0x00} }, | ||
| 511 | { 3, 0x113b, 0, {0xba,0x28,0x00} }, | ||
| 512 | { 2, 0x113e, 0, {0x50,0x03} }, | ||
| 513 | { 3, 0x1140, 0, {0x0a,0x80,0xf8} }, | ||
| 514 | { 1, 0x1143, 0, {0x22} }, | ||
| 515 | { 4, 0x1144, 0, {0xe5,0x6f,0x60,0x02} }, | ||
| 516 | { 2, 0x1148, 0, {0x80,0x07} }, | ||
| 517 | { 7, 0x114a, 0, {0x7a,0x00,0x75,0x39,0x00,0x80,0x05} }, | ||
| 518 | { 5, 0x1151, 0, {0x7a,0x40,0x75,0x39,0x10} }, | ||
| 519 | { 9, 0x1156, 0, {0xe5,0x6e,0x2a,0xfa,0xe5,0x6e,0x25,0x39,0xf5} }, | ||
| 520 | { 10, 0x115f, 0, {0x39,0x90,0x88,0x02,0x74,0x80,0x2a,0xf0,0x7a,0x00} }, | ||
| 521 | { 8, 0x1169, 0, {0xc3,0xea,0x64,0x80,0x94,0xa8,0x50,0x03} }, | ||
| 522 | { 3, 0x1171, 0, {0x0a,0x80,0xf5} }, | ||
| 523 | { 1, 0x1174, 0, {0x22} }, | ||
| 524 | { 6, 0x1175, 0, {0xaa,0x70,0xab,0x71,0xac,0x72} }, | ||
| 525 | { 12, 0x117b, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x12,0x14,0xee,0xfd,0x60,0x18} }, | ||
| 526 | { 13, 0x1187, 0, {0x8d,0x6d,0xc0,0x02,0xc0,0x03,0xc0,0x04,0x12,0x11,0x0c,0xd0,0x04} }, | ||
| 527 | { 9, 0x1194, 0, {0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} }, | ||
| 528 | { 2, 0x119d, 0, {0x80,0xdc} }, | ||
| 529 | { 1, 0x119f, 0, {0x22} }, | ||
| 530 | { 13, 0x11a0, 0, {0xe5,0x73,0xc4,0x54,0x0f,0xfa,0x53,0x02,0x0f,0xc3,0x74,0x09,0x9a} }, | ||
| 531 | { 2, 0x11ad, 0, {0x50,0x06} }, | ||
| 532 | { 6, 0x11af, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} }, | ||
| 533 | { 4, 0x11b5, 0, {0x74,0x30,0x2a,0xfb} }, | ||
| 534 | { 12, 0x11b9, 0, {0x8b,0x6d,0xc0,0x03,0x12,0x11,0x0c,0xd0,0x03,0xaa,0x73,0x53} }, | ||
| 535 | { 8, 0x11c5, 0, {0x02,0x0f,0xc3,0x74,0x09,0x9a,0x50,0x06} }, | ||
| 536 | { 6, 0x11cd, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} }, | ||
| 537 | { 4, 0x11d3, 0, {0x74,0x30,0x2a,0xfb} }, | ||
| 538 | { 5, 0x11d7, 0, {0x8b,0x6d,0x12,0x11,0x0c} }, | ||
| 539 | { 1, 0x11dc, 0, {0x22} }, | ||
| 540 | { 7, 0x11dd, 0, {0x90,0x7d,0xc3,0xe0,0xfa,0x60,0x0f} }, | ||
| 541 | { 12, 0x11e4, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x6e,0x90,0x7d,0xc2,0xe0,0xf5,0x6f} }, | ||
| 542 | { 3, 0x11f0, 0, {0x12,0x11,0x44} }, | ||
| 543 | { 12, 0x11f3, 0, {0x90,0x7d,0xff,0xe4,0xf0,0x75,0x70,0xc4,0x75,0x71,0x7d,0x75} }, | ||
| 544 | { 5, 0x11ff, 0, {0x72,0x01,0x12,0x11,0x75} }, | ||
| 545 | { 1, 0x1204, 0, {0x22} }, | ||
| 546 | { 2, 0x1205, 0, {0x7a,0x04} }, | ||
| 547 | { 3, 0x1207, 0, {0xba,0x40,0x00} }, | ||
| 548 | { 2, 0x120a, 0, {0x50,0x36} }, | ||
| 549 | { 14, 0x120c, 0, {0xea,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfb,0x7c,0x00} }, | ||
| 550 | { 3, 0x121a, 0, {0xbc,0x08,0x00} }, | ||
| 551 | { 2, 0x121d, 0, {0x50,0x20} }, | ||
| 552 | { 6, 0x121f, 0, {0x8b,0x05,0xed,0x30,0xe7,0x0b} }, | ||
| 553 | { 11, 0x1225, 0, {0x90,0x7f,0x96,0x74,0x42,0xf0,0x74,0xc3,0xf0,0x80,0x08} }, | ||
| 554 | { 8, 0x1230, 0, {0x90,0x7f,0x96,0xe4,0xf0,0x74,0x81,0xf0} }, | ||
| 555 | { 7, 0x1238, 0, {0xeb,0x25,0xe0,0xfb,0x0c,0x80,0xdb} }, | ||
| 556 | { 3, 0x123f, 0, {0x0a,0x80,0xc5} }, | ||
| 557 | { 1, 0x1242, 0, {0x22} }, | ||
| 558 | { 4, 0x1243, 0, {0x7a,0x00,0x7b,0xef} }, | ||
| 559 | { 3, 0x1247, 0, {0xba,0x10,0x00} }, | ||
| 560 | { 2, 0x124a, 0, {0x50,0x20} }, | ||
| 561 | { 14, 0x124c, 0, {0x74,0x11,0x2b,0xfb,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0x8c,0x82,0x8d} }, | ||
| 562 | { 14, 0x125a, 0, {0x83,0xe4,0xf0,0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe4} }, | ||
| 563 | { 4, 0x1268, 0, {0xf0,0x0a,0x80,0xdb} }, | ||
| 564 | { 1, 0x126c, 0, {0x22} }, | ||
| 565 | { 14, 0x126d, 0, {0x74,0xf8,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
| 566 | { 14, 0x127b, 0, {0x74,0xf9,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
| 567 | { 14, 0x1289, 0, {0x74,0xfa,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
| 568 | { 14, 0x1297, 0, {0x74,0xfb,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
| 569 | { 14, 0x12a5, 0, {0x74,0xff,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
| 570 | { 1, 0x12b3, 0, {0x22} }, | ||
| 571 | { 14, 0x12b4, 0, {0x12,0x03,0xcb,0x12,0x12,0x6d,0x7a,0xc0,0x7b,0x87,0x7c,0x01,0x74,0x01} }, | ||
| 572 | { 14, 0x12c2, 0, {0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74} }, | ||
| 573 | { 14, 0x12d0, 0, {0x01,0x12,0x14,0xbf,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e} }, | ||
| 574 | { 14, 0x12de, 0, {0x83,0x8f,0xf0,0x74,0x06,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b} }, | ||
| 575 | { 14, 0x12ec, 0, {0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74} }, | ||
| 576 | { 14, 0x12fa, 0, {0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0} }, | ||
| 577 | { 14, 0x1308, 0, {0x74,0x0b,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07} }, | ||
| 578 | { 14, 0x1316, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74,0x08,0x12,0x14,0xbf,0x74,0x01,0x2d} }, | ||
| 579 | { 14, 0x1324, 0, {0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x01} }, | ||
| 580 | { 14, 0x1332, 0, {0x12,0x14,0xbf,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83} }, | ||
| 581 | { 14, 0x1340, 0, {0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74,0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f} }, | ||
| 582 | { 14, 0x134e, 0, {0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x03,0x12,0x14,0xbf,0x7d,0x00} }, | ||
| 583 | { 3, 0x135c, 0, {0xbd,0x06,0x00} }, | ||
| 584 | { 2, 0x135f, 0, {0x50,0x12} }, | ||
| 585 | { 11, 0x1361, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x0a,0xba,0x00,0x01,0x0b} }, | ||
| 586 | { 7, 0x136c, 0, {0xe4,0x12,0x14,0xbf,0x0d,0x80,0xe9} }, | ||
| 587 | { 13, 0x1373, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe5,0x74,0x12,0x14,0xbf,0x74,0xf9} }, | ||
| 588 | { 14, 0x1380, 0, {0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x0f,0xf0,0x74} }, | ||
| 589 | { 14, 0x138e, 0, {0xfe,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x01,0xf0} }, | ||
| 590 | { 6, 0x139c, 0, {0x12,0x03,0xe1,0x12,0x04,0xf7} }, | ||
| 591 | { 1, 0x13a2, 0, {0x22} }, | ||
| 592 | { 13, 0x13a3, 0, {0x90,0x7d,0xc1,0xe0,0xfa,0x24,0x00,0xfb,0xe4,0x34,0x19,0xfc,0x90} }, | ||
| 593 | { 14, 0x13b0, 0, {0x7d,0xc2,0xe0,0xfd,0x8b,0x82,0x8c,0x83,0xf0,0x75,0xf0,0x11,0xea,0xa4} }, | ||
| 594 | { 3, 0x13be, 0, {0xfa,0x7b,0x00} }, | ||
| 595 | { 3, 0x13c1, 0, {0xbb,0x10,0x00} }, | ||
| 596 | { 2, 0x13c4, 0, {0x50,0x24} }, | ||
| 597 | { 14, 0x13c6, 0, {0xea,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0xeb,0x2c,0xfc,0xe4,0x3d,0xfd} }, | ||
| 598 | { 14, 0x13d4, 0, {0x74,0x04,0x2b,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfe} }, | ||
| 599 | { 8, 0x13e2, 0, {0x8c,0x82,0x8d,0x83,0xf0,0x0b,0x80,0xd7} }, | ||
| 600 | { 14, 0x13ea, 0, {0xea,0x24,0x00,0xfa,0xe4,0x34,0x18,0xfb,0x74,0x10,0x2a,0xf5,0x82,0xe4} }, | ||
| 601 | { 5, 0x13f8, 0, {0x3b,0xf5,0x83,0xe4,0xf0} }, | ||
| 602 | { 1, 0x13fd, 0, {0x22} }, | ||
| 603 | { 4, 0x13fe, 0, {0xe5,0x76,0x60,0x02} }, | ||
| 604 | { 2, 0x1402, 0, {0x80,0x16} }, | ||
| 605 | { 12, 0x1404, 0, {0x74,0x0f,0x55,0x75,0xfa,0x8a,0x75,0x24,0x00,0xf5,0x82,0xe4} }, | ||
| 606 | { 10, 0x1410, 0, {0x34,0x19,0xf5,0x83,0xe0,0xf5,0x74,0x12,0x12,0xb4} }, | ||
| 607 | { 10, 0x141a, 0, {0x12,0x10,0xca,0x75,0x6e,0x00,0x75,0x6f,0x00,0x12} }, | ||
| 608 | { 6, 0x1424, 0, {0x11,0x44,0x75,0x70,0xb9,0x75} }, | ||
| 609 | { 6, 0x142a, 0, {0x71,0x14,0x75,0x72,0x02,0x12} }, | ||
| 610 | { 11, 0x1430, 0, {0x11,0x75,0xe5,0x76,0xb4,0x02,0x04,0x74,0x01,0x80,0x01} }, | ||
| 611 | { 1, 0x143b, 0, {0xe4} }, | ||
| 612 | { 3, 0x143c, 0, {0xfa,0x70,0x0f} }, | ||
| 613 | { 12, 0x143f, 0, {0x74,0x01,0x25,0x75,0xf5,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0} }, | ||
| 614 | { 3, 0x144b, 0, {0x02,0x80,0x0a} }, | ||
| 615 | { 10, 0x144e, 0, {0x85,0x75,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0,0x02} }, | ||
| 616 | { 12, 0x1458, 0, {0x75,0x6e,0x00,0x75,0x6f,0x01,0xc0,0x02,0x12,0x11,0x44,0xd0} }, | ||
| 617 | { 4, 0x1464, 0, {0x02,0xea,0x70,0x1a} }, | ||
| 618 | { 13, 0x1468, 0, {0x75,0xf0,0x11,0xe5,0x75,0xa4,0xfa,0x24,0x00,0xfa,0xe4,0x34,0x18} }, | ||
| 619 | { 9, 0x1475, 0, {0xfb,0x8a,0x70,0x8b,0x71,0x75,0x72,0x01,0x12} }, | ||
| 620 | { 4, 0x147e, 0, {0x11,0x75,0x80,0x36} }, | ||
| 621 | { 2, 0x1482, 0, {0x7a,0x00} }, | ||
| 622 | { 3, 0x1484, 0, {0xba,0x10,0x00} }, | ||
| 623 | { 2, 0x1487, 0, {0x50,0x2f} }, | ||
| 624 | { 13, 0x1489, 0, {0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe0,0xfb,0xe5} }, | ||
| 625 | { 4, 0x1496, 0, {0x75,0xb5,0x03,0x1b} }, | ||
| 626 | { 14, 0x149a, 0, {0x75,0xf0,0x11,0xea,0xa4,0xfb,0x24,0x00,0xfb,0xe4,0x34,0x18,0xfc,0x8b} }, | ||
| 627 | { 9, 0x14a8, 0, {0x70,0x8c,0x71,0x75,0x72,0x01,0xc0,0x02,0x12} }, | ||
| 628 | { 4, 0x14b1, 0, {0x11,0x75,0xd0,0x02} }, | ||
| 629 | { 3, 0x14b5, 0, {0x0a,0x80,0xcc} }, | ||
| 630 | { 1, 0x14b8, 0, {0x22} }, | ||
| 631 | { 6, 0x14b9, 0, {0x50,0x72,0x6f,0x67,0x20,0x00} }, | ||
| 632 | { 14, 0x14bf, 0, {0xc8,0xc0,0xe0,0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0b,0x14,0x60,0x0f,0x14} }, | ||
| 633 | { 7, 0x14cd, 0, {0x60,0x11,0x14,0x60,0x12,0x80,0x15} }, | ||
| 634 | { 7, 0x14d4, 0, {0xd0,0xe0,0xa8,0x82,0xf6,0x80,0x0e} }, | ||
| 635 | { 5, 0x14db, 0, {0xd0,0xe0,0xf0,0x80,0x09} }, | ||
| 636 | { 4, 0x14e0, 0, {0xd0,0xe0,0x80,0x05} }, | ||
| 637 | { 5, 0x14e4, 0, {0xd0,0xe0,0xa8,0x82,0xf2} }, | ||
| 638 | { 4, 0x14e9, 0, {0xc8,0xd0,0xe0,0xc8} }, | ||
| 639 | { 1, 0x14ed, 0, {0x22} }, | ||
| 640 | { 14, 0x14ee, 0, {0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0d,0x14,0x60,0x0f,0x14,0x60,0x0f,0x14} }, | ||
| 641 | { 6, 0x14fc, 0, {0x60,0x10,0x74,0xff,0x80,0x0f} }, | ||
| 642 | { 5, 0x1502, 0, {0xa8,0x82,0xe6,0x80,0x0a} }, | ||
| 643 | { 3, 0x1507, 0, {0xe0,0x80,0x07} }, | ||
| 644 | { 4, 0x150a, 0, {0xe4,0x93,0x80,0x03} }, | ||
| 645 | { 3, 0x150e, 0, {0xa8,0x82,0xe2} }, | ||
| 646 | { 4, 0x1511, 0, {0xf8,0xd0,0xe0,0xc8} }, | ||
| 647 | { 1, 0x1515, 0, {0x22} }, | ||
| 648 | { 0, 0x0000, 1, {0} } | ||
| 649 | |||
| 650 | }; | ||
| 651 | |||
| 652 | static unsigned char bitstream[] = { | ||
| 653 | |||
| 654 | 0x00,0x09,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0, 0x0F,0xF0,0x00,0x00,0x01,0x61,0x00,0x0D, | ||
| 655 | 0x64,0x61,0x62,0x75,0x73,0x62,0x74,0x72, 0x2E,0x6E,0x63,0x64,0x00,0x62,0x00,0x0B, | ||
| 656 | 0x73,0x31,0x30,0x78,0x6C,0x76,0x71,0x31, 0x30,0x30,0x00,0x63,0x00,0x0B,0x31,0x39, | ||
| 657 | 0x39,0x39,0x2F,0x30,0x39,0x2F,0x32,0x34, 0x00,0x64,0x00,0x09,0x31,0x30,0x3A,0x34, | ||
| 658 | 0x32,0x3A,0x34,0x36,0x00,0x65,0x00,0x00, 0x2E,0xC0,0xFF,0x20,0x17,0x5F,0x9F,0x5B, | ||
| 659 | 0xFE,0xFB,0xBB,0xB7,0xBB,0xBB,0xFB,0xBF, 0xAF,0xEF,0xFB,0xDF,0xB7,0xFB,0xFB,0x7F, | ||
| 660 | 0xBF,0xB7,0xEF,0xF2,0xFF,0xFB,0xFE,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xBF,0xFF,0xFF, | ||
| 661 | 0xFF,0xFF,0xAF,0xFF,0xFA,0xFF,0xFF,0xFF, 0xC9,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF, | ||
| 662 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xA3,0xFF,0xFB, | ||
| 663 | 0xFE,0xFF,0xBF,0xEF,0xE3,0xFE,0xFF,0xBF, 0xE3,0xFE,0xFF,0xBF,0x6F,0xFB,0xF6,0xFF, | ||
| 664 | 0xBF,0xFF,0x47,0xFF,0xFF,0x9F,0xEE,0xF9, 0xFE,0xCF,0x9F,0xEF,0xFB,0xCF,0x9B,0xEE, | ||
| 665 | 0xF8,0xFE,0xEF,0x8F,0xEE,0xFB,0xFE,0x0B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 666 | 0xFF,0xFF,0xBF,0xFF,0xFF,0xFB,0xFF,0xFF, 0xBF,0xFF,0xFF,0xFC,0x17,0xFF,0xFF,0xFF, | ||
| 667 | 0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFB,0xFF,0xFF,0x7F,0xFF,0xFF, | ||
| 668 | 0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, | ||
| 669 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x5F,0xFF, 0xFF,0xFD,0xFF,0xFF,0xDB,0xFF,0xFD,0xFF, | ||
| 670 | 0x77,0xFF,0xFD,0xFF,0xFF,0xDF,0xFE,0xFD, 0xFF,0xFF,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 671 | 0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1, | ||
| 672 | 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, | ||
| 673 | 0xFF,0xFF,0xFF,0xFF,0xE3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, | ||
| 674 | 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x67,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 675 | 0x7F,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0x2F,0xFF, | ||
| 676 | 0xF3,0xFD,0xFF,0x7F,0xDE,0xF7,0xFD,0xFF, 0x7F,0xF7,0x7D,0xFF,0x7F,0xDF,0xF7,0xBD, | ||
| 677 | 0xFF,0x7F,0xFF,0x1F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xEF,0xFB, | ||
| 678 | 0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, 0x3F,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F, | ||
| 679 | 0x9F,0xE7,0xFA,0x7F,0x9F,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xFF,0xFC,0x7F,0xBF,0xBF, | ||
| 680 | 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xB7, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, | ||
| 681 | 0xFF,0xE0,0xFD,0xF9,0xFE,0x7F,0x9F,0xE7, 0xF9,0xFE,0x7F,0x9D,0xF9,0xFE,0x7D,0x9D, | ||
| 682 | 0xE7,0xF9,0xFE,0x7F,0x9F,0xED,0xED,0xFF, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F, | ||
| 683 | 0xDF,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF, 0x7F,0xDF,0xFF,0x9B,0xFF,0xEF,0xFB,0xFE, | ||
| 684 | 0xFB,0xBF,0xEF,0xBB,0xFE,0xFF,0xAF,0xBB, 0xBE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, | ||
| 685 | 0xB7,0xBF,0xDB,0xF6,0xBD,0xBF,0x6B,0xDB, 0xF6,0xF9,0xBF,0x5B,0xD6,0xF9,0xBF,0x6F, | ||
| 686 | 0xDB,0xF6,0xFD,0xBF,0xFF,0x0E,0xFF,0xFF, 0xFF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0x7F, | ||
| 687 | 0xF7,0xBD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xDF,0x9F,0xFF,0xFF,0xFF,0xFE,0xFF, | ||
| 688 | 0xFF,0xEF,0xFE,0xFE,0xFF,0xFF,0x77,0xFF, 0xFB,0xFB,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F, | ||
| 689 | 0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 690 | 0xFF,0xFF,0xFF,0xF4,0x7F,0xFF,0xFE,0xFD, 0xBE,0xFF,0xDF,0xFE,0xFF,0xFF,0xEF,0x7F, | ||
| 691 | 0xFF,0xCF,0xFF,0xCF,0xFF,0xFF,0xFF,0xDF, 0xE6,0xFF,0xFF,0x7F,0xDF,0xF7,0xDD,0x7F, | ||
| 692 | 0x7F,0xDF,0xF7,0xFF,0x7F,0xDF,0xD7,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFF,0xCD,0xFF,0xF2, | ||
| 693 | 0xFF,0xFF,0x4F,0x7F,0xF4,0xFF,0xFF,0xFF, 0xE7,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 694 | 0xFF,0xFF,0xBB,0xFF,0xEF,0xFF,0xFE,0xFF, 0xFF,0xFF,0xEF,0xFF,0xFF,0xEF,0xFF,0xFB, | ||
| 695 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x65, 0xEF,0xFF,0xFF,0x7F,0xFF,0xFD,0xEF,0xFF, | ||
| 696 | 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xCF,0xDF,0xFE,0xFF, | ||
| 697 | 0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xF3,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 698 | 0xFE,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 699 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF,0xFF, | ||
| 700 | 0xFF,0xFF,0xEF,0xEB,0xFF,0xFE,0xBF,0xFF, 0xEB,0xFF,0xFC,0x7F,0xFF,0xFF,0xFF,0xEE, | ||
| 701 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xD6,0xFF,0xFD,0xBF,0xFF,0xFB,0xFF,0xFE, | ||
| 702 | 0xFD,0xFF,0xFF,0xFD,0xEF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xDE,0xFF,0xFF,0xFF,0xFF, | ||
| 703 | 0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0x7F,0xBF, 0xFF,0x5F,0xDF,0xFF,0xFF,0xBF,0x77,0xFF, | ||
| 704 | 0xFF,0xFF,0x7F,0xD7,0xFF,0xFF,0xFF,0xFF, 0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xDF,0xEF, | ||
| 705 | 0xFF,0xFF,0xFE,0xFB,0xFF,0xFF,0xDF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xB7,0xFF, | ||
| 706 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 707 | 0xFF,0xFF,0xFF,0xAF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 708 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xBF,0xDF,0xF3,0xFD,0xFB,0xFF,0x5B, | ||
| 709 | 0xFD,0xFF,0xBF,0xEF,0xF7,0xFF,0xFF,0x7D, 0xFF,0xFF,0xFF,0xFF,0xF8,0x3B,0xFF,0xBF, | ||
| 710 | 0x6F,0xFF,0xFE,0xFF,0xBF,0xFF,0xEB,0x7D, 0xFF,0xEF,0xFB,0xFE,0xFF,0xFF,0xFF,0xFF, | ||
| 711 | 0xFF,0xF2,0x7F,0xFC,0xFF,0x3F,0xDF,0xED, 0xFE,0xFF,0xFF,0xFF,0xFF,0xEF,0x5F,0xF7, | ||
| 712 | 0xB5,0xFF,0xEF,0xFF,0xFF,0xFF,0xE0,0x3F, 0x9F,0x9E,0xFF,0xFF,0xEF,0xFF,0xDF,0xFF, | ||
| 713 | 0xBF,0x5F,0xBF,0xCF,0xF3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x69,0xAF,0x33,0xFD,0xFF, | ||
| 714 | 0xFB,0xFF,0xFF,0xFF,0xFF,0xFC,0xFF,0x7F, 0xD9,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xF5, | ||
| 715 | 0xA3,0xDF,0x6E,0xDE,0xFF,0xFF,0xBD,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xE7,0xFD, | ||
| 716 | 0xFF,0xFF,0xFF,0xF9,0xEF,0xC6,0xFE,0xB7, 0xAD,0xE5,0xF9,0xFF,0xFF,0xFF,0xCF,0xFF, | ||
| 717 | 0xFF,0xFF,0xCD,0xFB,0x7F,0xFF,0xFF,0xFF, 0xF9,0xF6,0x0F,0xDF,0xEC,0xCF,0x7F,0xFF, | ||
| 718 | 0xFB,0x7F,0xFF,0xFF,0xFF,0xFD,0xFF,0xFE, 0xF9,0xFD,0x7F,0xFF,0x7F,0xFF,0xF9,0x5B, | ||
| 719 | 0xFF,0x73,0xDC,0xFD,0x7B,0xDF,0xFF,0xFF, 0xFF,0x7B,0xFF,0xFF,0xF7,0x53,0xD6,0xFF, | ||
| 720 | 0xFF,0xFF,0xFF,0xD8,0x9F,0xFE,0xFF,0xEF, 0x7F,0xEE,0xFF,0xFF,0xFF,0xFB,0xED,0xED, | ||
| 721 | 0xFD,0xFF,0xFE,0xFF,0xFF,0xFB,0x7F,0xFF, 0xE2,0x7F,0xFF,0x6F,0xD8,0x57,0xF7,0xFF, | ||
| 722 | 0xFF,0xFF,0xDF,0xFF,0xE8,0xFF,0xFF,0xFD, 0xFF,0xFF,0xFC,0x7F,0xFF,0xE4,0xFF,0xFB, | ||
| 723 | 0xEF,0xFB,0xFE,0xDF,0xB7,0xED,0xFF,0xFE, 0xDF,0x7F,0xFF,0xFE,0x7F,0xB7,0xFF,0xFF, | ||
| 724 | 0xFF,0xFF,0x89,0xFF,0xFF,0xCF,0xF3,0xFE, 0x7F,0xFF,0xEF,0xFF,0xFE,0x7E,0x7F,0xFB, | ||
| 725 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF1, 0xFF,0xEB,0x7A,0xD5,0xBF,0x6F,0xDB,0xBE, | ||
| 726 | 0xFD,0xB7,0xD8,0xF6,0xE5,0xBF,0x6F,0xFB, 0xFE,0xF5,0xBD,0x7E,0x06,0xFF,0xDF,0xF7, | ||
| 727 | 0xFB,0xF6,0xFF,0x3F,0xFF,0xDB,0xFF,0xFF, 0x6F,0xFB,0xF7,0xFF,0xFF,0xFF,0xFB,0xFE, | ||
| 728 | 0xF7,0xAF,0xFF,0xB7,0xED,0xEF,0xF7,0xFE, 0xFF,0xFF,0xDF,0xFF,0xFE,0xFF,0xEF,0xFF, | ||
| 729 | 0xFF,0xFF,0xFF,0xBF,0xF7,0xFC,0x1F,0xEE, 0xFB,0xFE,0xBD,0xFF,0x7F,0x5F,0xD7,0xFD, | ||
| 730 | 0xFB,0x43,0xFF,0xFF,0xFD,0xFF,0x5F,0xFF, 0xF7,0xFF,0xF9,0x3F,0xFF,0xCF,0xF3,0xFD, | ||
| 731 | 0xF7,0x7E,0xEF,0xA7,0xF9,0xFE,0x8F,0xA7, 0xE9,0xF3,0x7E,0x9F,0xFB,0xF8,0xFF,0xFF, | ||
| 732 | 0x3F,0xFD,0x7F,0x5F,0xDF,0xFD,0xFF,0xFF, 0x5F,0xFF,0xFD,0x5F,0xFF,0xFF,0x7F,0xFD, | ||
| 733 | 0x7F,0xFD,0x9F,0xFF,0xE0,0xFF,0xFA,0xF8, 0xBE,0x6F,0x9F,0xE6,0xF8,0xBE,0x3F,0x9A, | ||
| 734 | 0xF9,0xBE,0x6F,0x9F,0xE2,0xF9,0xFE,0x6F, 0x9F,0xF9,0xFF,0xF5,0xFD,0x7F,0xCF,0xDF, | ||
| 735 | 0xFD,0xFD,0x7F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xF7,0xF5,0xFD,0x0F,0xDB,0xFF,0xD3,0xFF, | ||
| 736 | 0xEB,0xFA,0xFF,0xFF,0xBF,0xFF,0xFA,0xFF, 0xFF,0xCB,0xFB,0xFE,0xFF,0xFF,0xEB,0xFA, | ||
| 737 | 0xFE,0xFF,0xFF,0xB7,0xFF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xDF,0xF5,0xFF,0xFF,0xD7,0xFF, | ||
| 738 | 0xFF,0xFF,0xDF,0xD7,0xF5,0xFF,0x7F,0xFE, 0x4F,0xFF,0xFD,0xFF,0x7F,0x7F,0xFF,0xAD, | ||
| 739 | 0xEB,0xFB,0xFF,0xAD,0xFF,0xFF,0xFF,0xFF, 0xAF,0xEB,0xFB,0xFF,0xFC,0x0D,0xFF,0xFF, | ||
| 740 | 0xDF,0xD2,0xFD,0xFF,0xFF,0xFD,0xF6,0xFF, 0xFF,0x7F,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF, | ||
| 741 | 0xFF,0xFB,0x3F,0x7D,0xEB,0x32,0xFE,0xBF, 0x2F,0xEB,0xFA,0xAE,0xBD,0xE0,0xFA,0x7E, | ||
| 742 | 0xBF,0xAD,0xEB,0xFA,0xFE,0xBF,0xF5,0x7F, 0xFF,0xDE,0xFE,0xE3,0xFB,0xFF,0xFF,0xFF, | ||
| 743 | 0xDF,0xEF,0x4F,0xDF,0xFF,0x7F,0xDF,0xFF, 0xF7,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xEF, | ||
| 744 | 0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xDF, 0xED,0xFB,0xDF,0xFF,0xBF,0xFF,0xFF,0xFF, | ||
| 745 | 0x81,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFF,0xFE,0xDD,0xFE,0xEF,0xFD,0xFF, | ||
| 746 | 0xFF,0xFB,0xFE,0xF7,0xFF,0x93,0xFD,0xFB, 0x7E,0xFF,0xFE,0x87,0xE9,0xFF,0x7F,0xB3, | ||
| 747 | 0x9F,0xFE,0xFE,0xFF,0xAF,0xFD,0xFE,0x7E, 0x3F,0xFE,0x67,0xFF,0xFF,0xF7,0xFF,0xFF, | ||
| 748 | 0xFC,0xF7,0xDF,0xFD,0xFF,0x7F,0xFF,0xFF, 0x7F,0x6D,0xFF,0xFF,0xFE,0xFF,0xFF,0x2F, | ||
| 749 | 0xFF,0xBF,0xFF,0xFF,0xEE,0xFF,0xBE,0xFF, 0xFF,0xFE,0xFF,0xEF,0xFF,0xFF,0xFE,0xFF, | ||
| 750 | 0xEF,0xFF,0xFF,0xFA,0x5F,0xFF,0xFF,0xFB, 0xFF,0xFF,0xEF,0xFF,0xFB,0xFE,0xFD,0xFF, | ||
| 751 | 0xFE,0xFF,0xFB,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFE,0xBF,0xDF,0xFF,0xFB,0xFF,0xFF,0xF7, | ||
| 752 | 0xFC,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,0x7F,0xFF, | ||
| 753 | 0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xF3,0xFF,0xFF,0xFF,0xEF,0xFB,0xFF,0xFF, | ||
| 754 | 0xFF,0xDF,0xE2,0xFF,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xE7,0xFF,0xFD, | ||
| 755 | 0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xED, 0xEF,0xFD,0xFF,0xFF,0xDF,0xD7,0xF5,0xFD, | ||
| 756 | 0x7F,0x5D,0xFD,0xFF,0x7F,0xDF,0x97,0xF4, 0xFD,0x7B,0x5F,0xFF,0xC9,0xFF,0xFB,0xFE, | ||
| 757 | 0xFF,0xBF,0xFF,0x5F,0xFF,0xFF,0xF7,0xFF, 0xEF,0xFD,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF, | ||
| 758 | 0xFF,0xF7,0xFF,0xD7,0xFD,0x7D,0x7F,0xFF, 0xFF,0xFF,0xFF,0xEF,0xDF,0xF7,0xFD,0xFF, | ||
| 759 | 0xBB,0xFF,0xFF,0x7F,0xFF,0xFE,0xE3,0xFF, 0xF9,0xFE,0x7F,0xBF,0xEF,0xFB,0xFE,0xFF, | ||
| 760 | 0xBF,0xF9,0xFE,0xFF,0x9F,0xEF,0xF9,0xFE, 0xFF,0xBF,0xF3,0xDA,0xFF,0x37,0xCD,0xF3, | ||
| 761 | 0x7C,0xDF,0x37,0xCD,0xF3,0x7F,0x37,0xCD, 0xF3,0x7C,0xDF,0x37,0xCC,0xF3,0x7F,0x5A, | ||
| 762 | 0xBD,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFD, 0xBF,0x6F,0xDE,0xFD,0xBF,0x6F,0xDB,0xF6, | ||
| 763 | 0xFD,0xBF,0x6F,0xFE,0xF1,0x6F,0xEB,0x7A, 0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7,0xAF, | ||
| 764 | 0x7A,0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7, 0xFF,0x7E,0xFF,0xFE,0xCD,0xB3,0x6C,0xDB, | ||
| 765 | 0x36,0xCD,0xB3,0x6C,0xDE,0xCD,0xB3,0x6C, 0xDB,0x36,0xCD,0xB3,0x6C,0xDF,0xC9,0xBF, | ||
| 766 | 0xF7,0xBD,0xEF,0x7A,0x9E,0xA7,0xA9,0xEA, 0x7A,0xB7,0xBD,0xEA,0x7B,0xDE,0xA7,0xBD, | ||
| 767 | 0xCA,0x72,0x8D,0x91,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xF7,0xEF,0xFB, | ||
| 768 | 0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFE, 0x87,0xFF,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6, | ||
| 769 | 0xFD,0xBF,0x6F,0xF6,0xFD,0xBF,0x6F,0xDB, 0xF6,0xFD,0xBF,0x6F,0xFE,0x4F,0xFF,0xBF, | ||
| 770 | 0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,0xEF, 0xBE,0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB, | ||
| 771 | 0xEF,0xFC,0x5F,0xFF,0xFF,0xFF,0x3F,0xCF, 0xF3,0xFC,0xFF,0x3F,0xCF,0xFC,0xFF,0x3F, | ||
| 772 | 0xCF,0xF3,0xFC,0xFF,0x3F,0xCF,0xFD,0x9F, 0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF, | ||
| 773 | 0xEB,0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFF,0xE1,0x6F,0xFD,0xFF,0x7F, | ||
| 774 | 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFD,0xFF, 0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF, | ||
| 775 | 0x7A,0xBF,0xFB,0xFE,0xDF,0xB7,0xED,0xFB, 0x7E,0xDF,0xB7,0xFB,0x7E,0xDF,0xB7,0xED, | ||
| 776 | 0xFB,0x7E,0xDF,0xB7,0xFF,0xC9,0xFF,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, | ||
| 777 | 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEE, 0xFB,0xFE,0xBB,0xFF,0xFE,0xFF,0xBF,0xEF, | ||
| 778 | 0xFB,0xFE,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0x3F,0xCF,0xFF,0xE7, | ||
| 779 | 0xFE,0xFF,0xF5,0xFD,0x77,0x5D,0xD7,0x35, 0xDD,0x77,0xD7,0xF5,0xCD,0x7B,0x5D,0xD7, | ||
| 780 | 0xF5,0xDD,0x77,0xFE,0x27,0xFF,0xFF,0x8B, 0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9,0xAF, | ||
| 781 | 0x8B,0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9, 0xFE,0x1F,0xFF,0x5F,0xD7,0xF5,0xFD,0x7F, | ||
| 782 | 0x5F,0xD7,0xF5,0xFF,0x5F,0xD7,0xF5,0xFD, 0x7F,0x5F,0xD7,0xF5,0xFF,0xFA,0x3F,0xFE, | ||
| 783 | 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xEB, 0xEC,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF, | ||
| 784 | 0xEB,0xFF,0xFE,0x7F,0xFD,0x7F,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 785 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE6, 0xFF,0xFA,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF, | ||
| 786 | 0xF7,0xFC,0xFF,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFD,0xFF,0xF5,0xFF,0xFF,0xFF, | ||
| 787 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 788 | 0xFF,0x02,0xFF,0xFE,0xBF,0xAB,0xEB,0xFA, 0xBE,0xBF,0x23,0xEB,0xDE,0x1F,0xAF,0xEA, | ||
| 789 | 0xFA,0xFE,0xAF,0xAF,0xEB,0xFD,0x97,0xFF, 0xF3,0xFC,0x7B,0x1F,0xCF,0xF1,0xFC,0x7F, | ||
| 790 | 0x1F,0xF1,0xFC,0x77,0x1F,0xCD,0xF1,0xFC, 0xFF,0x1F,0xFE,0x87,0xFF,0xAF,0xEF,0xFA, | ||
| 791 | 0xFE,0xFF,0xAF,0xEF,0xFA,0xFD,0xBF,0x2B, 0xFB,0x7E,0xBF,0xBF,0xEB,0xFB,0xFB,0xFB, | ||
| 792 | 0xDF,0xFF,0xFB,0xF7,0xFF,0xFF,0x7F,0xF7, 0xF7,0xFF,0xFD,0xDF,0xFE,0xFC,0xDF,0xFF, | ||
| 793 | 0xDF,0xFF,0xFD,0xFF,0xDA,0xBF,0xFF,0xBB, 0xEF,0xFB,0xF9,0xFF,0xBE,0xEF,0xFB,0xFB, | ||
| 794 | 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xF7,0x7F,0xFD,0xD7,0xFF,0xFF,0x7F, | ||
| 795 | 0xFF,0xFF,0xFF,0xFE,0xF7,0xFF,0xFE,0xFF, 0xF7,0xFF,0xFF,0x7F,0xFF,0xFF,0xEC,0xFF, | ||
| 796 | 0xFF,0xFE,0xDF,0xBF,0xFF,0xFB,0xFE,0xFF, 0xBB,0x68,0xAE,0x1F,0xAE,0xFB,0xFB,0xFF, | ||
| 797 | 0xFF,0xBF,0xFF,0xD5,0xFF,0x7F,0xFF,0xFF, 0xF7,0xFE,0xFE,0xFF,0xBF,0xEF,0x9F,0xFD, | ||
| 798 | 0x7F,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,0xFF, 0xBB,0xF7,0xBF,0xFF,0xFF,0xFF,0xFF,0xDF, | ||
| 799 | 0xFF,0xBF,0xFB,0xFF,0xFF,0xFF,0xDE,0x3F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xA7,0xFF,0xFF, | ||
| 800 | 0xFF,0xFF,0xEF,0xFF,0x7F,0xFB,0xFD,0xFB, 0x7F,0xFF,0xFF,0xFF,0xFF,0xCF,0xF3,0x7C, | ||
| 801 | 0xFF,0x7F,0x8D,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFB,0xFF,0xF7,0xFB,0xFE,0xFD,0xFF,0xFF, | ||
| 802 | 0xFF,0xFF,0xF7,0xFD,0xFF,0x7F,0xFD,0x1F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xBF,0xDF,0xFF, | ||
| 803 | 0xFF,0xFE,0x5C,0xFF,0x6D,0xFF,0x7F,0xAB, 0xE7,0xF1,0xFF,0xFD,0x9F,0xFF,0xFF,0xAD, | ||
| 804 | 0xEB,0x7A,0x3F,0x1F,0xFF,0xFF,0xFE,0xBF, 0xAF,0xF3,0xDE,0xF5,0xFF,0x8F,0xFB,0xDF, | ||
| 805 | 0xE6,0x7F,0xFF,0xDF,0xF3,0xFD,0xFF,0x7E, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xF7,0xF3, | ||
| 806 | 0x7F,0xDF,0xF7,0xEF,0xFF,0xF6,0x3F,0x9F, 0xDF,0xFF,0xFF,0xEE,0xFF,0xFF,0xEF,0xFB, | ||
| 807 | 0xFF,0xFF,0xF9,0xFB,0xFE,0x4F,0xBF,0xEF, 0xBB,0xFF,0x69,0xAF,0xAF,0xFC,0xFF,0x3F, | ||
| 808 | 0xDD,0xFF,0xFC,0xBF,0x8F,0xFF,0xFD,0xF3, 0xBF,0xED,0x9E,0xFC,0xBF,0x6F,0xF5,0xD3, | ||
| 809 | 0xDF,0xFF,0xDB,0xD6,0xF5,0xEF,0xFD,0xFE, 0xFF,0xB9,0xFF,0x1F,0xD2,0xA9,0xAF,0xFF, | ||
| 810 | 0xDB,0xF7,0xBF,0xEF,0x46,0xFF,0xFF,0xAD, 0xEB,0x7A,0xDF,0xEF,0xF7,0xFF,0x7F,0xF7, | ||
| 811 | 0x9F,0xED,0xFF,0x7F,0xFF,0xAD,0xEB,0x7F, 0xF5,0x6F,0xFF,0xFD,0xFB,0xD6,0xF4,0xF7, | ||
| 812 | 0xFB,0xF9,0x7E,0x7F,0xFF,0x5F,0xC2,0xFE, 0xBF,0xFD,0xFB,0x33,0xDF,0xF9,0x5B,0xFF, | ||
| 813 | 0xFF,0xDD,0x67,0x7D,0xCF,0xEF,0xDB,0xEC, 0xFF,0x77,0xDD,0xF7,0xFD,0xFF,0xFF,0xDE, | ||
| 814 | 0xA7,0xBF,0xD4,0x9F,0xFF,0xFF,0xBF,0xEF, 0xFE,0xFF,0xDF,0xEF,0xBB,0xFF,0xFF,0xEF, | ||
| 815 | 0xEB,0xFA,0xFF,0xEF,0xBD,0xFB,0xFF,0xE2, 0x7F,0xFF,0xDF,0xDF,0xF7,0xFD,0xBF,0xBB, | ||
| 816 | 0x73,0xF7,0xFD,0x7F,0xDF,0xDE,0xF7,0xBF, 0xEA,0xDB,0xF6,0xFF,0xD6,0xFF,0xFF,0x66, | ||
| 817 | 0xFF,0xBE,0xFF,0xBF,0x6B,0xD9,0xF6,0xDF, 0xFF,0xFB,0x7E,0x7F,0xB7,0x7E,0xFF,0xFE, | ||
| 818 | 0xFF,0xCD,0xFF,0xFE,0x7F,0xFF,0xFC,0xFD, 0x3F,0xFB,0xFB,0xF7,0xFF,0xFF,0xFB,0xF6, | ||
| 819 | 0x7D,0xFE,0x7F,0xFF,0xFC,0xFF,0xB9,0xFF, 0xF9,0xFA,0xFE,0xBF,0xAF,0x5B,0xD6,0xED, | ||
| 820 | 0xAD,0x7B,0xF6,0xF9,0xBF,0xEF,0xF8,0xFA, 0xFE,0xBF,0xFE,0xE6,0xFF,0xFF,0xF7,0xFD, | ||
| 821 | 0xFF,0x7F,0xBF,0xEF,0xF3,0xFF,0xFF,0x6F, 0xF7,0xFE,0xFF,0xFF,0xF7,0xFD,0xFE,0xF7, | ||
| 822 | 0xEF,0xFF,0xFB,0xEF,0xFB,0x7E,0xDE,0xFE, 0xFF,0xBF,0xFF,0xFE,0xFF,0xFF,0xFB,0xFF, | ||
| 823 | 0xFF,0xEF,0xFB,0x6F,0xFC,0x1F,0xFE,0xE7, 0xFF,0xFF,0xFF,0xEF,0xFF,0xD3,0xB4,0xBB, | ||
| 824 | 0xFF,0xFF,0xFD,0xBF,0x6F,0xE3,0xFE,0xFF, 0xBF,0xFC,0xBF,0xF7,0xCF,0xF7,0xFD,0xFF, | ||
| 825 | 0x2F,0xDF,0xAB,0xEA,0xFF,0xDF,0xE7,0xEA, 0x9A,0xAF,0xEF,0xFB,0xFE,0xFF,0xF5,0x3F, | ||
| 826 | 0xFD,0x7E,0xFF,0xD7,0xF5,0xFB,0xFF,0xFD, 0xF7,0xFF,0x7F,0xFE,0xF7,0xFD,0xFF,0xD7, | ||
| 827 | 0xFF,0xD7,0x7F,0xEE,0x7F,0xFA,0x79,0xFE, 0x2F,0x8B,0xE6,0xF9,0xFE,0x3F,0x9E,0xF9, | ||
| 828 | 0xBE,0x2F,0x0B,0xE7,0xF9,0xFE,0x2F,0x9F, 0xFD,0xFF,0xFE,0x7D,0x7F,0x5F,0xD7,0xFF, | ||
| 829 | 0xFF,0x7F,0xFF,0xFD,0xFF,0x7F,0x5F,0x97, 0xFF,0xFD,0x7F,0x5F,0xFF,0xE3,0xFF,0xFF, | ||
| 830 | 0xFA,0xFE,0xBF,0xAF,0xFB,0xFB,0xFF,0xFF, 0xCF,0xEB,0xFE,0xBF,0xAF,0xFF,0xFA,0xFE, | ||
| 831 | 0xBF,0xFF,0x87,0xFF,0xFF,0xF5,0xFF,0xFF, 0xFF,0xFF,0xFD,0xFF,0x7F,0xFF,0xFF,0xFF, | ||
| 832 | 0xFB,0xFF,0xFF,0xF5,0xFF,0xFF,0xFE,0x0F, 0xFF,0xFD,0xEB,0xFF,0xFF,0xF7,0xFF,0xEF, | ||
| 833 | 0x7B,0xDF,0xFE,0xFF,0xFF,0xDF,0xF7,0xFD, 0xEB,0x7F,0xDF,0xFF,0x5F,0xFF,0xFF,0xFF, | ||
| 834 | 0xFF,0xFD,0xBF,0xFF,0x7E,0xFA,0xBF,0xC7, 0xDB,0xF7,0xBD,0x3F,0xFB,0xFF,0xF6,0xFF, | ||
| 835 | 0xFA,0xAF,0xFF,0xEB,0xFA,0xFE,0x3F,0x2F, 0xEA,0xFA,0x3E,0xAD,0xC9,0xBA,0xF6,0xAD, | ||
| 836 | 0xAF,0xEB,0xFA,0xF6,0xBF,0xFE,0x7F,0xFF, 0xFF,0xFD,0xFF,0xF1,0x7F,0x3F,0xCF,0xF1, | ||
| 837 | 0xEF,0xFF,0x7F,0xFF,0xBC,0xDF,0xDF,0xF7, 0xDD,0xFF,0xE0,0x7F,0xFF,0xFF,0xFE,0xFF, | ||
| 838 | 0xFA,0xEC,0xBB,0x7F,0x5F,0xFF,0xFB,0xEC, 0xFF,0xEF,0xB7,0xFF,0xF7,0xFF,0xFF,0xB5, | ||
| 839 | 0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xEE,0xDF, 0x5F,0xDF,0xDE,0xFF,0xAE,0xE7,0x77,0xFF, | ||
| 840 | 0xFF,0xDF,0xF7,0xFF,0xE3,0xFF,0xFA,0xBB, 0xFE,0xFF,0xAF,0xFD,0xFB,0xFE,0xBF,0xAB, | ||
| 841 | 0xF9,0xFE,0xFF,0xBF,0x7F,0xBF,0xFE,0xBD, 0xFE,0xD7,0xFF,0x9F,0xFD,0xFF,0xBE,0xEF, | ||
| 842 | 0xFF,0xEE,0xFD,0xBB,0x5B,0xEF,0xFF,0x7F, 0xEF,0xFF,0xEF,0xFF,0x7F,0xFF,0x4F,0xFF, | ||
| 843 | 0xEF,0xFB,0xBC,0xFC,0xFF,0xFF,0xFF,0xFE, 0xFE,0xFD,0xFA,0xFE,0xFB,0xFF,0xFD,0xF3, | ||
| 844 | 0xFB,0xFF,0xF8,0x5F,0xFF,0xFF,0xD7,0xF5, 0xFD,0xDF,0xEF,0xFF,0xF3,0xDC,0x5F,0xCE, | ||
| 845 | 0xF5,0xBD,0xFF,0xFF,0xD7,0xFF,0xFF,0xF9, 0x3F,0xFF,0xDF,0xF7,0xFF,0xFE,0xFF,0xFD, | ||
| 846 | 0xFF,0xFB,0xFF,0xF7,0xB9,0x7D,0xFE,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF9,0x7F,0xFF,0xFE, | ||
| 847 | 0xFF,0xFF,0x7F,0xFF,0xFE,0xFF,0xFF,0xF7, 0xF6,0xFF,0xBF,0xF1,0xF8,0xFF,0xFF,0xFF, | ||
| 848 | 0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xF9,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEF,0xEF,0xFF,0xFF, | ||
| 849 | 0x9B,0xFB,0x7F,0xFF,0xFF,0xFF,0xC1,0xFF, 0xDF,0xFF,0x3F,0x5F,0xD7,0xBF,0xEF,0xBB, | ||
| 850 | 0xDE,0xEE,0xFF,0x7F,0xDF,0xFF,0xFE,0xF5, 0x7F,0xDF,0xFF,0x99,0xFF,0xFF,0xFA,0xFF, | ||
| 851 | 0xBF,0xFD,0xEB,0x7A,0xFF,0xB7,0xFE,0xFE, 0xFF,0xFF,0xEF,0xFF,0xFF,0xFD,0xBF,0xFF, | ||
| 852 | 0x97,0xFF,0xFD,0xF7,0xFF,0x7F,0xF7,0xFF, 0xFF,0xFD,0x5F,0xFE,0xF3,0xF9,0xDF,0xDF, | ||
| 853 | 0xFF,0xFF,0xFC,0xFF,0xFF,0x83,0xFF,0xFF, 0xFE,0xFF,0x9E,0xEC,0xFB,0xEE,0xFF,0x9F, | ||
| 854 | 0xBF,0xEF,0xFF,0xFE,0xED,0x7B,0xFF,0xFF, 0xFF,0xF1,0x5A,0xFF,0xFF,0xFD,0xFF,0x7C, | ||
| 855 | 0x69,0x3B,0xDF,0xFF,0x7F,0x1F,0xDF,0xFF, 0xFD,0xBA,0xFF,0xFF,0xFB,0xFF,0x5B,0xBD, | ||
| 856 | 0xFF,0xFF,0xFF,0xFF,0xD7,0xB6,0xED,0xE9, 0xFF,0xD6,0xBD,0x6F,0x5F,0xFB,0xFF,0xEF, | ||
| 857 | 0xFF,0x5F,0xFE,0xF6,0x6F,0xFF,0xFF,0xFF, 0xFF,0xF7,0xEB,0x7A,0xDF,0xFF,0x9F,0x7F, | ||
| 858 | 0x7F,0xFF,0xB7,0xFF,0xFF,0xFE,0xDF,0xFF, 0x6C,0xFF,0xFB,0xFF,0xBB,0x6F,0xEB,0xFE, | ||
| 859 | 0xCC,0xF7,0xA5,0xFA,0x5C,0xF5,0x75,0xBB, 0xB7,0xDF,0xFE,0x6F,0x5F,0xC5,0xBF,0xFD, | ||
| 860 | 0x7B,0xFE,0xFF,0x95,0xE7,0x29,0xCF,0x4F, 0xF5,0x91,0xEE,0x6B,0xDF,0xEF,0xFD,0x54, | ||
| 861 | 0xF5,0xBD,0xB1,0xFF,0xEF,0xEE,0xFB,0xBE, 0xBF,0xAF,0xFE,0xDE,0xBD,0x6F,0xDA,0xF2, | ||
| 862 | 0xFF,0xAF,0xBE,0xFF,0xFF,0xFD,0x7E,0xA7, 0xFF,0xF7,0xFF,0xBF,0xEF,0x7B,0xF6,0xFD, | ||
| 863 | 0xBD,0x4A,0xF2,0x85,0x85,0xBF,0x5B,0xFE, 0xB5,0xFD,0xFA,0xFF,0x4F,0xFF,0xFE,0xDF, | ||
| 864 | 0xFF,0xED,0xFF,0xBF,0xFF,0xBF,0x7F,0xFE, 0xFF,0xB7,0x6D,0xFF,0xF7,0xBF,0xBF,0xEF, | ||
| 865 | 0xFD,0x1F,0xFF,0xFE,0x7D,0xFF,0x67,0xFF, 0xFF,0xFF,0x3F,0x7F,0xFE,0xBF,0xFF,0xE7, | ||
| 866 | 0xDF,0xE7,0xFF,0xEF,0x6B,0xFC,0x1F,0xFF, 0xBF,0xEF,0xFB,0xFE,0xDE,0xBF,0xAF,0xFA, | ||
| 867 | 0xFF,0xB6,0xEF,0xF9,0xFE,0xFF,0x8F,0xEF, 0xDB,0xEF,0xAB,0x6F,0xFB,0xFE,0xFF,0xFF, | ||
| 868 | 0xEF,0xFD,0xFF,0x7F,0xFF,0xFF,0xDE,0xFF, 0xFF,0xEF,0xFF,0xFF,0xFF,0x3F,0xFF,0x6C, | ||
| 869 | 0xFF,0xBF,0xFB,0xFF,0xFE,0xFF,0xFB,0xFE, 0xDF,0xFF,0xFF,0xEF,0xFF,0xFF,0xBF,0xFF, | ||
| 870 | 0xFF,0xFE,0xFB,0xFF,0xD5,0x7F,0xFF,0xFF, 0xEF,0xFB,0xFF,0xFF,0xBF,0xEF,0x43,0xB5, | ||
| 871 | 0xFD,0x6F,0xCF,0xD6,0xBE,0x3F,0x7F,0xDB, 0xFE,0xC3,0xFF,0xFD,0xFF,0xAF,0xEB,0xFB, | ||
| 872 | 0xFC,0xFF,0x3E,0xEF,0xE8,0xFA,0xBD,0xCD, 0xAA,0xFE,0xFE,0x7D,0xCF,0xFF,0xB7,0xFF, | ||
| 873 | 0xF7,0xFF,0xFF,0xFF,0xFD,0xFF,0x75,0xCD, 0x52,0xD7,0xFD,0xFB,0xF7,0xDD,0xFB,0xEF, | ||
| 874 | 0xEB,0xFF,0xFF,0x4F,0xFF,0xBF,0x9F,0xE7, 0xF9,0xFC,0x7F,0x8B,0xC3,0xF9,0xAF,0x8F, | ||
| 875 | 0xE7,0xE9,0xBE,0x7F,0x9F,0xE6,0xF9,0xFC, 0x5F,0xFF,0xFF,0xF7,0xFD,0xFF,0x7A,0x5F, | ||
| 876 | 0xD7,0xED,0xFF,0xFF,0xD7,0xFF,0xDD,0x7F, 0xE7,0xFF,0xFC,0xFF,0xFC,0x3F,0xFF,0xFF, | ||
| 877 | 0xFF,0xFB,0xFF,0xFE,0xBF,0xAF,0xFF,0xFD, 0xFF,0xEF,0xFF,0xEB,0xFF,0xFF,0xFF,0xFF, | ||
| 878 | 0xFF,0xF7,0x7F,0xFF,0x7F,0xDF,0xFF,0xFD, 0xFD,0x7F,0xFE,0xF7,0xFD,0x7F,0xDF,0xFF, | ||
| 879 | 0xFD,0xFF,0xFF,0xDF,0xFB,0xFF,0xEE,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7A,0xDF,0xF5, | ||
| 880 | 0xFD,0xFA,0xDF,0xF7,0xFC,0xFF,0x7F,0xDF, 0xBF,0xED,0xFF,0xC9,0xFF,0xDF,0xFF,0xBF, | ||
| 881 | 0x2F,0xFB,0xFF,0xBC,0xAD,0xFF,0xF7,0xFF, 0xFF,0xEF,0xD3,0xFF,0x7D,0xBF,0x6F,0xFF, | ||
| 882 | 0xFA,0xFF,0xFE,0xBF,0xAE,0xEA,0xFA,0xBE, 0xAD,0xA5,0xEB,0xCE,0xBF,0xA7,0xEB,0x5A, | ||
| 883 | 0xDE,0xBD,0xAF,0x6B,0xFD,0x57,0xFF,0xFF, 0xF4,0x7F,0x1F,0x7F,0xFD,0xFF,0x7F,0x36, | ||
| 884 | 0xF0,0xDF,0x79,0xFF,0xFF,0xFF,0xF7,0xFD, 0xBF,0xFF,0x87,0xFF,0xFB,0xF3,0xFC,0xFF, | ||
| 885 | 0xFF,0xFF,0xFF,0x7E,0xFF,0xBF,0xDF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xF8,0x9F, | ||
| 886 | 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFD, 0xF7,0xFC,0xBD,0xFF,0xFE,0xFF,0xFF,0xFF, | ||
| 887 | 0xFF,0xFF,0xFB,0xF9,0xBF,0xFF,0xFF,0xEB, 0xE2,0xFE,0xFF,0xBF,0xEF,0xA9,0xBA,0x2F, | ||
| 888 | 0xEB,0xF9,0xFE,0x77,0xDF,0xF7,0xFF,0xFF, 0xF9,0x7F,0xFF,0xFF,0x7F,0xEF,0xD7,0xFF, | ||
| 889 | 0xFD,0xFF,0xFB,0xF5,0xFF,0xBF,0x6F,0xDF, 0xFF,0xFF,0xFD,0xFF,0xFF,0xF0,0xFF,0xFF, | ||
| 890 | 0xFF,0x3F,0xCF,0xFF,0xBA,0xEE,0x9B,0xBF, 0xEE,0xD7,0xFE,0xCD,0xEF,0xFF,0xDF,0xBF, | ||
| 891 | 0xFF,0xFF,0xC5,0xFF,0xFF,0xFD,0x7F,0x4F, 0xFD,0xF6,0xD9,0xFF,0x4F,0xD6,0xFD,0xBF, | ||
| 892 | 0x6E,0xFF,0xFF,0xF4,0x7F,0xFF,0x7F,0x8B, 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xF9,0xFE, | ||
| 893 | 0x37,0xFF,0xD9,0xFB,0xF5,0xAF,0xFD,0xFF, 0xFF,0xFB,0xFF,0xFF,0x07,0xFF,0xFF,0xFF, | ||
| 894 | 0xFB,0xF7,0xFF,0xFD,0xFF,0x7C,0xFA,0x7E, 0x4F,0xFC,0xDF,0x1D,0xC7,0xFF,0xFF,0xFF, | ||
| 895 | 0xFF,0xAE,0xFF,0xFF,0xFF,0xFF,0xFD,0xFB, 0xFF,0xFF,0xFE,0xFE,0xFC,0xFF,0x7F,0x7F, | ||
| 896 | 0xBF,0xEF,0xFE,0xFF,0xFF,0xFF,0x5F,0xFD, 0xFF,0xFF,0xFF,0xFD,0x6F,0x5A,0xD7,0x7B, | ||
| 897 | 0xBE,0x5F,0xFE,0x39,0xFF,0xF7,0xFF,0xF7, 0xFD,0xFE,0xAA,0x1F,0xFF,0xFF,0xFF,0xFF, | ||
| 898 | 0xFE,0xFE,0xAB,0xAF,0xFD,0xFE,0xBF,0xFF, 0xF7,0xFF,0x7F,0xFE,0x8F,0xE3,0xFB,0xEE, | ||
| 899 | 0x7F,0xFF,0xFF,0xFF,0xFF,0xEB,0xFB,0xFF, 0xFD,0xBF,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF, | ||
| 900 | 0xFF,0xFF,0xFF,0xFB,0xE4,0x3F,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF3,0xEF,0xBB,0xFB, | ||
| 901 | 0xBF,0xEF,0xBB,0xFF,0xD7,0xBF,0xFF,0xFF, 0xFF,0x29,0xAF,0xF7,0xFF,0xFF,0xFB,0xFF, | ||
| 902 | 0xFB,0xE6,0xFF,0x0F,0xFB,0x3F,0xDF,0x0F, 0xFF,0xAF,0xFF,0xFF,0xFF,0xF5,0xC3,0xDF, | ||
| 903 | 0x5F,0xFF,0xFF,0xFF,0xFE,0x6B,0xCA,0xBE, 0xBC,0xFF,0x9F,0xF2,0xBF,0xFF,0xFE,0xFA, | ||
| 904 | 0xFF,0xFF,0xEF,0x16,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFC,0xDF,0x97,0xFD,0x79,0xFF,0x37, | ||
| 905 | 0xE7,0x7F,0xFF,0xFF,0xB5,0xFF,0xFF,0xF6, 0x2F,0xFF,0xFD,0xFB,0xFE,0xFF,0xFF,0xFD, | ||
| 906 | 0x5F,0x57,0x5F,0xFF,0xDB,0x52,0xDF,0xFF, 0xFD,0xBF,0xFF,0xFF,0xFC,0xDB,0xFF,0x7B, | ||
| 907 | 0xB5,0xFD,0x7F,0xFF,0x71,0x9C,0x6E,0xFF, 0xF6,0x35,0xA5,0x9B,0xFF,0xFF,0xFD,0xFF, | ||
| 908 | 0xFF,0xDB,0x9E,0x7F,0xFE,0xEF,0xFB,0xFF, 0xFF,0xBD,0xEF,0xFF,0xDE,0xB7,0xF9,0x4B, | ||
| 909 | 0xFF,0xF5,0xEF,0xFF,0xFF,0xFF,0xE8,0x7E, 0xFF,0xEA,0xDF,0xF7,0xFF,0xFD,0x69,0x5B, | ||
| 910 | 0xFC,0x9F,0xEF,0x78,0xD6,0xFF,0xEB,0xEF, 0xFF,0xFF,0xFF,0xE8,0xFF,0xFF,0xED,0xFF, | ||
| 911 | 0xFF,0xFF,0xFF,0xE3,0xF9,0xF6,0xBF,0xFF, 0xFF,0xFE,0xDF,0xFF,0x7F,0xFF,0xFF,0xFF, | ||
| 912 | 0xD1,0xFF,0xFF,0xE7,0xFF,0xFF,0xFF,0xFF, 0xE7,0xF9,0xFF,0xBF,0x7F,0xD9,0xFF,0xFD, | ||
| 913 | 0xFE,0x7F,0xFF,0xFE,0xFF,0xF9,0xFF,0xFB, 0xD6,0xDF,0xBF,0xEF,0x5B,0xD6,0xFF,0xBF, | ||
| 914 | 0xFB,0xF6,0xFF,0xBF,0xEF,0xF8,0xF6,0xDD, 0xBE,0xFE,0x16,0xFF,0xBF,0xEF,0xFF,0xFE, | ||
| 915 | 0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0x6F,0xFB, 0xFF,0xFF,0xFF,0x6F,0xF3,0xFF,0xF7,0xEF, | ||
| 916 | 0xFB,0xFF,0xBF,0xFF,0xEF,0xFE,0xFF,0xBF, 0xFF,0xFF,0xFF,0xBE,0xBF,0xFF,0xEF,0xFF, | ||
| 917 | 0x7F,0xEF,0xFF,0xFD,0x17,0xFB,0x7B,0xFF, 0xFF,0xFD,0x7F,0xDB,0xF6,0xF4,0x7F,0xFA, | ||
| 918 | 0xFE,0xF5,0xBF,0xEB,0xE3,0xF7,0xFF,0xFF, 0xE9,0xBF,0xFF,0xAF,0xF7,0xFD,0xF3,0x7E, | ||
| 919 | 0x8F,0xA3,0xEA,0xFF,0xCB,0xF3,0xEE,0xFF, 0xBF,0xEF,0xF7,0xF9,0xFF,0xFE,0x7F,0xFF, | ||
| 920 | 0xFF,0xFF,0xFF,0xF5,0xFB,0xF6,0xFF,0xF5, 0x2F,0xFE,0xFB,0xD7,0xBF,0xFF,0xBE,0xDF, | ||
| 921 | 0x9F,0xFF,0xF0,0xFF,0xFF,0xF9,0xFE,0x7F, 0x8F,0xA3,0xF8,0xFE,0x6F,0x9F,0xF9,0xF6, | ||
| 922 | 0x2F,0x9F,0xE7,0xF9,0xFE,0x2F,0x9F,0xE1, 0xFF,0xFF,0xFF,0x7F,0xDF,0xF7,0xF5,0xFD, | ||
| 923 | 0x7F,0x7F,0xF5,0xFF,0x9F,0x5F,0xFB,0xFE, 0xFF,0x7F,0xFF,0xFF,0xCB,0xFF,0xFF,0xFB, | ||
| 924 | 0xFE,0xFF,0xBF,0xAF,0xFB,0xFE,0xFF,0xDF, 0xFE,0xFE,0xBF,0xF7,0xFF,0xFF,0xFF,0xFF, | ||
| 925 | 0xFF,0xC7,0xFF,0xFF,0xFD,0xFF,0x7F,0xDD, 0xF7,0xFD,0xFF,0xFF,0xD7,0xFF,0xFD,0x7F, | ||
| 926 | 0xFF,0xFB,0xFD,0xFF,0xFF,0xFE,0xEF,0x7F, 0xFD,0xEF,0xFB,0xFE,0xFB,0xFD,0xFF,0x7F, | ||
| 927 | 0xDF,0xFD,0xFF,0x7A,0xDF,0xF7,0xFD,0xFF, 0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xD3,0xF7, | ||
| 928 | 0xFF,0xFF,0x6F,0xDB,0xFF,0xFF,0xEF,0xCB, 0xF4,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, | ||
| 929 | 0x29,0xFF,0xE8,0xDA,0x76,0x9F,0xAF,0x6A, 0xDA,0xFE,0x35,0xEB,0xDA,0xD6,0xBF,0xAB, | ||
| 930 | 0xEB,0x7A,0xDE,0xBF,0xD7,0x7F,0xFF,0xFE, 0xFF,0xBF,0xEF,0xFD,0xDF,0x77,0xBF,0xFD, | ||
| 931 | 0x37,0xEF,0xFF,0xEF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xF7,0x7E, | ||
| 932 | 0xDF,0xFF,0xFF,0xFF,0xFA,0xB7,0x7F,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x89,0xFF, | ||
| 933 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x9F,0xFB,0xFF,0xFF,0xFF,0xE7,0xFF, | ||
| 934 | 0xFF,0xFF,0xFF,0xAA,0xFF,0xAB,0xFB,0xFA, 0xEF,0xBF,0xFF,0xDF,0xFA,0x7B,0xB9,0xFE, | ||
| 935 | 0xFE,0xFF,0xFD,0xFF,0xF7,0xFE,0x3F,0xFF, 0xB7,0xFF,0xF7,0xEE,0xFF,0x7F,0xEF,0xFF, | ||
| 936 | 0xFF,0x7F,0xFF,0x1F,0xFB,0xFF,0xBF,0xFB, 0xFE,0xFF,0xBD,0xFF,0xFF,0x2F,0xFF,0xBF, | ||
| 937 | 0xFF,0x7F,0xDF,0xFA,0xFF,0xFF,0xFC,0xEE, 0xF5,0xF3,0xBE,0xFB,0x0F,0xEF,0xF3,0xBE, | ||
| 938 | 0xEF,0xFC,0x5F,0xFF,0x5A,0xFF,0xF7,0xDF, 0xFF,0xFF,0xFE,0xD5,0xFC,0x5F,0xFB,0xF2, | ||
| 939 | 0xFF,0xFF,0x2F,0xBB,0xF3,0xFF,0xFF,0xBF, 0xFF,0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF, | ||
| 940 | 0xBF,0xFF,0xFF,0xFD,0x7B,0xFF,0xDF,0xB9, 0xFF,0xFB,0xFF,0xD8,0x7F,0xFF,0xFF,0xFF, | ||
| 941 | 0xFB,0xFF,0xFC,0x7F,0x1F,0xBF,0xE0,0xDF, 0xF7,0xEF,0xFF,0xFD,0x7F,0xFE,0xDF,0xFF, | ||
| 942 | 0xE0,0xFF,0xFF,0xFD,0xEF,0xFB,0xFF,0xFE, 0xF7,0xDF,0xFF,0xEB,0x5F,0xFF,0xF7,0xFF, | ||
| 943 | 0xFF,0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0xFD, 0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,0x3B,0xDC, | ||
| 944 | 0xFD,0x6D,0x7B,0x5F,0x57,0xF5,0xFD,0x7F, 0x5F,0xFF,0xB1,0xFF,0xEB,0xFF,0xFF,0xFF, | ||
| 945 | 0xFB,0xFB,0xFE,0xFF,0xBF,0xFB,0xBE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xAF,0xFE,0xF7, | ||
| 946 | 0xDF,0xDF,0xFF,0xFF,0xFF,0x7F,0xCF,0xF3, 0xF8,0xFF,0xD7,0xFB,0xFF,0x5F,0xBF,0xF7, | ||
| 947 | 0xFB,0xFF,0x7F,0xFE,0x23,0xFF,0xFF,0xFE, 0x7F,0xF3,0xFF,0xFB,0xFE,0xFF,0xFF,0xF3, | ||
| 948 | 0xFF,0xFF,0xF5,0xF9,0xFF,0x3F,0xFF,0xFF, 0xF0,0x9A,0xFF,0xBE,0x7F,0xFF,0xFC,0xF9, | ||
| 949 | 0xFF,0xFD,0xAF,0xEB,0xFE,0xBF,0xFF,0xCF, 0xF3,0xFE,0x7F,0xFF,0xFF,0x5B,0xBD,0xFF, | ||
| 950 | 0xBC,0xEB,0xFF,0xD7,0xD4,0xAF,0xAF,0xFD, 0xFF,0xCF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, | ||
| 951 | 0xFD,0xFE,0xFF,0x6F,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFD,0x7F,0x5E,0xFD,0xBF,0xDB,0xF6, | ||
| 952 | 0xFD,0xBF,0x6F,0xFB,0xEE,0xFD,0xFF,0x7A, 0xFF,0xFA,0xFB,0xFF,0x3F,0xFB,0xB7,0x5F, | ||
| 953 | 0xD6,0xF7,0x1F,0x71,0xDC,0x77,0x1D,0xC7, 0x31,0xDC,0x77,0xDF,0xF9,0xBF,0xF5,0x5B, | ||
| 954 | 0xF4,0xD7,0x9D,0xAE,0xFF,0xBF,0xFD,0xBF, 0xDB,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFE, | ||
| 955 | 0x3D,0x81,0xFF,0xEB,0xFE,0xFE,0xFE,0xFF, 0xEB,0x7A,0xDF,0x7D,0x77,0x7D,0xF5,0x79, | ||
| 956 | 0xDF,0x57,0xDD,0xF5,0x7D,0x7E,0xE6,0xFF, 0xD6,0x3F,0xBF,0x7F,0xFF,0xD4,0xF5,0x3F, | ||
| 957 | 0xBF,0xFB,0xBE,0xEF,0xB3,0xEE,0xFB,0x9E, 0xEF,0xBB,0xFE,0x8B,0xFF,0xFE,0xDF,0xB7, | ||
| 958 | 0xED,0xFF,0xF7,0xFD,0xFE,0xFF,0xEF,0xBB, 0xEE,0xFF,0xBE,0xEF,0xBB,0xEE,0xEB,0xFC, | ||
| 959 | 0x1F,0xFF,0xFF,0xFD,0xFF,0xE7,0xFF,0xF7, 0xFD,0xFF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, | ||
| 960 | 0xFE,0xFF,0xBF,0xEB,0xFA,0x1F,0xFF,0xB7, 0xEF,0x5B,0xFE,0xFF,0xAF,0xEB,0xDD,0xE7, | ||
| 961 | 0xDE,0x77,0x9D,0xE7,0x79,0xDE,0x77,0x9D, 0xBF,0xE6,0x6F,0xFF,0xFE,0xFF,0xBF,0xEF, | ||
| 962 | 0xFB,0xFE,0xFD,0xBF,0x6F,0xF6,0xFD,0xBF, 0x6F,0xDB,0xF6,0xFD,0xBF,0xFF,0x7E,0xFF, | ||
| 963 | 0xFF,0xFB,0xFE,0xFE,0xFF,0xEF,0xFB,0xFD, 0xEF,0x7E,0xF7,0xBD,0xEF,0x7B,0xDE,0xF7, | ||
| 964 | 0xBD,0xEF,0xFF,0xD5,0xFF,0xBF,0xFF,0xEF, 0xFE,0xFF,0xFC,0x3F,0x0F,0xE7,0xFE,0x7F, | ||
| 965 | 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFE, 0xF3,0xFF,0xFE,0xDF,0xAD,0xDF,0x67,0xEE, | ||
| 966 | 0xFB,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFF,0x23,0xFF,0xFF, | ||
| 967 | 0xFF,0xFF,0x7F,0xFF,0xF3,0xBC,0xDB,0xFE, 0xFB,0xFF,0xFB,0xBE,0xF7,0xFB,0xFF,0x7F, | ||
| 968 | 0xDF,0xFF,0xCF,0xFB,0xFF,0x9F,0xE3,0xF9, 0xBE,0x3F,0x8F,0xE7,0x79,0xFF,0x9D,0xE7, | ||
| 969 | 0xF9,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x5F, 0xFF,0xCF,0xF7,0xFF,0xFF,0xFF,0xDF,0xF7, | ||
| 970 | 0xFE,0x7F,0xE7,0xF9,0xFE,0x7F,0xFF,0xFF, 0xFB,0xFE,0xFF,0xFF,0xBF,0xFF,0xBF,0xBF, | ||
| 971 | 0xFF,0xFE,0xFF,0xBF,0xEF,0xFF,0xFD,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFD,0xFF, | ||
| 972 | 0xFF,0x3F,0xFF,0xBF,0xFF,0xF7,0xFF,0xFF, 0x7F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 973 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xE8,0xEF,0xFF, 0x5F,0xF7,0xBF,0xF9,0xFE,0xDF,0xB7,0xFD, | ||
| 974 | 0xFF,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xDD,0xFF,0xF2,0xFF,0xBF,0xFF, | ||
| 975 | 0xFF,0xBF,0xFF,0xFF,0x2F,0xF2,0xFF,0xBF, 0x2F,0x7B,0xD2,0xF7,0xBF,0x2F,0xFF,0xBB, | ||
| 976 | 0xFF,0xEE,0x8F,0xAF,0xEB,0xFA,0xFE,0x3F, 0xA7,0x69,0xCE,0x8F,0xA4,0xEA,0xFA,0xEE, | ||
| 977 | 0xB7,0xAE,0xEB,0xFD,0xC7,0xFF,0xF7,0xF7, 0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x3E,0xF3, | ||
| 978 | 0x74,0xFF,0x3F,0x4F,0xFF,0xE7,0xFF,0x3F, 0xFE,0xA7,0xFF,0xFF,0xDF,0xF7,0xB7,0xFF, | ||
| 979 | 0xF7,0xFF,0xBA,0xEF,0x37,0xEB,0xFB,0xFE, 0xBF,0xFB,0xFE,0xF3,0xFF,0xF9,0xDF,0xFF, | ||
| 980 | 0xBF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFD,0xDF,0xFF,0xFD,0xFF,0xFF,0xFB,0xFE, | ||
| 981 | 0xFD,0xFF,0xFB,0xBF,0xFE,0x3F,0xED,0xFF, 0xDF,0xBE,0x3D,0xA7,0xFB,0xFA,0x3F,0xE6, | ||
| 982 | 0xE1,0xFE,0xFE,0x3F,0xEF,0xE3,0xDF,0xF5, 0x7F,0xFE,0xFF,0x7E,0xFF,0xFF,0xFF,0xFF, | ||
| 983 | 0xEF,0x6F,0xF6,0xFF,0x7D,0xEF,0xD7,0xDE, 0xFF,0x7D,0xEF,0xFF,0xF2,0xFF,0xFF,0xFF, | ||
| 984 | 0xFF,0xFF,0xFF,0x7B,0xDE,0xFB,0xE6,0xEE, 0xEF,0x37,0x6E,0xF3,0x7E,0xEB,0x37,0xEF, | ||
| 985 | 0xFF,0xC1,0xFF,0xFE,0xFF,0xF7,0xEF,0xFF, 0xFF,0xFF,0xBF,0x3F,0xD2,0xDF,0xBF,0x2F, | ||
| 986 | 0x7B,0xE2,0xFF,0xFE,0x3B,0xBD,0xDB,0xFF, 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFE, | ||
| 987 | 0xFF,0xFB,0xFF,0xFF,0xBF,0xFF,0xFB,0xDF, 0xFF,0xBF,0xFF,0xB7,0xFF,0xFF,0xBF,0xEF, | ||
| 988 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, 0x7F,0xFF,0x1F,0xEF,0xF1,0xFD,0xFF,0xF6, | ||
| 989 | 0xAF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF, 0xFF,0xFF,0xFE,0x9F,0xFF,0xFF,0xFF,0x77, | ||
| 990 | 0xEF,0xF7,0xFB,0xFF,0xFE,0x5F,0xFF,0xFF, 0xBF,0xCF,0xFB,0xF7,0xDD,0xF7,0xF5,0xFF, | ||
| 991 | 0x5F,0xD5,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5, 0xFF,0xFB,0x0F,0xFF,0xFF,0xA9,0xEA,0x7A, | ||
| 992 | 0xFF,0xAF,0x8F,0xFE,0xDF,0xAF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFB,0xDF,0xE5,0x5F, | ||
| 993 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xBD,0x57,0xFF, 0xFF,0x6F,0x77,0xBF,0xF7,0xFB,0xFF,0x7F, | ||
| 994 | 0xBF,0xF7,0xFF,0xFC,0xBF,0xFF,0x9F,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF,0x1F, | ||
| 995 | 0xCF,0xFF,0xFC,0xFF,0xFF,0xFF,0xFF,0xFB, 0x65,0xAF,0xF3,0x7C,0xFF,0x3F,0xDF,0xFF, | ||
| 996 | 0xFD,0xE9,0xFE,0x7F,0xE7,0xFF,0xFE,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFD,0xE3,0xDF,0xFB, | ||
| 997 | 0xDB,0xF6,0xFD,0xEF,0x5B,0xFB,0xFF,0xDF, 0xFC,0xFF,0x3F,0xDF,0xF3,0xFD,0xFF,0x7F, | ||
| 998 | 0xDF,0xEF,0x66,0xFF,0xDF,0xAD,0xEB,0x7A, 0xDE,0xF7,0xF7,0xE7,0xD9,0xFD,0x9F,0x67, | ||
| 999 | 0xD9,0xF6,0x7D,0x9F,0xE7,0xDF,0xF5,0x47, 0xFD,0x65,0x5B,0xD6,0xF4,0xFE,0xFF,0xEF, | ||
| 1000 | 0xFF,0x6D,0xF6,0xDD,0xB7,0x6D,0xDB,0x76, 0xDC,0xB7,0x7D,0xFA,0x9B,0xF6,0x6D,0x9D, | ||
| 1001 | 0x67,0x59,0xDF,0xF7,0xDD,0xFF,0xEB,0xFE, 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xE3, | ||
| 1002 | 0xD1,0x9F,0xFF,0xBD,0xBF,0xEF,0xFE,0xF7, 0xBF,0xBF,0xF7,0xD7,0x7F,0xDD,0xF7,0x9D, | ||
| 1003 | 0xDF,0x7F,0xDF,0xF7,0xFF,0xE0,0x7F,0xFD, 0xC1,0xDF,0xF7,0xFD,0xC7,0x7F,0x7F,0xFB, | ||
| 1004 | 0xFF,0xBB,0xEC,0xFB,0x3E,0xFF,0xBF,0xEC, 0xFB,0xFF,0xD8,0x7F,0xBF,0x6C,0xFF,0xBE, | ||
| 1005 | 0xFF,0xBF,0xED,0xFF,0xEF,0xFE,0xFB,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEE,0xFF,0xC5, | ||
| 1006 | 0xFF,0xAF,0x6F,0xFF,0xFC,0xFD,0x3F,0xE7, 0xFF,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, | ||
| 1007 | 0xEF,0xFB,0xFE,0xBF,0x89,0xFE,0xFA,0xBA, 0xFE,0xBF,0xAF,0xFB,0xF6,0xF5,0xD9,0x7D, | ||
| 1008 | 0x97,0x65,0xD9,0x74,0x5D,0x97,0x65,0xD3, 0xFE,0xD6,0xFF,0xBF,0xF7,0xFD,0xFF,0x7F, | ||
| 1009 | 0xBF,0xCF,0xFB,0xFE,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFF,0xF6,0x8F,0xFB, | ||
| 1010 | 0xFF,0xEF,0xFB,0x7E,0xDB,0xFE,0xFF,0xBE, 0xEF,0xEE,0xFB,0xBE,0xEF,0xBB,0xEE,0xFB, | ||
| 1011 | 0xBE,0xFF,0xFF,0xDF,0xFF,0x43,0xFF,0xFF, 0xFB,0xEF,0x5F,0xB7,0xFE,0x7F,0xE7,0xF9, | ||
| 1012 | 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xF9, 0xBF,0xFE,0xAF,0x77,0xFD,0xFF,0x2F,0xAF, | ||
| 1013 | 0xA7,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xF1,0x7F,0xEF,0xDF, | ||
| 1014 | 0xFF,0x97,0xF5,0xEF,0xFF,0xDF,0xFF,0xFF, 0xBF,0xFF,0xBF,0xFF,0xFF,0xFE,0xFF,0xFF, | ||
| 1015 | 0xFF,0xE0,0xFF,0xFF,0xF9,0xFE,0x2F,0x8B, 0xE3,0xF8,0xBE,0x77,0x9F,0xF9,0xDA,0x77, | ||
| 1016 | 0x9D,0xE7,0x79,0xDE,0x77,0x9F,0xDD,0xFF, 0xFD,0xFD,0x7F,0x5F,0xD7,0xFD,0xFF,0x7F, | ||
| 1017 | 0xE7,0xFE,0x7F,0x97,0xE7,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFF,0xAB,0xFF,0xEF,0xFA,0xFE, | ||
| 1018 | 0xBF,0xAF,0xFF,0xFA,0xFF,0xFF,0xDF,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF, | ||
| 1019 | 0x67,0xFF,0xF7,0xF5,0xFF,0xFF,0xFF,0xDF, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1020 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xBD, 0xEB,0xFF,0xFF,0xF7,0xAD,0xEB,0xFF,0xDF, | ||
| 1021 | 0xFD,0xFF,0x3F,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0xFD, | ||
| 1022 | 0xBF,0xFF,0xCB,0xF4,0xFF,0x7F,0xD3,0xF7, 0xFD,0x3F,0x7F,0xD3,0xF7,0xFF,0xFC,0x3F, | ||
| 1023 | 0xFF,0xEA,0xFA,0xBE,0xAF,0xAB,0xEB,0xBA, 0xF4,0x95,0x6B,0x52,0xD4,0xAD,0x2F,0x4A, | ||
| 1024 | 0xD2,0xF6,0xBF,0xD2,0x7F,0xF7,0x3F,0xFF, 0xFF,0xF3,0x7F,0xFF,0xFF,0xF7,0xFF,0xBA, | ||
| 1025 | 0xDF,0xFB,0xFD,0xFF,0xBF,0xFF,0xFB,0xFF, 0xF8,0x7F,0xEA,0xFF,0xFE,0xFE,0xDF,0xFF, | ||
| 1026 | 0xF7,0xFF,0x7F,0xBB,0xFF,0xFF,0xBF,0xDF, 0xFB,0xFF,0xFF,0xBF,0xFF,0xB1,0x7F,0xFF, | ||
| 1027 | 0xFB,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, 0xCF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF7,0xFF, | ||
| 1028 | 0xFF,0xFF,0xF1,0xFF,0x69,0xBE,0xFA,0xBF, 0xAF,0xE2,0xFF,0xFE,0xFD,0xAF,0xF3,0xFE, | ||
| 1029 | 0xFF,0xBF,0xEF,0xFB,0xFC,0xFF,0xFF,0x07, 0xFD,0x95,0xDB,0xDF,0x7F,0xDF,0xAF,0xFF, | ||
| 1030 | 0xF7,0xAF,0x36,0xFE,0xBF,0x65,0xEB,0xF6, 0xFE,0x9F,0x6F,0xFE,0x07,0xFF,0xCF,0xFF, | ||
| 1031 | 0xF8,0xFE,0xFF,0xCF,0xFF,0xF6,0xFA,0xE7, 0xFB,0xFE,0xFF,0xBB,0xED,0xF9,0xFF,0xFF, | ||
| 1032 | 0xFF,0x5F,0xFF,0xFF,0xFF,0x75,0xFF,0xEF, 0x7E,0xFD,0xE0,0xE8,0x5E,0xD3,0xE5,0xF9, | ||
| 1033 | 0x3E,0x5F,0xD7,0xF7,0xFF,0xFA,0x2F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0x7F, | ||
| 1034 | 0x7F,0xD7,0xF5,0x7D,0x5F,0x57,0xD5,0xF5, 0xEF,0xFF,0xF3,0x7F,0xFC,0x7F,0xFF,0xC7, | ||
| 1035 | 0xF1,0xFF,0xFF,0x1F,0xCF,0xB0,0xFF,0x3F, 0xCF,0xF3,0xFC,0xFF,0x3F,0xCE,0xFF,0xE4, | ||
| 1036 | 0xFF,0xDF,0x7F,0xFE,0xF7,0xBB,0xFF,0xFF, 0xDF,0xEF,0xEE,0xFF,0xBF,0xEF,0xFB,0xFE, | ||
| 1037 | 0xBF,0xBF,0xEF,0xFF,0xD1,0xFF,0xFF,0xFF, 0xFD,0xFB,0xFF,0xFD,0xFF,0xFB,0x9F,0xE9, | ||
| 1038 | 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xBF, 0xFF,0xB3,0xFF,0xFF,0xF7,0xFF,0xFF,0xAF, | ||
| 1039 | 0xF7,0xFF,0xB6,0x3F,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFA,0xFE,0xBF,0xFE,0xA7,0xFF, | ||
| 1040 | 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF, 0xFE,0x9F,0xF7,0xF9,0xFF,0x7F,0x9F,0xE7, | ||
| 1041 | 0xFF,0xFF,0xFE,0xAF,0x6F,0xFF,0xFF,0xFF, 0x9F,0xFF,0xDF,0xFF,0x7D,0x5F,0xDD,0xFF, | ||
| 1042 | 0xFB,0xBF,0xE7,0xBB,0xFF,0xFB,0xDF,0x6D, 0x5F,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1043 | 0xEB,0xF7,0xFF,0xE7,0xEF,0xF7,0xFF,0xFF, 0x7F,0xFF,0xF7,0xFF,0xFC,0x8F,0xFF,0xEF, | ||
| 1044 | 0xFD,0xFE,0xFF,0xBE,0xF4,0xF2,0x7D,0xD7, 0xCF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1045 | 0xFF,0xCF,0x6B,0xFF,0xBF,0x3F,0xFB,0xF2, 0xFC,0x7F,0xEB,0xFF,0x9F,0xFA,0xFF,0xFF, | ||
| 1046 | 0x3F,0xFF,0xF3,0xFF,0xFF,0xFD,0x70,0xF7, 0xFF,0xFF,0xBF,0xFF,0xFB,0xD7,0xFE,0xF5, | ||
| 1047 | 0x77,0xFF,0x15,0xDD,0x77,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFB,0xCD,0xBF,0xFF,0xFD,0xFF, | ||
| 1048 | 0xFF,0xDF,0x37,0xCD,0xF9,0xEC,0xFE,0xEF, 0xBB,0xF4,0xFB,0x3F,0x4F,0xB3,0xFF,0xFD, | ||
| 1049 | 0xCB,0xFF,0xE9,0x7E,0x54,0x9F,0xE5,0x4B, 0xB7,0xFF,0xDD,0x7D,0xC7,0x71,0xDD,0x77, | ||
| 1050 | 0x5D,0xD7,0x75,0xCD,0x7F,0xD6,0xFF,0xD3, 0xF6,0xF9,0x3F,0x6D,0x95,0xAF,0x7F,0xFE, | ||
| 1051 | 0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xF6,0xC7,0xFF,0xAD,0x7B,0xCA,0xFF, | ||
| 1052 | 0xBF,0xBF,0xEF,0xFD,0xE3,0xDF,0xB7,0xED, 0xFB,0x7E,0xDF,0x37,0xED,0xE3,0xFB,0xDF, | ||
| 1053 | 0xFF,0x52,0x5C,0x15,0xFD,0xCF,0x7F,0xDF, 0xFE,0xEF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEC, | ||
| 1054 | 0x7B,0xFE,0xFF,0xFE,0x3E,0x7F,0xDA,0xF7, 0xFD,0xFF,0x7F,0xFF,0xFF,0xFB,0xEF,0xBB, | ||
| 1055 | 0x6F,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, 0xF7,0x7D,0xFF,0xD8,0xFF,0xFD,0xBF,0x7F, | ||
| 1056 | 0xFB,0xFF,0xFF,0x9F,0xFB,0xFE,0x7F,0x9F, 0xE7,0xF9,0xFE,0x7F,0x9F,0xEA,0x7F,0xF6, | ||
| 1057 | 0xBF,0xBD,0x6A,0x5A,0xF6,0xE5,0xBF,0x77, 0x5F,0x6D,0xDD,0x77,0x5D,0xD7,0x75,0xDD, | ||
| 1058 | 0x77,0xFF,0xA5,0xBF,0xCF,0xFB,0xFF,0xFF, 0xBF,0xCF,0xFB,0xFD,0xFF,0xBF,0xF3,0xFE, | ||
| 1059 | 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD,0xAB, 0xFF,0xBF,0xBF,0xFF,0xFB,0xFF,0x7F,0xEF, | ||
| 1060 | 0xFF,0xBE,0xFB,0xEE,0xFB,0xBE,0xEF,0xBB, 0xEE,0xFB,0xBF,0xFF,0xB5,0xFF,0xD0,0xBC, | ||
| 1061 | 0xFD,0x2F,0x4B,0xF7,0xFF,0xFF,0x9F,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x9F, | ||
| 1062 | 0xFA,0x8F,0xFD,0xAB,0xFA,0xDA,0xBF,0xAF, 0xB3,0xFD,0xFF,0xBF,0xFB,0xFE,0xFF,0xBF, | ||
| 1063 | 0xEF,0xFB,0xFE,0xF7,0xBF,0xFF,0x9F,0xFF, 0x77,0xF7,0xBD,0xFD,0x77,0xDF,0xFF,0x7E, | ||
| 1064 | 0xDF,0xED,0xBB,0xFE,0xFF,0xBE,0xEF,0xFB, 0xFE,0xFF,0xFA,0x3F,0xFF,0xBE,0x6F,0x8F, | ||
| 1065 | 0xE6,0xF9,0xFE,0x7F,0x9F,0xC7,0xFE,0x7F, 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFB, | ||
| 1066 | 0x7F,0xFF,0x7F,0xCF,0xFF,0xFD,0xFF,0xFF, 0xDF,0xFB,0xAF,0xBF,0xEF,0xFF,0xFE,0xFF, | ||
| 1067 | 0x9F,0xEF,0xFB,0xFF,0xFC,0xFF,0xFB,0xFE, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xF7, | ||
| 1068 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF5,0xFF,0xFF,0xFF,0x3F,0xDF,0xF7, | ||
| 1069 | 0xFF,0xFF,0x7F,0xEF,0xFE,0xFF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xEF,0xFF,0xB3,0x7F, | ||
| 1070 | 0xFF,0x7B,0x5E,0xF7,0xFD,0xFF,0x7B,0x7F, 0xF7,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F, | ||
| 1071 | 0xDF,0xF7,0xFF,0x17,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xDD,0xF6,0xFC,0xBF,0xCB,0xF2, | ||
| 1072 | 0xBC,0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xFE, 0x8F,0xFF,0xFA,0x7E,0xBF,0xA7,0xEB,0xDA, | ||
| 1073 | 0xFC,0xBF,0xAF,0x7A,0xFE,0xBF,0xAF,0xEA, 0xFA,0xFE,0xBF,0xAF,0xF4,0xDF,0xFE,0xFF, | ||
| 1074 | 0xF3,0x3C,0x7F,0x3E,0xFF,0xCF,0xF8,0xBF, 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xE7,0xE8, | ||
| 1075 | 0xFF,0xFC,0x9F,0xFF,0xFF,0xCF,0xEB,0xB3, 0xE7,0xFB,0x7B,0xF3,0xFE,0xFF,0xCF,0xDB, | ||
| 1076 | 0xFB,0xFB,0xBF,0x6F,0x6F,0xDF,0xEC,0x7F, 0xFF,0xFF,0xF7,0xFD,0xFD,0xFF,0xFF,0xFF, | ||
| 1077 | 0xFF,0xB2,0xBF,0xFF,0xDE,0xFD,0xBD,0xEF, 0xFB,0xF6,0xDF,0xEA,0xE7,0xDB,0xFE,0xBB, | ||
| 1078 | 0xFF,0xEB,0xFB,0xBF,0x9F,0x8F,0xE8,0xFE, 0x3F,0x8F,0xA3,0xF8,0xFE,0x3F,0x8F,0xFF, | ||
| 1079 | 0xF8,0x7E,0xFD,0xFD,0x7F,0xFF,0xFB,0xCD, 0xFF,0xFD,0xFF,0x5F,0xEF,0xFD,0xFF,0xFF, | ||
| 1080 | 0xDF,0xF7,0xFD,0xFF,0xBE,0x90,0xFF,0xFF, 0xEE,0xFF,0x3F,0xBF,0xF3,0xBB,0xFE,0xB7, | ||
| 1081 | 0xAB,0xFA,0xFE,0xAF,0xAD,0xEA,0xFA,0xDE, 0xAB,0xFF,0x63,0xFF,0xFE,0xF2,0xFF,0xB3, | ||
| 1082 | 0xFF,0xDF,0xEE,0x7D,0xFF,0x03,0xF1,0xF4, 0x3F,0x1F,0xC3,0xF1,0xEC,0x7F,0xFE,0x6F, | ||
| 1083 | 0xFF,0xFB,0xFB,0xFF,0x9F,0xFF,0xBF,0xFF, 0x7B,0x5F,0xFD,0xFF,0xDF,0xF7,0xFD,0xFD, | ||
| 1084 | 0x7F,0x7F,0xDF,0xFE,0xCF,0xFB,0xFF,0xFF, 0xAF,0xFB,0xFF,0x1F,0xEF,0xA5,0xFD,0xBF, | ||
| 1085 | 0xDF,0xFB,0x7D,0xFF,0xBF,0xDF,0xFB,0xFF, 0xFD,0x3B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, | ||
| 1086 | 0xAF,0xF3,0xFF,0xFB,0x7F,0xBF,0xD7,0xFB, 0xBF,0x7F,0xBB,0xF7,0xFF,0xF8,0x7F,0xFF, | ||
| 1087 | 0xFA,0x5F,0xD7,0xFF,0xDF,0x7F,0xEF,0xFF, 0xFF,0x7F,0xDB,0xF7,0xFD,0xFF,0x7F,0xDF, | ||
| 1088 | 0xB7,0xFB,0xEC,0xFF,0xFF,0xF7,0xBF,0xEF, 0xFD,0xFC,0xFB,0xFF,0xEF,0xF0,0xFE,0x3F, | ||
| 1089 | 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xEF,0x8D, 0xFF,0xFF,0xEF,0x7F,0xBF,0xFF,0xFB,0xFF, | ||
| 1090 | 0xDB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0xD8,0xFF,0x2E,0x7F, | ||
| 1091 | 0xBE,0xEF,0xFE,0x6E,0xFF,0xBF,0xF9,0xFF, 0xFF,0xF3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1092 | 0xFC,0x66,0xBE,0x47,0xF3,0x7F,0xDF,0xFE, 0x87,0x9F,0xFF,0xFF,0xFF,0xFF,0xE7,0xFF, | ||
| 1093 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xD6,0x6F,0x7C, 0xFB,0x4F,0xD2,0xFF,0xFD,0x2B,0xFE,0xFF, | ||
| 1094 | 0xFF,0xFD,0x5F,0xD7,0xD5,0xF5,0x7D,0xFF, 0xFF,0xFF,0xBF,0x9B,0xFF,0xFF,0xDF,0xB7, | ||
| 1095 | 0xFF,0xFF,0xDF,0xFF,0x3F,0xCF,0xFE,0x7F, 0xBF,0xEF,0xFB,0xFC,0xFF,0x3F,0xFF,0xD9, | ||
| 1096 | 0xBF,0xFE,0x97,0xEC,0x8F,0xB7,0xFE,0x9B, 0x7D,0xFD,0xB7,0xDD,0x77,0x1D,0xC7,0x71, | ||
| 1097 | 0xDD,0x77,0x5D,0xD7,0xF3,0x6F,0xFD,0x3F, 0x73,0xDD,0xAF,0xFD,0x7A,0xFF,0xFF,0xAF, | ||
| 1098 | 0xFE,0xFD,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0x66,0x7F,0xFF,0xFF,0xBF,0xBF,0xFF, | ||
| 1099 | 0xFB,0xFF,0xF7,0xDF,0xFD,0xFB,0x7D,0xDF, 0xB7,0xCD,0xF3,0x7C,0x5F,0x3F,0x91,0x3F, | ||
| 1100 | 0xFF,0x3D,0xEF,0x7B,0xFF,0xFC,0xFF,0xCA, 0xEF,0xFE,0xFF,0xBD,0xEF,0xFB,0x1E,0xE7, | ||
| 1101 | 0xBB,0xEC,0x7F,0xB3,0xFF,0xFD,0x9F,0xFF, 0xFF,0xFE,0xFF,0xFF,0x7F,0xBF,0xFB,0xFE, | ||
| 1102 | 0xFF,0xBF,0xEF,0xFB,0xEE,0xFB,0xBF,0xDF, 0x67,0xFF,0xFF,0xBF,0xEF,0xDB,0xFF,0xBC, | ||
| 1103 | 0xFE,0x7F,0xFB,0xFF,0x9F,0xEF,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x87,0xFF,0xEE, | ||
| 1104 | 0xFB,0xBE,0xE5,0xBF,0xEF,0xF9,0xD7,0x65, 0xF7,0xDD,0xE7,0x7D,0xDF,0x77,0x5D,0xD7, | ||
| 1105 | 0x7F,0xF8,0x9B,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xBF,0xEF,0xFB,0xFF,0x7F,0xCF, | ||
| 1106 | 0xF3,0xFC,0xFF,0xBF,0xEF,0xFF,0xDB,0x3F, 0xEF,0xFB,0xFE,0xFF,0xDF,0xFF,0xFE,0xFB, | ||
| 1107 | 0xBB,0xEF,0xBF,0xEF,0xBB,0xEE,0xFB,0xBE, 0xEF,0xBB,0xFF,0xFC,0x7F,0xFD,0x3B,0x5B, | ||
| 1108 | 0xD6,0xE5,0xFD,0x4F,0xC3,0xFB,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, | ||
| 1109 | 0xB4,0xFF,0xFA,0xBC,0x8F,0xB2,0xE9,0xD2, 0x2E,0xCF,0xFB,0xFF,0xBF,0xEF,0xFB,0xFE, | ||
| 1110 | 0xFF,0xBF,0xEF,0xFB,0xFF,0xEC,0xFF,0xFD, 0xFD,0x7F,0xDF,0xF7,0xE4,0xDF,0x5F,0xFF, | ||
| 1111 | 0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xC3,0xFF,0xEF,0xE6,0xF8,0xFE, | ||
| 1112 | 0x3F,0x8B,0x83,0xF9,0xFE,0x7F,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x17, | ||
| 1113 | 0xFD,0xFF,0xFF,0xFF,0x7F,0x5F,0xF7,0x2C, 0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xE7,0xF9, | ||
| 1114 | 0xFE,0x7F,0x9F,0xFE,0x2F,0xFF,0xFF,0xEF, 0xFF,0xFE,0xBF,0xEF,0xAD,0xFF,0xFF,0x7F, | ||
| 1115 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFE,0xDF,0xFF,0xDF,0xFF,0xFD,0xFD,0x7F, | ||
| 1116 | 0xDF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0x3F,0xFE, | ||
| 1117 | 0xF7,0xFD,0xEF,0x7A,0xFF,0xB1,0xBD,0xFF, 0x7F,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD, | ||
| 1118 | 0xFF,0x7F,0xF3,0x27,0xFF,0xDF,0xFF,0xDD, 0xFF,0xFC,0x9B,0xFF,0xCB,0xFC,0xBF,0x2F, | ||
| 1119 | 0xCB,0xF2,0xFC,0xBF,0x2F,0xC9,0xFF,0xDE, 0xFF,0xDF,0xAF,0xEB,0xDA,0xFE,0xBB,0xAF, | ||
| 1120 | 0xEB,0xF8,0xF7,0xAF,0xE8,0xFA,0xFE,0xBF, 0xAF,0xEB,0xF2,0xFF,0xFD,0xFF,0xFF,0xEF, | ||
| 1121 | 0xBD,0xD7,0xBF,0xFF,0xFF,0xDE,0x8F,0xB8, 0xDE,0x37,0x8D,0xA3,0x78,0xDA,0x3F,0x8F, | ||
| 1122 | 0xFF,0xA1,0xFF,0xFF,0xFB,0xFB,0xFF,0xFF, 0xFF,0xFF,0xA7,0xBD,0xFB,0x76,0xFD,0xBF, | ||
| 1123 | 0xEF,0xDB,0xFE,0xBB,0xBF,0xFE,0x27,0x7F, 0xFF,0xFE,0xFE,0xFD,0xF5,0xFF,0xEF,0xF5, | ||
| 1124 | 0xDF,0x1F,0xE7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xFF,0xCD,0xFD,0xAE,0xFF,0xFA, | ||
| 1125 | 0x3E,0x3F,0xAB,0xFD,0xF8,0x7E,0x8F,0xE3, 0xF8,0xFE,0x3E,0x8F,0xE3,0xF8,0xFF,0xFE, | ||
| 1126 | 0x1F,0xEF,0xDF,0xBF,0xFE,0xDE,0xDF,0xD9, 0xFF,0xDF,0xBC,0xFF,0xFF,0x7F,0xFF,0xEF, | ||
| 1127 | 0xFD,0x7F,0xDF,0xF7,0xF9,0x3F,0xFE,0xFF, 0xFF,0x6F,0xFE,0xDE,0xBF,0xF7,0xED,0xEA, | ||
| 1128 | 0xFD,0x8F,0x83,0xF8,0xEA,0x3F,0x8F,0xEF, 0xFF,0xF4,0x7F,0xFF,0xEF,0xEF,0x7B,0xF3, | ||
| 1129 | 0xF1,0x5F,0xFF,0xFF,0xF1,0x3B,0x7F,0xDF, 0xF7,0xFD,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF, | ||
| 1130 | 0xFF,0xFF,0xF7,0xFF,0x6F,0xFF,0x7F,0xFF, 0xFF,0xF7,0xDE,0xF7,0xBF,0xEF,0xFB,0xF7, | ||
| 1131 | 0xFD,0xFF,0xFF,0xF5,0xFA,0xFF,0xFF,0xFB, 0xE7,0xFF,0xF3,0xF8,0x7F,0xF3,0xDF,0xFF, | ||
| 1132 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xEF, 0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, | ||
| 1133 | 0xFF,0x7F,0xFF,0x9F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xCF,0xFF,0x37,0xFF,0xFF, | ||
| 1134 | 0x7F,0xDF,0x77,0x5D,0xE7,0xFC,0xFF,0xBF, 0xF7,0xF5,0xFB,0xFF,0xFF,0xD7,0xF5,0xFB, | ||
| 1135 | 0xFF,0xFF,0x45,0xFD,0x7F,0xEA,0xFD,0xBE, 0xBF,0xDF,0xF7,0xFF,0xFF,0xDB,0xFB,0xFE, | ||
| 1136 | 0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0xFB,0x5F, 0x7F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1137 | 0xFF,0xFE,0xFF,0xEF,0xFD,0xFF,0x7F,0xDF, 0xFF,0xEF,0xFB,0xF8,0x0F,0xF3,0xFF,0xF9, | ||
| 1138 | 0x2E,0xFB,0xFE,0xFC,0xF3,0xEF,0xFF,0xFF, 0xBF,0xFF,0xFB,0xE7,0xFF,0xFE,0x7E,0xFF, | ||
| 1139 | 0xC0,0x6B,0xCF,0xFF,0x34,0xDF,0xF1,0xFD, 0xFF,0xEF,0xFF,0xFF,0xFF,0xDF,0xF7,0xFD, | ||
| 1140 | 0xCF,0x7F,0x9C,0xFD,0xFD,0x6C,0xF7,0xFF, 0xF6,0xFD,0xEB,0x2B,0x9F,0xFF,0xFC,0xFE, | ||
| 1141 | 0x7E,0xFF,0xFF,0xFF,0xFF,0xD7,0xF3,0xF7, 0xFF,0xFB,0xE1,0xBF,0xFF,0xEB,0x7A,0xDE, | ||
| 1142 | 0xD7,0xFB,0xFF,0xF9,0xFE,0xFF,0xFF,0xF3, 0xDE,0x7F,0xFD,0xE7,0x7F,0xFF,0xFD,0xBB, | ||
| 1143 | 0xFF,0xFF,0x7E,0xCC,0xF6,0xAF,0x5F,0x7F, 0xFE,0xF4,0x7D,0xF7,0xFD,0xBB,0x6E,0xDB, | ||
| 1144 | 0xB7,0xFF,0xF7,0xDF,0x66,0xFF,0xFF,0xF7, 0x3D,0xCF,0xDE,0xBD,0xFF,0xFF,0xDE,0xDB, | ||
| 1145 | 0x8D,0xF7,0x7E,0xDF,0xB7,0xEF,0x7F,0xFF, 0xF6,0x87,0xFF,0xFF,0xEF,0xFE,0xDE,0xBF, | ||
| 1146 | 0xFF,0xFF,0xFF,0xBB,0xEF,0xFD,0xFF,0x7B, 0xDE,0xF7,0x3F,0xFF,0xBF,0xFB,0xDB,0xFF, | ||
| 1147 | 0xF2,0xB6,0xFD,0xBD,0x7F,0xE7,0xFF,0xFF, 0xFF,0x6F,0xF7,0xFF,0xFF,0xFF,0xFE,0x77, | ||
| 1148 | 0xFF,0xBF,0xF8,0xAF,0xFF,0xDF,0xBF,0xFF, 0xBF,0x7F,0xFB,0xFF,0xFF,0xFF,0xDB,0xFE, | ||
| 1149 | 0xFF,0xBF,0xFF,0xFA,0xFF,0xFD,0xFF,0xF6, 0x7F,0xFF,0x9F,0xFF,0xFF,0x3F,0xEF,0xF8, | ||
| 1150 | 0xEE,0x7E,0x9F,0xBA,0xFE,0xBF,0x8F,0xEF, 0xFE,0xFE,0xF9,0xFF,0xFA,0x7F,0xFE,0x7E, | ||
| 1151 | 0xBF,0xAF,0xFB,0x96,0xFD,0x9F,0xEF,0x5E, 0x65,0xBE,0xEF,0x5B,0xB6,0xFF,0xBE,0xE3, | ||
| 1152 | 0xFF,0xB5,0xBF,0xFF,0xFD,0xFF,0x7F,0xFF, 0xEF,0xDF,0xFE,0xFF,0xBF,0xFB,0xFE,0xFF, | ||
| 1153 | 0xBF,0xCF,0xFF,0xFF,0xFF,0xFD,0x9B,0xFF, 0xFE,0xFB,0xFE,0xDF,0xFF,0x7F,0xFF,0xF7, | ||
| 1154 | 0xFE,0xFF,0xDF,0xFB,0xFB,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xB7,0xFE,0xFA,0xFF,0xAB, | ||
| 1155 | 0xEF,0xFF,0xFD,0xB5,0x7B,0x7F,0xFB,0xF7, 0xFD,0xFF,0xFF,0xDD,0xFF,0xEF,0x8F,0xFF, | ||
| 1156 | 0x2F,0xFF,0xFB,0x7C,0xFF,0x3F,0xDF,0x73, 0xEB,0xFE,0x3F,0xFF,0xEF,0xFB,0xFE,0xFF, | ||
| 1157 | 0xEF,0xFD,0xFF,0xBF,0xFD,0x0F,0xFF,0xFF, 0xFF,0xF5,0xF9,0xFF,0x7F,0xD7,0xFD,0xFF, | ||
| 1158 | 0xDF,0xFF,0xF7,0xFB,0xFF,0x7F,0xBF,0xFF, 0xFF,0xF0,0x9F,0xFF,0xFE,0x7F,0x8B,0xE3, | ||
| 1159 | 0xF9,0xDE,0x27,0x9B,0xE6,0xBE,0x7F,0x9B, 0xC3,0xF8,0xDE,0x7F,0x9D,0xE7,0xFE,0x7F, | ||
| 1160 | 0xFF,0xFF,0x5F,0xD7,0xFF,0xFF,0xFF,0x4F, 0xFB,0xFF,0xFF,0x7F,0xFF,0xAF,0xFF,0x9F, | ||
| 1161 | 0x7F,0xFB,0xFF,0xE8,0xFF,0xFF,0xFE,0xBF, 0xAF,0xFF,0xFF,0xFE,0xBF,0xEF,0xF7,0xFF, | ||
| 1162 | 0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFC,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, | ||
| 1163 | 0xFD,0x3F,0xCF,0xFF,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFD,0x7F,0xFF,0xFF,0x93,0xFF,0xFF, | ||
| 1164 | 0x7A,0xDF,0xF7,0xFF,0xFF,0x7B,0x7F,0xB7, 0xEF,0xFF,0xFF,0xFD,0xBF,0xFD,0xFB,0xFF, | ||
| 1165 | 0xF7,0xFF,0xD7,0xFF,0xFF,0xFF,0xFC,0x9F, 0x6F,0xCB,0xFF,0xF4,0xBB,0xDF,0xD6,0xFD, | ||
| 1166 | 0xBF,0x2F,0xD3,0xF7,0xFF,0xDF,0xFF,0xCF, 0xFF,0xFA,0xBE,0xBD,0xAF,0x6A,0xDA,0xBE, | ||
| 1167 | 0xBB,0xAB,0x3A,0xBE,0x2D,0xAE,0xEB,0xDA, 0xF6,0x3F,0xAD,0xF5,0xDD,0xFF,0xCF,0xF1, | ||
| 1168 | 0xFF,0xF9,0x7F,0xFF,0x73,0xFE,0xFF,0xCF, 0xC3,0xF4,0xF7,0x2F,0xF3,0xFF,0xFC,0xFF, | ||
| 1169 | 0x7C,0x1F,0xFF,0x3F,0x4F,0xFF,0x7E,0xFF, 0xEF,0xBD,0xF6,0xFE,0xFF,0x2B,0xEF,0xDC, | ||
| 1170 | 0xFB,0xFD,0xFF,0xFB,0xFF,0xEA,0x7B,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xF7,0xDF,0xFF, | ||
| 1171 | 0xE3,0x7D,0xFF,0xB7,0xFF,0xBF,0xFF,0xFF, 0xDF,0xFF,0xF8,0xFF,0xBF,0xFF,0xBF,0xEB, | ||
| 1172 | 0xE7,0xFA,0xFE,0x3D,0xBF,0xE9,0xFC,0xBF, 0xFF,0xFA,0xFB,0xFE,0xFF,0xFF,0xFF,0xD9, | ||
| 1173 | 0xFF,0xFF,0xFF,0xF6,0x7F,0xFF,0xF6,0x7D, 0xFF,0xDF,0xCF,0xFD,0xBF,0xFB,0xEF,0x7E, | ||
| 1174 | 0xFF,0x7F,0xFF,0xFF,0xD3,0xFF,0xFD,0xFB, 0xFF,0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xBF, | ||
| 1175 | 0xFE,0xFF,0xF7,0xEF,0xFF,0xFF,0xFF,0xFB, 0xFF,0x87,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF, | ||
| 1176 | 0x7B,0xFE,0xFF,0xFE,0x3B,0xF7,0xF7,0xFF, 0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, | ||
| 1177 | 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFF,0xAD,0xFF,0xFE,0xF7,0xFF,0xFF, | ||
| 1178 | 0x5F,0xFF,0xFF,0xDF,0xFF,0xFD,0xFF,0xF5, 0xFF,0xDF,0xFF,0xBD,0xFF,0xE9,0xFF,0xC7, | ||
| 1179 | 0xF3,0xFF,0xFF,0xF7,0xFF,0xF3,0xFF,0xF8, 0x3B,0xFF,0xFF,0x7B,0xDF,0xBF,0xFB,0xEF, | ||
| 1180 | 0xFB,0xFF,0xFB,0xF7,0xF7,0xBB,0xFF,0xFF, 0xFF,0xFF,0xFB,0xFF,0xFE,0x7F,0xF3,0x7F, | ||
| 1181 | 0x5E,0xB7,0xBF,0xFD,0x7F,0xFF,0xF9,0x7F, 0xFB,0xFF,0xEB,0xFD,0x7F,0x7F,0xFF,0xEF, | ||
| 1182 | 0xFB,0xE0,0x3F,0xFE,0xBF,0xBF,0xDF,0xFF, 0x7E,0xFF,0xF7,0xFF,0xFF,0xFE,0xBF,0xFF, | ||
| 1183 | 0xDB,0x78,0xFF,0xFF,0xFF,0xEE,0xA1,0xBF, 0xF5,0xDE,0xFB,0xF7,0xFF,0xFB,0xFF,0xFF, | ||
| 1184 | 0xFF,0xFF,0xFB,0xFF,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xEF,0xF0,0xFF,0xFF,0xFF,0xF3, | ||
| 1185 | 0xF7,0xFF,0xEF,0xFF,0xE7,0xCF,0xFF,0xFB, 0xFF,0xEF,0xFF,0xFF,0x9F,0x9F,0xEF,0xFC, | ||
| 1186 | 0x16,0xBF,0xFE,0xF3,0xE4,0xFF,0xFF,0xC6, 0xFF,0xE7,0xFF,0xFF,0xFD,0xFF,0xBF,0xFF, | ||
| 1187 | 0xFF,0x3F,0xFF,0xBF,0xD6,0xAF,0x7F,0xFE, 0x6B,0x7E,0x7F,0xFF,0xAF,0xFF,0xFF,0xBF, | ||
| 1188 | 0xFF,0x5F,0xFF,0xFE,0xFF,0xFF,0xFE,0xFF, 0xFF,0xBD,0xDB,0xFF,0xFE,0x5F,0xF2,0xFF, | ||
| 1189 | 0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xEF,0x7F,0xFF,0xFF,0xFF,0xFF,0xDE,0xBF, | ||
| 1190 | 0xFF,0xFF,0xEF,0xFB,0x77,0xFE,0xBD,0x7F, 0x5F,0xFF,0xFF,0xFF,0xDF,0x6F,0xED,0xFF, | ||
| 1191 | 0xFD,0xFF,0x7F,0xFD,0x6F,0xFF,0xFF,0x77, 0xDA,0xCF,0xFD,0x5F,0xFF,0xBF,0xFF,0xFF, | ||
| 1192 | 0xDF,0x7F,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, 0x66,0x7F,0xFF,0xFE,0xBF,0xE7,0xBF,0xFA, | ||
| 1193 | 0xFF,0xFE,0xFF,0xFF,0xFF,0xDF,0xFF,0x59, 0xEF,0xFF,0xEF,0xFB,0x7F,0x89,0xFF,0xFF, | ||
| 1194 | 0xE9,0xFF,0x6F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xFF,0xFF,0x7F,0xF2,0xF7,0xFF,0xFF,0xEF, | ||
| 1195 | 0xF8,0x7F,0xFB,0xFF,0xFD,0xFF,0xFF,0xD9, 0xFF,0xEF,0xBB,0xFF,0xFF,0xFF,0xBF,0xEF, | ||
| 1196 | 0xDE,0xFF,0xFF,0x9F,0x7F,0xDF,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xAF, | ||
| 1197 | 0xFF,0xFF,0xF7,0x3F,0xEB,0x9F,0xFE,0x7F, 0x9E,0x7F,0x9F,0xFE,0x87,0xFF,0xED,0xDB, | ||
| 1198 | 0x56,0xFF,0xBF,0xAF,0x0B,0xD2,0xFF,0xEF, 0xDB,0x6E,0x7D,0xBD,0x6F,0xF8,0xFE,0x3F, | ||
| 1199 | 0xFA,0x5B,0xFF,0xFD,0xBF,0xEF,0xFF,0xBF, 0x6F,0xDB,0xE6,0xFF,0xFF,0x3F,0xFF,0xDF, | ||
| 1200 | 0xFE,0xFF,0xFF,0xFF,0xFF,0xDA,0x3F,0xFF, 0xFB,0xFE,0xFE,0xFF,0xFF,0xDF,0xF7,0xBD, | ||
| 1201 | 0xFF,0xFD,0xFF,0xFE,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xF1,0x5F,0xFD,0x9F,0xDF,0xFD, | ||
| 1202 | 0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,0xFF,0x76, 0xFA,0xFF,0xFF,0x7F,0xE3,0xF8,0xFF,0xAE, | ||
| 1203 | 0xFF,0xFB,0x7E,0x9D,0x73,0xFF,0xFA,0x7F, 0xDF,0xFF,0xFF,0x7F,0xFF,0xFB,0xCD,0xFF, | ||
| 1204 | 0x7F,0xEF,0xFB,0xFF,0xFD,0xFF,0xF7,0x7F, 0x7F,0xEF,0xFF,0xED,0xFF,0xFF,0xFF,0xB5, | ||
| 1205 | 0xFF,0xBF,0xFF,0xBF,0xFD,0xEF,0xDB,0xF7, 0xFF,0x93,0xFF,0xEF,0xE2,0xF9,0xBE,0x7F, | ||
| 1206 | 0x8B,0xE7,0xF9,0xFE,0x6B,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x47,0xFF, | ||
| 1207 | 0xFF,0xFD,0xFF,0x9F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xF5,0xFF,0x9F,0xFF,0xF7,0xFE, | ||
| 1208 | 0xFF,0xBF,0xFE,0x6F,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xAF,0xFF,0xFF,0xFF,0x7F,0xFB, | ||
| 1209 | 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xDF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xDF, | ||
| 1210 | 0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,0xFF,0xFF, 0x5F,0xFB,0xFE,0xFF,0xF8,0x37,0xFF,0xFF, | ||
| 1211 | 0xEF,0xFF,0x7F,0xFE,0xBF,0xFF,0xFF,0xFE, 0xBF,0xFF,0xFF,0x7F,0xFF,0xBF,0xFD,0xFF, | ||
| 1212 | 0x7F,0xFA,0x7F,0xFF,0xFF,0x6F,0xFF,0xFF, 0x7D,0xFF,0xCF,0xFF,0xFF,0xFF,0x4F,0xFF, | ||
| 1213 | 0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0xBF, 0xFF,0xAE,0xEB,0xFA,0xFE,0xBB,0xAD,0xEB, | ||
| 1214 | 0xFA,0xF7,0xAF,0x6B,0xFA,0xF6,0xBF,0x25, 0xE9,0xF2,0x7F,0x45,0xFF,0xFF,0xFD,0xF7, | ||
| 1215 | 0xF7,0xBF,0xFF,0xDF,0xFF,0xFF,0xBF,0xFB, 0xFF,0xDF,0xF3,0xFF,0xF7,0x3F,0xCF,0xFF, | ||
| 1216 | 0xA1,0xFF,0xFF,0xBF,0xE7,0xFF,0xFF,0x7F, 0xFF,0x3D,0xFF,0xFF,0xFF,0xF7,0xFF,0x2F, | ||
| 1217 | 0xFF,0xFB,0xF5,0x7F,0xFE,0x57,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7, | ||
| 1218 | 0x3F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,0xFE, 0xF7,0xEE,0xAF,0xFE,0xEE,0xE7,0xFA,0xFF, | ||
| 1219 | 0xFE,0x9D,0xF9,0x5E,0xFE,0xFF,0xEB,0xFF, 0xFF,0xDF,0xA7,0xFF,0xFF,0xFF,0xFC,0xDB, | ||
| 1220 | 0xFF,0xFF,0xFF,0x7E,0xFB,0xFF,0xFF,0xEF, 0xFB,0xFD,0xFF,0xDB,0xFF,0xFF,0xFF,0xEF, | ||
| 1221 | 0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,0xBF,0xFF, 0x6F,0x7F,0xFF,0xF7,0xFF,0xFF,0xF9,0xFF, | ||
| 1222 | 0xF7,0xFF,0xBF,0xDE,0xF7,0xFF,0xFF,0xFF, 0xFA,0x7F,0xFD,0xBF,0x5F,0xFF,0xFF,0xBF, | ||
| 1223 | 0xFF,0xED,0xFF,0xF7,0xBF,0xFF,0xFF,0xEF, 0xFF,0xDF,0xFF,0xFF,0xFF,0xE6,0xFF,0xFB, | ||
| 1224 | 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xFF, | ||
| 1225 | 0xFD,0xFF,0xF5,0xFF,0xF6,0x7F,0xDF,0xBD, 0xCF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF, | ||
| 1226 | 0xFF,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3, 0xFF,0xEE,0xBF,0xFF,0x7D,0xEF,0xFE,0xFF, | ||
| 1227 | 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,0xB5,0xAE, | ||
| 1228 | 0xFF,0xFF,0xB6,0xFE,0xBF,0xFF,0xFF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1229 | 0xFF,0x27,0xFF,0xEF,0xFE,0x7F,0xDF,0xFF, 0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1230 | 0xFF,0xFF,0xFD,0xFF,0xF7,0xF9,0x9F,0xFF, 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, | ||
| 1231 | 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x0F,0xFF,0xE7,0xBF,0xFE, | ||
| 1232 | 0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFC,0xBF, 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xC4, | ||
| 1233 | 0x6B,0xFF,0x29,0x1F,0xFB,0xAF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0x1B,0xFE,0xFF,0xFC, | ||
| 1234 | 0x6F,0xFF,0xFF,0xFD,0x6A,0xF7,0xD7,0xF5, 0xBF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1235 | 0xFE,0xBF,0xFF,0xFF,0xFA,0xFF,0xFF,0xF7, 0xFB,0xDD,0xBF,0xFF,0xE7,0xFF,0xFF,0xFF, | ||
| 1236 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x7F,0xFF, 0xFF,0xF5,0xFF,0xFF,0xF7,0xFD,0xB3,0xEF, | ||
| 1237 | 0xFD,0x7E,0x5D,0xFF,0xFD,0xFF,0xFF,0xFF, 0xFD,0x7F,0xD2,0xF5,0xFB,0x7E,0xCB,0xB7, | ||
| 1238 | 0xFF,0xFF,0xFF,0xC6,0xFF,0xFD,0xEE,0x63, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xFD,0x65, | ||
| 1239 | 0x5B,0xDF,0xFF,0xD5,0xFF,0xFF,0xFF,0xF6, 0xE7,0xBF,0xF7,0xA9,0xFF,0xFF,0xED,0xFF, | ||
| 1240 | 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFF,0xFF, 0xAF,0xFF,0xFF,0xFF,0xF8,0x1B,0xFF,0xE3, | ||
| 1241 | 0xD0,0xBF,0xFF,0xE1,0xFF,0xFF,0xFF,0xFF, 0xFF,0xD7,0xFF,0xFF,0xFF,0x5F,0xFF,0xFF, | ||
| 1242 | 0xFF,0xFF,0xAF,0xFF,0xDB,0x76,0xBF,0xFF, 0x7F,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF, | ||
| 1243 | 0xFB,0xFE,0xFF,0xFF,0xFF,0xBF,0xF2,0x7F, 0xFF,0x9F,0xFE,0xBD,0xFE,0x7F,0xFF,0xFF, | ||
| 1244 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF7,0x3F,0xEC,0x7F,0xF6,0x95,0xBB, | ||
| 1245 | 0xEF,0xF8,0xFE,0xFC,0xBF,0x2F,0xDA,0xFC, 0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xEF,0xFF, | ||
| 1246 | 0xA9,0xBF,0xCF,0xFB,0xFF,0xFF,0xFF,0xFE, 0xDD,0xB7,0x6D,0xF6,0xD9,0xB6,0x6D,0x9B, | ||
| 1247 | 0x76,0xD9,0xBF,0xFB,0xFD,0xA3,0xFF,0xBF, 0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0x7F,0xDF, | ||
| 1248 | 0xFD,0xEF,0x7B,0xDE,0xF7,0xFD,0xEF,0x7F, 0xFF,0xFF,0x05,0xFF,0xFA,0xFE,0x7F,0xEF, | ||
| 1249 | 0xE3,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, 0xFF,0x5F,0xFF,0xFF,0xFD,0x7F,0xFB,0xAF, | ||
| 1250 | 0xFF,0x63,0xC8,0xFF,0xBF,0xEF,0xFF,0xFF, 0xFA,0x7F,0xFF,0xFF,0xFF,0xFE,0x9F,0xF7, | ||
| 1251 | 0xFF,0xFA,0xBF,0xFE,0x9F,0xFB,0x7F,0xFF, 0xFF,0xEF,0xD7,0xFF,0xFF,0xF5,0xFF,0xFF, | ||
| 1252 | 0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xBF,0xFF, 0xF9,0xBF,0xFF,0xBE,0x27,0x9F,0xE7,0xF9, | ||
| 1253 | 0xFE,0x7F,0x8B,0xE7,0xFE,0x7F,0x9F,0xE2, 0xF9,0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF, | ||
| 1254 | 0xFF,0xFF,0xFB,0xFE,0xFF,0xFF,0xFF,0xD7, 0xFF,0xFF,0xFF,0xFF,0xF5,0xFF,0xFF,0xFF, | ||
| 1255 | 0xD7,0xFF,0xFA,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF,0xAF,0xF7,0xFF,0xFF, | ||
| 1256 | 0xFF,0xEB,0xFF,0xFF,0xFF,0xAF,0xFF,0xC4, 0xFF,0xF7,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, | ||
| 1257 | 0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xD7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFB,0x7A, | ||
| 1258 | 0xDF,0xF7,0xFD,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0x7F,0xFF,0xAF,0xFF,0xFF,0xFF,0xF7, | ||
| 1259 | 0xEF,0xE3,0xFF,0xDD,0xD2,0xFF,0xDF,0xFF, 0xFF,0xF2,0xFC,0xBF,0xCB,0xF6,0xFD,0xBF, | ||
| 1260 | 0x2F,0xCB,0xFF,0x7F,0xDF,0xDE,0xAF,0xFF, 0xDA,0xEE,0xBF,0xAF,0xE9,0xFA,0xF4,0xBD, | ||
| 1261 | 0xAF,0x5A,0xAE,0xBB,0xAB,0x6B,0xDA,0xDE, 0xBF,0xAD,0xD7,0x5E,0xFF,0xFF,0xBF,0xFC, | ||
| 1262 | 0xFF,0xDF,0xFD,0xFF,0xFF,0xFF,0xFF,0xDF, 0xF7,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFA, | ||
| 1263 | 0x1F,0xFF,0xFE,0xFB,0xEF,0xBF,0xFD,0xFF, 0xFD,0xBD,0x77,0xFF,0xFF,0xFF,0xFF,0x9D, | ||
| 1264 | 0xEF,0xFF,0xFF,0xFF,0xEF,0x7D,0xFF,0xFB, 0xFE,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7, | ||
| 1265 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE, 0xBF,0xE4,0xFB,0xFF,0xFE,0x3F,0xFE,0xFF, | ||
| 1266 | 0xFF,0xFF,0xFF,0xAF,0xEA,0xFE,0xBF,0xAF, 0xEB,0xFA,0xFE,0xFF,0xFF,0xFF,0x55,0xF6, | ||
| 1267 | 0xFF,0xFE,0xF7,0xFF,0x7F,0xFF,0xEB,0xF7, 0x5F,0xC5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF, | ||
| 1268 | 0x6F,0xFB,0xFF,0x8A,0xFF,0xFF,0xFF,0xFF, 0xEB,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0xBF, | ||
| 1269 | 0xEF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0x77,0xDF,0xFB,0xFF,0xFD,0x7F,0xEF,0xFF, | ||
| 1270 | 0xFF,0xFF,0xBF,0x7F,0xFF,0xDF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xFF,0xFE,0xEF,0xDF,0xFF, | ||
| 1271 | 0xFE,0xFF,0x9F,0xEF,0x7D,0xFF,0xF7,0xFF, 0x7F,0xFF,0xFF,0xDF,0xF7,0xFD,0xFF,0xEF, | ||
| 1272 | 0xDF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFB, | ||
| 1273 | 0xFD,0xFF,0xBF,0xDF,0xD1,0xFF,0xF8,0x3B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1274 | 0x7E,0xDB,0xFD,0xFF,0x77,0xDB,0xB7,0x7D, 0xBF,0xFB,0xFF,0xF8,0x7F,0xED,0x7B,0x5E, | ||
| 1275 | 0xFF,0xFE,0xFF,0xFF,0x4F,0xD7,0xFD,0x7F, 0xDF,0xD7,0xF5,0xFF,0x7F,0xFF,0xFF,0xFF, | ||
| 1276 | 0xF2,0x3F,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFF,0xBF,0xEF,0xFE,0xFF,0x3B,0xEE,0xFF, | ||
| 1277 | 0xFC,0xEF,0xFF,0xFF,0xFF,0x85,0xFF,0xFD, 0xFE,0xFF,0xF5,0xFF,0xFF,0xFE,0xFF,0xDF, | ||
| 1278 | 0xFB,0xFF,0x5F,0xBF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xA8,0xFF,0xFF,0x9F,0x9E,0xFF, | ||
| 1279 | 0xFF,0xFF,0x7F,0xF3,0xFF,0xFF,0xCF,0xFF, 0xF7,0xFD,0xFF,0x7F,0xFF,0xFF,0xFC,0x16, | ||
| 1280 | 0xBF,0xCF,0xA3,0xE5,0xEF,0x7F,0xFF,0xF3, 0xE4,0xFF,0xCF,0x93,0xFC,0xFF,0x3F,0xCF, | ||
| 1281 | 0xFF,0xFF,0xFF,0xD6,0x0F,0x7D,0xBF,0x6E, 0xFB,0xF4,0xFC,0xAF,0x6D,0xDB,0x77,0xB7, | ||
| 1282 | 0x6D,0xDB,0xF6,0xFD,0xBF,0xFF,0xFF,0xFF, 0xBF,0x9B,0xFA,0xDE,0xB7,0xB7,0xED,0xF9, | ||
| 1283 | 0x7E,0xB7,0xAC,0xEB,0xD6,0xB3,0xAD,0xEB, 0x7A,0xDF,0xFF,0xFF,0xFF,0xD8,0xBF,0xFF, | ||
| 1284 | 0xB7,0xED,0x9F,0x6F,0xDD,0xF7,0x68,0xDB, 0x37,0xB3,0x6C,0xDB,0x36,0xCD,0xB3,0x7F, | ||
| 1285 | 0xFF,0x7F,0xF5,0x6F,0xFD,0xEF,0x79,0x3D, 0xF7,0x93,0xE4,0x7A,0x9E,0xAD,0xEA,0x7A, | ||
| 1286 | 0x9E,0xF7,0xBD,0xEF,0xFF,0xFF,0xFF,0x76, 0x7F,0xFB,0xC6,0xFF,0xBB,0xEF,0xDA,0xFE, | ||
| 1287 | 0xFD,0xBF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xFB,0xFF,0xA5,0xFF,0xFD,0xAB, | ||
| 1288 | 0x6F,0x78,0xDE,0x17,0x8F,0x79,0xDF,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xFF,0xFB, | ||
| 1289 | 0xFF,0xFB,0xFF,0xEF,0xFB,0xEF,0xFB,0xFE, 0xFF,0xBB,0xDA,0xF3,0xEF,0x3B,0xCE,0xF3, | ||
| 1290 | 0xBC,0xEF,0x3F,0xCF,0xDF,0xFF,0xB7,0xFF, 0xFF,0xFF,0xCF,0x73,0xFF,0xBF,0xEF,0xFF, | ||
| 1291 | 0xF3,0xFF,0x3F,0xCF,0xF3,0xFC,0xFF,0x3D, 0xCF,0x9F,0xFE,0x07,0xFF,0xAF,0xEB,0xFE, | ||
| 1292 | 0xFD,0xBF,0xEF,0xEB,0xFA,0xFF,0xAF,0xEB, 0xFA,0xFE,0xBF,0xAF,0xFB,0xFE,0x3F,0xFB, | ||
| 1293 | 0x9B,0xFF,0x7F,0xDF,0xFF,0xF3,0xFE,0xFF, 0xDE,0xF7,0xBF,0x7B,0xDE,0xF7,0xBD,0xEF, | ||
| 1294 | 0x7B,0xFE,0xFF,0xFF,0xDF,0x3F,0xFE,0xFF, 0xB7,0xFF,0xEF,0xF7,0xFF,0xBF,0xED,0xFE, | ||
| 1295 | 0xDF,0xB7,0xED,0xFB,0x7E,0xDF,0xFF,0xFF, 0xFF,0xFD,0x5F,0xEF,0xEB,0xFA,0xFE,0xF5, | ||
| 1296 | 0xBF,0x6F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xF8,0xFF,0xA8,0xFF, | ||
| 1297 | 0xFF,0xBF,0xEF,0xFB,0x6A,0xFB,0xB7,0xEF, 0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, | ||
| 1298 | 0xEF,0xFB,0xFF,0xE0,0xFF,0xFF,0xFD,0x7F, 0x5C,0xD7,0x7D,0xDF,0xF3,0x5C,0xF5,0xCD, | ||
| 1299 | 0x73,0x5E,0xD7,0xB5,0xFD,0x7F,0xEF,0xFF, 0xDB,0xFF,0xFF,0xE2,0xF8,0xBE,0x2F,0x8F, | ||
| 1300 | 0xE7,0xF8,0xBE,0x6B,0xE2,0xF8,0xBE,0x2F, 0x8B,0xE2,0xF9,0xFE,0x7F,0xE7,0xFF,0xD7, | ||
| 1301 | 0xF5,0xFD,0x7F,0xFF,0xF7,0xF5,0xFD,0x7F, 0xD7,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF, | ||
| 1302 | 0xFF,0xFF,0x8F,0xFF,0xAF,0xEB,0xFA,0xFF, 0xFF,0xBF,0xEB,0xFA,0xFF,0x2F,0xEB,0xFA, | ||
| 1303 | 0xFE,0xBF,0xAF,0xEB,0xFF,0xFF,0xFE,0x5F, 0xFF,0x5F,0xFF,0xFF,0xFD,0xFF,0xFF,0xD7, | ||
| 1304 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFE,0xB7,0xFD, | ||
| 1305 | 0xFF,0x7E,0xDF,0xF7,0xAD,0xFF,0x7F,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F, | ||
| 1306 | 0xF6,0x7F,0xFF,0xFF,0xFF,0xDB,0xF6,0xFC, 0xAF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF, | ||
| 1307 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xEC,0xBF,0xFF, 0xAF,0xEB,0xFA,0xF6,0xAB,0x8F,0xEB,0xFA, | ||
| 1308 | 0xF7,0xA5,0xEB,0xFA,0xBE,0xBF,0xAF,0xEB, 0xFA,0xFF,0x6D,0xFF,0xFF,0x7F,0xDF,0x33, | ||
| 1309 | 0xDD,0xFF,0x7F,0xFE,0xF7,0xFC,0x7F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA9, | ||
| 1310 | 0xFF,0xFD,0xFF,0xFF,0xFE,0xFF,0xFF,0xDF, 0xFF,0xFF,0xEF,0xEF,0xFD,0xFF,0x7F,0xFF, | ||
| 1311 | 0xFF,0xFF,0xFF,0xFE,0xA7,0xFF,0xFF,0xFF, 0x77,0xDF,0xF7,0xFD,0x9F,0x7F,0xFE,0x77, | ||
| 1312 | 0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xAF,0xBF,0xAF,0xFF,0xF9,0xBE,0xBF, | ||
| 1313 | 0x8F,0xFB,0xFE,0xFE,0xEF,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFF,0xFF,0xFD,0xDF,0x6F, | ||
| 1314 | 0xEF,0xFF,0x7F,0xFF,0xBF,0xBF,0xDF,0xFF, 0xFC,0xFF,0xDF,0xF7,0xFD,0xEF,0x7F,0xDF, | ||
| 1315 | 0xFF,0xFF,0xFF,0x3F,0xF6,0xFF,0xCF,0xFF, 0xDB,0xFB,0xF7,0xFF,0xEB,0x7A,0xFF,0xFF, | ||
| 1316 | 0xFF,0xBF,0xEF,0xFB,0xFF,0xFF,0xFF,0xFE, 0x6D,0xFD,0xFF,0x5F,0xFB,0xFF,0xFF,0xF7, | ||
| 1317 | 0xFF,0x5F,0xF5,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xFB,0xFF, | ||
| 1318 | 0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xE7,0xF6, 0xBF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF, | ||
| 1319 | 0xFF,0xC9,0xFF,0xFF,0xFF,0xBD,0xFF,0xBF, 0xAF,0xEF,0xEF,0x3F,0xD1,0xFC,0x7F,0xFB, | ||
| 1320 | 0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xFF, 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0x77,0xFF, | ||
| 1321 | 0xDF,0xB7,0xFD,0xF7,0xFD,0xF7,0xFF,0xFF, 0xFF,0xFF,0xFF,0x57,0xFF,0xF7,0xA5,0xFD, | ||
| 1322 | 0x3F,0xDF,0xBF,0xBF,0xFE,0x7F,0xFF,0xFF, 0xFF,0xDF,0xFA,0xFD,0xFF,0xFF,0xFF,0xFE, | ||
| 1323 | 0x87,0xFF,0xE9,0xFF,0xFE,0xEF,0xBF,0xEF, 0xFE,0xFE,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF, | ||
| 1324 | 0xFF,0xFF,0xFF,0xFF,0xFA,0x9F,0xFF,0x3F, 0xFF,0xFD,0xFD,0x57,0xDF,0xFD,0xF3,0xFF, | ||
| 1325 | 0xDF,0xFD,0xFF,0x5F,0xDF,0xF5,0xFD,0xFF, 0xFF,0xF9,0x8F,0xFF,0xFF,0xFF,0xEE,0x7F, | ||
| 1326 | 0xFF,0xFF,0xBF,0x5E,0xFE,0xEC,0xFB,0x3F, 0x7F,0x9F,0xEF,0xF9,0xFF,0xFF,0xCD,0x6B, | ||
| 1327 | 0xFF,0xFF,0xFF,0xC5,0xF3,0xFC,0xFA,0x38, 0xFF,0xAF,0x3F,0xEE,0x7F,0x9F,0xFF,0xD9, | ||
| 1328 | 0xFF,0xFF,0xFD,0x7A,0xF7,0xFF,0xF3,0xFF, 0xAF,0x6F,0xDB,0xF2,0xB9,0xE9,0xFB,0xFF, | ||
| 1329 | 0xFF,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xFB, 0xC5,0xBF,0xFF,0xEF,0xFF,0x5E,0xB7,0xAD, | ||
| 1330 | 0xCD,0x79,0x7C,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0x93,0xFF,0xEF, | ||
| 1331 | 0xEA,0xFE,0xBF,0xEF,0x5B,0xD2,0xCD,0xF5, 0x6D,0x77,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF, | ||
| 1332 | 0xFF,0xFF,0x66,0xFF,0xD5,0x65,0x7D,0x5F, 0x75,0x9D,0x65,0x7F,0xD6,0xFB,0x4F,0xFF, | ||
| 1333 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xC7, 0xFF,0xBF,0xEF,0xFA,0xFE,0xFF,0xBF,0xEB, | ||
| 1334 | 0xFF,0xDF,0xFF,0x7E,0xFF,0xFF,0xEF,0xFD, 0x7E,0xD7,0xFF,0x78,0xDF,0xFF,0x5F,0xDF, | ||
| 1335 | 0xF5,0xBF,0x7F,0xDF,0xC5,0xFF,0x3F,0xF6, 0x7E,0xFF,0x0F,0xEF,0xF2,0x3E,0xBF,0xFF, | ||
| 1336 | 0xFB,0x3F,0xFF,0xFB,0x7F,0xFF,0xB3,0xFE, 0xFB,0xF6,0xFD,0xFF,0xDA,0xF7,0xFD,0xFF, | ||
| 1337 | 0x7F,0xDF,0xF7,0xBF,0xFF,0xFA,0x7F,0xFF, 0xFF,0xFF,0xFF,0x9F,0xFF,0xF3,0xDC,0xF9, | ||
| 1338 | 0xBF,0xCE,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7, 0xFF,0xFF,0xE2,0x7F,0xFE,0xFF,0xBF,0xEF, | ||
| 1339 | 0xEB,0xFA,0xFF,0x9F,0x67,0x1E,0xFF,0x8F, 0xE7,0xF8,0xFE,0x7F,0x8F,0xEF,0xFF,0xBD, | ||
| 1340 | 0xBF,0xFF,0xFB,0xFF,0xFF,0xDF,0xF7,0xFF, 0xFC,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1341 | 0xFF,0xFF,0xFF,0xFD,0xB3,0xFF,0xFF,0xEF, 0xFF,0xFF,0xBF,0xED,0xFF,0xFB,0xEE,0xFE, | ||
| 1342 | 0xFF,0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFF,0xB5,0xFF,0xB7,0xFD,0xFD,0x6E,0xFF, | ||
| 1343 | 0xFF,0xFE,0xFD,0x2F,0xD8,0xFE,0xBF,0x8F, 0xEB,0xF9,0xFE,0x3F,0xFF,0xFA,0xCF,0xFF, | ||
| 1344 | 0xE7,0xD9,0xFA,0xBF,0xDF,0x77,0xFC,0xFB, 0x3F,0xAB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFE, | ||
| 1345 | 0xFF,0xFF,0xEE,0x1F,0xFF,0xDF,0xF7,0xFF, 0xFF,0xFF,0x5F,0x97,0x35,0xBF,0x5E,0xFE, | ||
| 1346 | 0xBF,0xEF,0xFF,0xF7,0xFD,0xFF,0xFF,0xFA, 0xBF,0xFF,0xBE,0x6F,0x9F,0xE7,0xF8,0xBE, | ||
| 1347 | 0x2F,0x8B,0x66,0x94,0x7D,0x9D,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,0xFF, | ||
| 1348 | 0xFF,0xF7,0xF5,0xFD,0x7F,0x5F,0xFB,0xFD, 0x9E,0xFF,0xFB,0xFE,0xFF,0xFF,0xEF,0xFF, | ||
| 1349 | 0xFF,0xA0,0xFF,0xFF,0xFF,0xBF,0xEF,0xEB, 0xFA,0xFE,0xBF,0xB7,0xF7,0xF7,0xFF,0xFF, | ||
| 1350 | 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xFD,0xFF,0xFF,0xFF,0xD7,0xFF,0xFF,0xFF, | ||
| 1351 | 0x7F,0xF5,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xFF,0xAB,0xFE,0xFB,0xFE,0xFF, | ||
| 1352 | 0xF7,0xAF,0xFF,0xFF,0xDE,0xF7,0xEB,0x5F, 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,0xFF, | ||
| 1353 | 0xB3,0xFF,0xC9,0xFE,0xFF,0xFF,0xFF,0xFF, 0xD6,0xFF,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF, | ||
| 1354 | 0xFF,0xFF,0xFF,0xFF,0xFC,0x8F,0xFF,0xBA, 0xBE,0xBF,0xAF,0xEB,0x78,0xFE,0xB7,0xAD, | ||
| 1355 | 0x3A,0xFE,0xB7,0xAF,0xEB,0x7A,0xFE,0xBF, 0xAF,0xFF,0x9F,0xFF,0xFF,0xDF,0xFC,0xFF, | ||
| 1356 | 0xFF,0xFE,0xC3,0xFE,0xFF,0xFF,0x33,0xFC, 0xFF,0xBF,0xDF,0xF3,0xFF,0xFF,0xBB,0x9F, | ||
| 1357 | 0xFF,0xFF,0xFF,0xEB,0xDF,0xFF,0xFF,0xAF, 0xF7,0x6F,0xF9,0xBF,0xEF,0xFD,0xFF,0xFF, | ||
| 1358 | 0xFF,0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xFD,0xFB,0xF7,0xFF, | ||
| 1359 | 0xDF,0xF7,0xFF,0xFE,0xEF,0x5F,0xBD,0xFF, 0xFA,0xFF,0xF8,0xFF,0xBF,0xAF,0xFB,0xFE, | ||
| 1360 | 0xFE,0x3F,0xEF,0xE8,0xFF,0xDF,0xF3,0xFD, 0xFF,0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xFB, | ||
| 1361 | 0xFD,0xFF,0xAF,0xFF,0xFF,0xFE,0xFE,0xBF, 0xDB,0xFF,0xFF,0xFF,0xBF,0xFF,0xDF,0xFF, | ||
| 1362 | 0xFD,0xFF,0xCB,0xFF,0xFF,0xFF,0xFF,0xFF, 0xBF,0x6F,0xFF,0x7F,0xB7,0xB3,0xFF,0xFF, | ||
| 1363 | 0xDF,0xFF,0xFB,0xEF,0xFF,0xFF,0xFF,0x07, 0xFF,0xFB,0xFF,0xFF,0xFF,0xED,0xFF,0xF5, | ||
| 1364 | 0x7C,0xFF,0x7F,0xFE,0xFF,0xFF,0xEF,0xCF, 0xFF,0xFB,0xFF,0xFF,0x2F,0xFF,0xFF,0xFF, | ||
| 1365 | 0xFF,0xF3,0xFF,0xFB,0xFF,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, | ||
| 1366 | 0xFD,0x1B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFE,0x7C,0xFF,0xFF,0xFF,0xFF, | ||
| 1367 | 0xEF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0x7F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1368 | 0xDB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xFF,0xFF,0xF0,0x7F,0xFF,0xFF,0xFF,0xFF, | ||
| 1369 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xFE, | ||
| 1370 | 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xEF,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, | ||
| 1371 | 0xFF,0xFF,0xEF,0xFA,0xB5,0xFF,0xFF,0xFF, 0xF7,0xF7,0xFF,0xFF,0xFF,0xFF,0xDF,0xFB, | ||
| 1372 | 0xFC,0xFF,0xFF,0xFE,0xFF,0x7F,0xDF,0xBF, 0xFF,0xCB,0xBF,0xF9,0xFE,0x7F,0x9F,0xE7, | ||
| 1373 | 0xF9,0xFE,0x7F,0x97,0xE1,0xFE,0x79,0x9F, 0xE7,0xFD,0xFE,0x7F,0xDF,0xFE,0x37,0xFF, | ||
| 1374 | 0xFB,0xDE,0xDE,0xBD,0xEF,0xF3,0xFE,0xFB, 0xAF,0xEB,0xFE,0xFF,0xFF,0xCF,0xFF,0xFE, | ||
| 1375 | 0xFF,0xBF,0xFF,0x8F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xE7,0xF9,0x5E,0x7F,0xEF,0xFB, | ||
| 1376 | 0xDA,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD, 0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF, | ||
| 1377 | 0xFF,0xFF,0x7F,0xFF,0xFF,0xF7,0xFB,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFC,0x3F,0xFF,0xBF, | ||
| 1378 | 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0x7B,0x7F, 0xBF,0xEF,0xFB,0xFE,0xFF,0xB5,0xEF,0xFB, | ||
| 1379 | 0xBF,0xFA,0x7F,0xFC,0xFF,0x3F,0xCF,0xF3, 0xFC,0xFF,0x3F,0xCF,0xBC,0xFF,0x3F,0xEF, | ||
| 1380 | 0xF3,0xFC,0xFE,0x3F,0xCF,0xFF,0xEE,0xEF, 0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0x6A,0xD7, | ||
| 1381 | 0xB7,0xFB,0xF8,0xFF,0xB7,0xEF,0xBA,0xFE, 0xFF,0xBF,0x7F,0xE9,0xFF,0xF9,0x7E,0x5F, | ||
| 1382 | 0x97,0xE5,0xF9,0xFE,0x7F,0xBF,0xF9,0x7E, 0x5F,0x9F,0xE5,0xFB,0xFE,0x5F,0xB7,0xFF, | ||
| 1383 | 0xA3,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0x5E,0xF7,0x7D,0xFF,0x77,0xDF, | ||
| 1384 | 0xF7,0xFD,0xFF,0x7F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xDF,0xFB,0x7F, | ||
| 1385 | 0xFF,0xFF,0xEF,0xFF,0xFE,0xFB,0xFF,0xFF, 0xBF,0xFE,0x8F,0xFF,0xDF,0xF7,0xFD,0xFD, | ||
| 1386 | 0x7F,0xDF,0xF7,0xFD,0x3E,0xDF,0xF5,0xBD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xF7,0xFF,0x9F, | ||
| 1387 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xBE,0xFF,0xFF,0xFF,0xFF, | ||
| 1388 | 0xFF,0xFF,0xFF,0xFD,0x3F,0xFF,0xDF,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xCF, | ||
| 1389 | 0x77,0xFC,0xFF,0x5F,0xDF,0xF7,0xFD,0xFF, 0xF4,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1390 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xFF,0xFF,0xEE,0xFF,0xFF, | ||
| 1391 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xED,0xFB,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, | ||
| 1392 | 0xFF,0xFF,0xE9,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFB,0xFF,0xFF,0xFF,0xD3,0xFF,0xFF, | ||
| 1393 | 0xBF,0x3F,0xFB,0xFF,0xFF,0xFF,0xFB,0xF3, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1394 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0x17,0xFF,0xFF,0xFF, | ||
| 1395 | 0xDF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xDF,0xFF,0xFD,0xFF,0xFF,0xDF,0xF7, | ||
| 1396 | 0xFF,0x4F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD, | ||
| 1397 | 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x9F,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
| 1398 | 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFF,0xFF,0x7A,0x3F,0xFF,0xFF,0xFF,0xFF, | ||
| 1399 | 0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF2, | ||
| 1400 | 0x7F,0xFF,0xFB,0xFE,0xFF,0xBF,0xEF,0xF8, 0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,0x8F,0xEC, | ||
| 1401 | 0xFB,0xFE,0xFF,0xBF,0xF8,0xF7,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFD,0xBF,0xCF,0xEC, | ||
| 1402 | 0xFF,0x3F,0xEF,0xDB,0xF8,0xFF,0xBF,0xCF, 0xFF,0xF9,0xFF,0xFF,0xBF,0xFF,0xFB,0xFF, | ||
| 1403 | 0xFF,0xFF,0xEF,0xFB,0xDF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xBB,0xFF, | ||
| 1404 | 0xEF,0xFB,0xFE,0xEF,0xBF,0xEE,0xEB,0xFB, 0xFE,0xFF,0xEF,0xFE,0xEE,0xBF,0xFE,0xEB, | ||
| 1405 | 0xFF,0xEF,0xFF,0x17,0xFF,0x7E,0xEB,0xBB, 0xFE,0xBF,0xBE,0xFB,0xEF,0x5B,0xF7,0xBD, | ||
| 1406 | 0xFB,0xCF,0xBF,0xBF,0xBB,0xFB,0x7E,0xCC, 0xEF,0xFF | ||
| 1407 | |||
| 1408 | }; | ||
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c deleted file mode 100644 index 1774ab7a40d2..000000000000 --- a/drivers/usb/media/dabusb.c +++ /dev/null | |||
| @@ -1,874 +0,0 @@ | |||
| 1 | /*****************************************************************************/ | ||
| 2 | |||
| 3 | /* | ||
| 4 | * dabusb.c -- dab usb driver. | ||
| 5 | * | ||
| 6 | * Copyright (C) 1999 Deti Fliegl (deti@fliegl.de) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | * | ||
| 22 | * | ||
| 23 | * | ||
| 24 | * $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $ | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | /*****************************************************************************/ | ||
| 29 | |||
| 30 | #include <linux/module.h> | ||
| 31 | #include <linux/socket.h> | ||
| 32 | #include <linux/list.h> | ||
| 33 | #include <linux/vmalloc.h> | ||
| 34 | #include <linux/slab.h> | ||
| 35 | #include <linux/init.h> | ||
| 36 | #include <asm/uaccess.h> | ||
| 37 | #include <asm/atomic.h> | ||
| 38 | #include <linux/delay.h> | ||
| 39 | #include <linux/usb.h> | ||
| 40 | #include <linux/smp_lock.h> | ||
| 41 | #include <linux/mutex.h> | ||
| 42 | |||
| 43 | #include "dabusb.h" | ||
| 44 | #include "dabfirmware.h" | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Version Information | ||
| 48 | */ | ||
| 49 | #define DRIVER_VERSION "v1.54" | ||
| 50 | #define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de" | ||
| 51 | #define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999" | ||
| 52 | |||
| 53 | /* --------------------------------------------------------------------- */ | ||
| 54 | |||
| 55 | #ifdef CONFIG_USB_DYNAMIC_MINORS | ||
| 56 | #define NRDABUSB 256 | ||
| 57 | #else | ||
| 58 | #define NRDABUSB 4 | ||
| 59 | #endif | ||
| 60 | |||
| 61 | /*-------------------------------------------------------------------*/ | ||
| 62 | |||
| 63 | static dabusb_t dabusb[NRDABUSB]; | ||
| 64 | static int buffers = 256; | ||
| 65 | static struct usb_driver dabusb_driver; | ||
| 66 | |||
| 67 | /*-------------------------------------------------------------------*/ | ||
| 68 | |||
| 69 | static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src) | ||
| 70 | { | ||
| 71 | unsigned long flags; | ||
| 72 | struct list_head *tmp; | ||
| 73 | int ret = 0; | ||
| 74 | |||
| 75 | spin_lock_irqsave (&s->lock, flags); | ||
| 76 | |||
| 77 | if (list_empty (src)) { | ||
| 78 | // no elements in source buffer | ||
| 79 | ret = -1; | ||
| 80 | goto err; | ||
| 81 | } | ||
| 82 | tmp = src->next; | ||
| 83 | list_move_tail (tmp, dst); | ||
| 84 | |||
| 85 | err: spin_unlock_irqrestore (&s->lock, flags); | ||
| 86 | return ret; | ||
| 87 | } | ||
| 88 | /*-------------------------------------------------------------------*/ | ||
| 89 | #ifdef DEBUG | ||
| 90 | static void dump_urb (struct urb *urb) | ||
| 91 | { | ||
| 92 | dbg("urb :%p", urb); | ||
| 93 | dbg("dev :%p", urb->dev); | ||
| 94 | dbg("pipe :%08X", urb->pipe); | ||
| 95 | dbg("status :%d", urb->status); | ||
| 96 | dbg("transfer_flags :%08X", urb->transfer_flags); | ||
| 97 | dbg("transfer_buffer :%p", urb->transfer_buffer); | ||
| 98 | dbg("transfer_buffer_length:%d", urb->transfer_buffer_length); | ||
| 99 | dbg("actual_length :%d", urb->actual_length); | ||
| 100 | dbg("setup_packet :%p", urb->setup_packet); | ||
| 101 | dbg("start_frame :%d", urb->start_frame); | ||
| 102 | dbg("number_of_packets :%d", urb->number_of_packets); | ||
| 103 | dbg("interval :%d", urb->interval); | ||
| 104 | dbg("error_count :%d", urb->error_count); | ||
| 105 | dbg("context :%p", urb->context); | ||
| 106 | dbg("complete :%p", urb->complete); | ||
| 107 | } | ||
| 108 | #endif | ||
| 109 | /*-------------------------------------------------------------------*/ | ||
| 110 | static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q) | ||
| 111 | { | ||
| 112 | unsigned long flags; | ||
| 113 | pbuff_t b; | ||
| 114 | |||
| 115 | dbg("dabusb_cancel_queue"); | ||
| 116 | |||
| 117 | spin_lock_irqsave (&s->lock, flags); | ||
| 118 | |||
| 119 | list_for_each_entry(b, q, buff_list) { | ||
| 120 | #ifdef DEBUG | ||
| 121 | dump_urb(b->purb); | ||
| 122 | #endif | ||
| 123 | usb_unlink_urb (b->purb); | ||
| 124 | } | ||
| 125 | spin_unlock_irqrestore (&s->lock, flags); | ||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | /*-------------------------------------------------------------------*/ | ||
| 129 | static int dabusb_free_queue (struct list_head *q) | ||
| 130 | { | ||
| 131 | struct list_head *tmp; | ||
| 132 | struct list_head *p; | ||
| 133 | pbuff_t b; | ||
| 134 | |||
| 135 | dbg("dabusb_free_queue"); | ||
| 136 | for (p = q->next; p != q;) { | ||
| 137 | b = list_entry (p, buff_t, buff_list); | ||
| 138 | |||
| 139 | #ifdef DEBUG | ||
| 140 | dump_urb(b->purb); | ||
| 141 | #endif | ||
| 142 | kfree(b->purb->transfer_buffer); | ||
| 143 | usb_free_urb(b->purb); | ||
| 144 | tmp = p->next; | ||
| 145 | list_del (p); | ||
| 146 | kfree (b); | ||
| 147 | p = tmp; | ||
| 148 | } | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | /*-------------------------------------------------------------------*/ | ||
| 153 | static int dabusb_free_buffers (pdabusb_t s) | ||
| 154 | { | ||
| 155 | unsigned long flags; | ||
| 156 | dbg("dabusb_free_buffers"); | ||
| 157 | |||
| 158 | spin_lock_irqsave(&s->lock, flags); | ||
| 159 | |||
| 160 | dabusb_free_queue (&s->free_buff_list); | ||
| 161 | dabusb_free_queue (&s->rec_buff_list); | ||
| 162 | |||
| 163 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 164 | |||
| 165 | s->got_mem = 0; | ||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | /*-------------------------------------------------------------------*/ | ||
| 169 | static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs) | ||
| 170 | { | ||
| 171 | pbuff_t b = purb->context; | ||
| 172 | pdabusb_t s = b->s; | ||
| 173 | int i; | ||
| 174 | int len; | ||
| 175 | int dst = 0; | ||
| 176 | void *buf = purb->transfer_buffer; | ||
| 177 | |||
| 178 | dbg("dabusb_iso_complete"); | ||
| 179 | |||
| 180 | // process if URB was not killed | ||
| 181 | if (purb->status != -ENOENT) { | ||
| 182 | unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE); | ||
| 183 | int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)); | ||
| 184 | for (i = 0; i < purb->number_of_packets; i++) | ||
| 185 | if (!purb->iso_frame_desc[i].status) { | ||
| 186 | len = purb->iso_frame_desc[i].actual_length; | ||
| 187 | if (len <= pipesize) { | ||
| 188 | memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len); | ||
| 189 | dst += len; | ||
| 190 | } | ||
| 191 | else | ||
| 192 | err("dabusb_iso_complete: invalid len %d", len); | ||
| 193 | } | ||
| 194 | else | ||
| 195 | warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status); | ||
| 196 | if (dst != purb->actual_length) | ||
| 197 | err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length); | ||
| 198 | } | ||
| 199 | |||
| 200 | if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) { | ||
| 201 | s->overruns++; | ||
| 202 | err("overrun (%d)", s->overruns); | ||
| 203 | } | ||
| 204 | wake_up (&s->wait); | ||
| 205 | } | ||
| 206 | /*-------------------------------------------------------------------*/ | ||
| 207 | static int dabusb_alloc_buffers (pdabusb_t s) | ||
| 208 | { | ||
| 209 | int buffers = 0; | ||
| 210 | pbuff_t b; | ||
| 211 | unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE); | ||
| 212 | int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe)); | ||
| 213 | int packets = _ISOPIPESIZE / pipesize; | ||
| 214 | int transfer_buffer_length = packets * pipesize; | ||
| 215 | int i; | ||
| 216 | |||
| 217 | dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d", | ||
| 218 | pipesize, packets, transfer_buffer_length); | ||
| 219 | |||
| 220 | while (buffers < (s->total_buffer_size << 10)) { | ||
| 221 | b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL); | ||
| 222 | if (!b) { | ||
| 223 | err("kzalloc(sizeof(buff_t))==NULL"); | ||
| 224 | goto err; | ||
| 225 | } | ||
| 226 | b->s = s; | ||
| 227 | b->purb = usb_alloc_urb(packets, GFP_KERNEL); | ||
| 228 | if (!b->purb) { | ||
| 229 | err("usb_alloc_urb == NULL"); | ||
| 230 | kfree (b); | ||
| 231 | goto err; | ||
| 232 | } | ||
| 233 | |||
| 234 | b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL); | ||
| 235 | if (!b->purb->transfer_buffer) { | ||
| 236 | kfree (b->purb); | ||
| 237 | kfree (b); | ||
| 238 | err("kmalloc(%d)==NULL", transfer_buffer_length); | ||
| 239 | goto err; | ||
| 240 | } | ||
| 241 | |||
| 242 | b->purb->transfer_buffer_length = transfer_buffer_length; | ||
| 243 | b->purb->number_of_packets = packets; | ||
| 244 | b->purb->complete = dabusb_iso_complete; | ||
| 245 | b->purb->context = b; | ||
| 246 | b->purb->dev = s->usbdev; | ||
| 247 | b->purb->pipe = pipe; | ||
| 248 | b->purb->transfer_flags = URB_ISO_ASAP; | ||
| 249 | |||
| 250 | for (i = 0; i < packets; i++) { | ||
| 251 | b->purb->iso_frame_desc[i].offset = i * pipesize; | ||
| 252 | b->purb->iso_frame_desc[i].length = pipesize; | ||
| 253 | } | ||
| 254 | |||
| 255 | buffers += transfer_buffer_length; | ||
| 256 | list_add_tail (&b->buff_list, &s->free_buff_list); | ||
| 257 | } | ||
| 258 | s->got_mem = buffers; | ||
| 259 | |||
| 260 | return 0; | ||
| 261 | |||
| 262 | err: | ||
| 263 | dabusb_free_buffers (s); | ||
| 264 | return -ENOMEM; | ||
| 265 | } | ||
| 266 | /*-------------------------------------------------------------------*/ | ||
| 267 | static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb) | ||
| 268 | { | ||
| 269 | int ret; | ||
| 270 | unsigned int pipe; | ||
| 271 | int actual_length; | ||
| 272 | |||
| 273 | dbg("dabusb_bulk"); | ||
| 274 | |||
| 275 | if (!pb->pipe) | ||
| 276 | pipe = usb_rcvbulkpipe (s->usbdev, 2); | ||
| 277 | else | ||
| 278 | pipe = usb_sndbulkpipe (s->usbdev, 2); | ||
| 279 | |||
| 280 | ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100); | ||
| 281 | if(ret<0) { | ||
| 282 | err("dabusb: usb_bulk_msg failed(%d)",ret); | ||
| 283 | |||
| 284 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { | ||
| 285 | err("set_interface failed"); | ||
| 286 | return -EINVAL; | ||
| 287 | } | ||
| 288 | |||
| 289 | } | ||
| 290 | |||
| 291 | if( ret == -EPIPE ) { | ||
| 292 | warn("CLEAR_FEATURE request to remove STALL condition."); | ||
| 293 | if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe))) | ||
| 294 | err("request failed"); | ||
| 295 | } | ||
| 296 | |||
| 297 | pb->size = actual_length; | ||
| 298 | return ret; | ||
| 299 | } | ||
| 300 | /* --------------------------------------------------------------------- */ | ||
| 301 | static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len) | ||
| 302 | { | ||
| 303 | int ret; | ||
| 304 | unsigned char *transfer_buffer = kmalloc (len, GFP_KERNEL); | ||
| 305 | |||
| 306 | if (!transfer_buffer) { | ||
| 307 | err("dabusb_writemem: kmalloc(%d) failed.", len); | ||
| 308 | return -ENOMEM; | ||
| 309 | } | ||
| 310 | |||
| 311 | memcpy (transfer_buffer, data, len); | ||
| 312 | |||
| 313 | ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300); | ||
| 314 | |||
| 315 | kfree (transfer_buffer); | ||
| 316 | return ret; | ||
| 317 | } | ||
| 318 | /* --------------------------------------------------------------------- */ | ||
| 319 | static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit) | ||
| 320 | { | ||
| 321 | dbg("dabusb_8051_reset: %d",reset_bit); | ||
| 322 | return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1); | ||
| 323 | } | ||
| 324 | /* --------------------------------------------------------------------- */ | ||
| 325 | static int dabusb_loadmem (pdabusb_t s, const char *fname) | ||
| 326 | { | ||
| 327 | int ret; | ||
| 328 | PINTEL_HEX_RECORD ptr = firmware; | ||
| 329 | |||
| 330 | dbg("Enter dabusb_loadmem (internal)"); | ||
| 331 | |||
| 332 | ret = dabusb_8051_reset (s, 1); | ||
| 333 | while (ptr->Type == 0) { | ||
| 334 | |||
| 335 | dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length); | ||
| 336 | |||
| 337 | ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length); | ||
| 338 | if (ret < 0) { | ||
| 339 | err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length); | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | ptr++; | ||
| 343 | } | ||
| 344 | ret = dabusb_8051_reset (s, 0); | ||
| 345 | |||
| 346 | dbg("dabusb_loadmem: exit"); | ||
| 347 | |||
| 348 | return ret; | ||
| 349 | } | ||
| 350 | /* --------------------------------------------------------------------- */ | ||
| 351 | static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b) | ||
| 352 | { | ||
| 353 | b->size = 4; | ||
| 354 | b->data[0] = 0x2a; | ||
| 355 | b->data[1] = 0; | ||
| 356 | b->data[2] = 0; | ||
| 357 | b->data[3] = 0; | ||
| 358 | |||
| 359 | dbg("dabusb_fpga_clear"); | ||
| 360 | |||
| 361 | return dabusb_bulk (s, b); | ||
| 362 | } | ||
| 363 | /* --------------------------------------------------------------------- */ | ||
| 364 | static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b) | ||
| 365 | { | ||
| 366 | b->size = 4; | ||
| 367 | b->data[0] = 0x2c; | ||
| 368 | b->data[1] = 0; | ||
| 369 | b->data[2] = 0; | ||
| 370 | b->data[3] = 0; | ||
| 371 | |||
| 372 | dbg("dabusb_fpga_init"); | ||
| 373 | |||
| 374 | return dabusb_bulk (s, b); | ||
| 375 | } | ||
| 376 | /* --------------------------------------------------------------------- */ | ||
| 377 | static int dabusb_fpga_download (pdabusb_t s, const char *fname) | ||
| 378 | { | ||
| 379 | pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL); | ||
| 380 | unsigned int blen, n; | ||
| 381 | int ret; | ||
| 382 | unsigned char *buf = bitstream; | ||
| 383 | |||
| 384 | dbg("Enter dabusb_fpga_download (internal)"); | ||
| 385 | |||
| 386 | if (!b) { | ||
| 387 | err("kmalloc(sizeof(bulk_transfer_t))==NULL"); | ||
| 388 | return -ENOMEM; | ||
| 389 | } | ||
| 390 | |||
| 391 | b->pipe = 1; | ||
| 392 | ret = dabusb_fpga_clear (s, b); | ||
| 393 | mdelay (10); | ||
| 394 | blen = buf[73] + (buf[72] << 8); | ||
| 395 | |||
| 396 | dbg("Bitstream len: %i", blen); | ||
| 397 | |||
| 398 | b->data[0] = 0x2b; | ||
| 399 | b->data[1] = 0; | ||
| 400 | b->data[2] = 0; | ||
| 401 | b->data[3] = 60; | ||
| 402 | |||
| 403 | for (n = 0; n <= blen + 60; n += 60) { | ||
| 404 | // some cclks for startup | ||
| 405 | b->size = 64; | ||
| 406 | memcpy (b->data + 4, buf + 74 + n, 60); | ||
| 407 | ret = dabusb_bulk (s, b); | ||
| 408 | if (ret < 0) { | ||
| 409 | err("dabusb_bulk failed."); | ||
| 410 | break; | ||
| 411 | } | ||
| 412 | mdelay (1); | ||
| 413 | } | ||
| 414 | |||
| 415 | ret = dabusb_fpga_init (s, b); | ||
| 416 | kfree (b); | ||
| 417 | |||
| 418 | dbg("exit dabusb_fpga_download"); | ||
| 419 | |||
| 420 | return ret; | ||
| 421 | } | ||
| 422 | |||
| 423 | static int dabusb_stop (pdabusb_t s) | ||
| 424 | { | ||
| 425 | dbg("dabusb_stop"); | ||
| 426 | |||
| 427 | s->state = _stopped; | ||
| 428 | dabusb_cancel_queue (s, &s->rec_buff_list); | ||
| 429 | |||
| 430 | dbg("pending_io: %d", s->pending_io.counter); | ||
| 431 | |||
| 432 | s->pending_io.counter = 0; | ||
| 433 | return 0; | ||
| 434 | } | ||
| 435 | |||
| 436 | static int dabusb_startrek (pdabusb_t s) | ||
| 437 | { | ||
| 438 | if (!s->got_mem && s->state != _started) { | ||
| 439 | |||
| 440 | dbg("dabusb_startrek"); | ||
| 441 | |||
| 442 | if (dabusb_alloc_buffers (s) < 0) | ||
| 443 | return -ENOMEM; | ||
| 444 | dabusb_stop (s); | ||
| 445 | s->state = _started; | ||
| 446 | s->readptr = 0; | ||
| 447 | } | ||
| 448 | |||
| 449 | if (!list_empty (&s->free_buff_list)) { | ||
| 450 | pbuff_t end; | ||
| 451 | int ret; | ||
| 452 | |||
| 453 | while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) { | ||
| 454 | |||
| 455 | dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list); | ||
| 456 | |||
| 457 | end = list_entry (s->rec_buff_list.prev, buff_t, buff_list); | ||
| 458 | |||
| 459 | ret = usb_submit_urb (end->purb, GFP_KERNEL); | ||
| 460 | if (ret) { | ||
| 461 | err("usb_submit_urb returned:%d", ret); | ||
| 462 | if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) | ||
| 463 | err("startrek: dabusb_add_buf_tail failed"); | ||
| 464 | break; | ||
| 465 | } | ||
| 466 | else | ||
| 467 | atomic_inc (&s->pending_io); | ||
| 468 | } | ||
| 469 | dbg("pending_io: %d",s->pending_io.counter); | ||
| 470 | } | ||
| 471 | |||
| 472 | return 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos) | ||
| 476 | { | ||
| 477 | pdabusb_t s = (pdabusb_t) file->private_data; | ||
| 478 | unsigned long flags; | ||
| 479 | unsigned ret = 0; | ||
| 480 | int rem; | ||
| 481 | int cnt; | ||
| 482 | pbuff_t b; | ||
| 483 | struct urb *purb = NULL; | ||
| 484 | |||
| 485 | dbg("dabusb_read"); | ||
| 486 | |||
| 487 | if (*ppos) | ||
| 488 | return -ESPIPE; | ||
| 489 | |||
| 490 | if (s->remove_pending) | ||
| 491 | return -EIO; | ||
| 492 | |||
| 493 | |||
| 494 | if (!s->usbdev) | ||
| 495 | return -EIO; | ||
| 496 | |||
| 497 | while (count > 0) { | ||
| 498 | dabusb_startrek (s); | ||
| 499 | |||
| 500 | spin_lock_irqsave (&s->lock, flags); | ||
| 501 | |||
| 502 | if (list_empty (&s->rec_buff_list)) { | ||
| 503 | |||
| 504 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 505 | |||
| 506 | err("error: rec_buf_list is empty"); | ||
| 507 | goto err; | ||
| 508 | } | ||
| 509 | |||
| 510 | b = list_entry (s->rec_buff_list.next, buff_t, buff_list); | ||
| 511 | purb = b->purb; | ||
| 512 | |||
| 513 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 514 | |||
| 515 | if (purb->status == -EINPROGRESS) { | ||
| 516 | if (file->f_flags & O_NONBLOCK) // return nonblocking | ||
| 517 | { | ||
| 518 | if (!ret) | ||
| 519 | ret = -EAGAIN; | ||
| 520 | goto err; | ||
| 521 | } | ||
| 522 | |||
| 523 | interruptible_sleep_on (&s->wait); | ||
| 524 | |||
| 525 | if (signal_pending (current)) { | ||
| 526 | if (!ret) | ||
| 527 | ret = -ERESTARTSYS; | ||
| 528 | goto err; | ||
| 529 | } | ||
| 530 | |||
| 531 | spin_lock_irqsave (&s->lock, flags); | ||
| 532 | |||
| 533 | if (list_empty (&s->rec_buff_list)) { | ||
| 534 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 535 | err("error: still no buffer available."); | ||
| 536 | goto err; | ||
| 537 | } | ||
| 538 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 539 | s->readptr = 0; | ||
| 540 | } | ||
| 541 | if (s->remove_pending) { | ||
| 542 | ret = -EIO; | ||
| 543 | goto err; | ||
| 544 | } | ||
| 545 | |||
| 546 | rem = purb->actual_length - s->readptr; // set remaining bytes to copy | ||
| 547 | |||
| 548 | if (count >= rem) | ||
| 549 | cnt = rem; | ||
| 550 | else | ||
| 551 | cnt = count; | ||
| 552 | |||
| 553 | dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt); | ||
| 554 | |||
| 555 | if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) { | ||
| 556 | err("read: copy_to_user failed"); | ||
| 557 | if (!ret) | ||
| 558 | ret = -EFAULT; | ||
| 559 | goto err; | ||
| 560 | } | ||
| 561 | |||
| 562 | s->readptr += cnt; | ||
| 563 | count -= cnt; | ||
| 564 | buf += cnt; | ||
| 565 | ret += cnt; | ||
| 566 | |||
| 567 | if (s->readptr == purb->actual_length) { | ||
| 568 | // finished, take next buffer | ||
| 569 | if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) | ||
| 570 | err("read: dabusb_add_buf_tail failed"); | ||
| 571 | s->readptr = 0; | ||
| 572 | } | ||
| 573 | } | ||
| 574 | err: //mutex_unlock(&s->mutex); | ||
| 575 | return ret; | ||
| 576 | } | ||
| 577 | |||
| 578 | static int dabusb_open (struct inode *inode, struct file *file) | ||
| 579 | { | ||
| 580 | int devnum = iminor(inode); | ||
| 581 | pdabusb_t s; | ||
| 582 | |||
| 583 | if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB)) | ||
| 584 | return -EIO; | ||
| 585 | |||
| 586 | s = &dabusb[devnum - DABUSB_MINOR]; | ||
| 587 | |||
| 588 | dbg("dabusb_open"); | ||
| 589 | mutex_lock(&s->mutex); | ||
| 590 | |||
| 591 | while (!s->usbdev || s->opened) { | ||
| 592 | mutex_unlock(&s->mutex); | ||
| 593 | |||
| 594 | if (file->f_flags & O_NONBLOCK) { | ||
| 595 | return -EBUSY; | ||
| 596 | } | ||
| 597 | msleep_interruptible(500); | ||
| 598 | |||
| 599 | if (signal_pending (current)) { | ||
| 600 | return -EAGAIN; | ||
| 601 | } | ||
| 602 | mutex_lock(&s->mutex); | ||
| 603 | } | ||
| 604 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { | ||
| 605 | mutex_unlock(&s->mutex); | ||
| 606 | err("set_interface failed"); | ||
| 607 | return -EINVAL; | ||
| 608 | } | ||
| 609 | s->opened = 1; | ||
| 610 | mutex_unlock(&s->mutex); | ||
| 611 | |||
| 612 | file->f_pos = 0; | ||
| 613 | file->private_data = s; | ||
| 614 | |||
| 615 | return nonseekable_open(inode, file); | ||
| 616 | } | ||
| 617 | |||
| 618 | static int dabusb_release (struct inode *inode, struct file *file) | ||
| 619 | { | ||
| 620 | pdabusb_t s = (pdabusb_t) file->private_data; | ||
| 621 | |||
| 622 | dbg("dabusb_release"); | ||
| 623 | |||
| 624 | mutex_lock(&s->mutex); | ||
| 625 | dabusb_stop (s); | ||
| 626 | dabusb_free_buffers (s); | ||
| 627 | mutex_unlock(&s->mutex); | ||
| 628 | |||
| 629 | if (!s->remove_pending) { | ||
| 630 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) | ||
| 631 | err("set_interface failed"); | ||
| 632 | } | ||
| 633 | else | ||
| 634 | wake_up (&s->remove_ok); | ||
| 635 | |||
| 636 | s->opened = 0; | ||
| 637 | return 0; | ||
| 638 | } | ||
| 639 | |||
| 640 | static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
| 641 | { | ||
| 642 | pdabusb_t s = (pdabusb_t) file->private_data; | ||
| 643 | pbulk_transfer_t pbulk; | ||
| 644 | int ret = 0; | ||
| 645 | int version = DABUSB_VERSION; | ||
| 646 | |||
| 647 | dbg("dabusb_ioctl"); | ||
| 648 | |||
| 649 | if (s->remove_pending) | ||
| 650 | return -EIO; | ||
| 651 | |||
| 652 | mutex_lock(&s->mutex); | ||
| 653 | |||
| 654 | if (!s->usbdev) { | ||
| 655 | mutex_unlock(&s->mutex); | ||
| 656 | return -EIO; | ||
| 657 | } | ||
| 658 | |||
| 659 | switch (cmd) { | ||
| 660 | |||
| 661 | case IOCTL_DAB_BULK: | ||
| 662 | pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL); | ||
| 663 | |||
| 664 | if (!pbulk) { | ||
| 665 | ret = -ENOMEM; | ||
| 666 | break; | ||
| 667 | } | ||
| 668 | |||
| 669 | if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) { | ||
| 670 | ret = -EFAULT; | ||
| 671 | kfree (pbulk); | ||
| 672 | break; | ||
| 673 | } | ||
| 674 | |||
| 675 | ret=dabusb_bulk (s, pbulk); | ||
| 676 | if(ret==0) | ||
| 677 | if (copy_to_user((void __user *)arg, pbulk, | ||
| 678 | sizeof(bulk_transfer_t))) | ||
| 679 | ret = -EFAULT; | ||
| 680 | kfree (pbulk); | ||
| 681 | break; | ||
| 682 | |||
| 683 | case IOCTL_DAB_OVERRUNS: | ||
| 684 | ret = put_user (s->overruns, (unsigned int __user *) arg); | ||
| 685 | break; | ||
| 686 | |||
| 687 | case IOCTL_DAB_VERSION: | ||
| 688 | ret = put_user (version, (unsigned int __user *) arg); | ||
| 689 | break; | ||
| 690 | |||
| 691 | default: | ||
| 692 | ret = -ENOIOCTLCMD; | ||
| 693 | break; | ||
| 694 | } | ||
| 695 | mutex_unlock(&s->mutex); | ||
| 696 | return ret; | ||
| 697 | } | ||
| 698 | |||
| 699 | static struct file_operations dabusb_fops = | ||
| 700 | { | ||
| 701 | .owner = THIS_MODULE, | ||
| 702 | .llseek = no_llseek, | ||
| 703 | .read = dabusb_read, | ||
| 704 | .ioctl = dabusb_ioctl, | ||
| 705 | .open = dabusb_open, | ||
| 706 | .release = dabusb_release, | ||
| 707 | }; | ||
| 708 | |||
| 709 | static struct usb_class_driver dabusb_class = { | ||
| 710 | .name = "dabusb%d", | ||
| 711 | .fops = &dabusb_fops, | ||
| 712 | .minor_base = DABUSB_MINOR, | ||
| 713 | }; | ||
| 714 | |||
| 715 | |||
| 716 | /* --------------------------------------------------------------------- */ | ||
| 717 | static int dabusb_probe (struct usb_interface *intf, | ||
| 718 | const struct usb_device_id *id) | ||
| 719 | { | ||
| 720 | struct usb_device *usbdev = interface_to_usbdev(intf); | ||
| 721 | int retval; | ||
| 722 | pdabusb_t s; | ||
| 723 | |||
| 724 | dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d", | ||
| 725 | le16_to_cpu(usbdev->descriptor.idVendor), | ||
| 726 | le16_to_cpu(usbdev->descriptor.idProduct), | ||
| 727 | intf->altsetting->desc.bInterfaceNumber); | ||
| 728 | |||
| 729 | /* We don't handle multiple configurations */ | ||
| 730 | if (usbdev->descriptor.bNumConfigurations != 1) | ||
| 731 | return -ENODEV; | ||
| 732 | |||
| 733 | if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF && | ||
| 734 | le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999) | ||
| 735 | return -ENODEV; | ||
| 736 | |||
| 737 | |||
| 738 | |||
| 739 | s = &dabusb[intf->minor]; | ||
| 740 | |||
| 741 | mutex_lock(&s->mutex); | ||
| 742 | s->remove_pending = 0; | ||
| 743 | s->usbdev = usbdev; | ||
| 744 | s->devnum = intf->minor; | ||
| 745 | |||
| 746 | if (usb_reset_configuration (usbdev) < 0) { | ||
| 747 | err("reset_configuration failed"); | ||
| 748 | goto reject; | ||
| 749 | } | ||
| 750 | if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) { | ||
| 751 | dabusb_loadmem (s, NULL); | ||
| 752 | goto reject; | ||
| 753 | } | ||
| 754 | else { | ||
| 755 | dabusb_fpga_download (s, NULL); | ||
| 756 | |||
| 757 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) { | ||
| 758 | err("set_interface failed"); | ||
| 759 | goto reject; | ||
| 760 | } | ||
| 761 | } | ||
| 762 | dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber); | ||
| 763 | usb_set_intfdata (intf, s); | ||
| 764 | mutex_unlock(&s->mutex); | ||
| 765 | |||
| 766 | retval = usb_register_dev(intf, &dabusb_class); | ||
| 767 | if (retval) { | ||
| 768 | usb_set_intfdata (intf, NULL); | ||
| 769 | return -ENOMEM; | ||
| 770 | } | ||
| 771 | |||
| 772 | return 0; | ||
| 773 | |||
| 774 | reject: | ||
| 775 | mutex_unlock(&s->mutex); | ||
| 776 | s->usbdev = NULL; | ||
| 777 | return -ENODEV; | ||
| 778 | } | ||
| 779 | |||
| 780 | static void dabusb_disconnect (struct usb_interface *intf) | ||
| 781 | { | ||
| 782 | wait_queue_t __wait; | ||
| 783 | pdabusb_t s = usb_get_intfdata (intf); | ||
| 784 | |||
| 785 | dbg("dabusb_disconnect"); | ||
| 786 | |||
| 787 | init_waitqueue_entry(&__wait, current); | ||
| 788 | |||
| 789 | usb_set_intfdata (intf, NULL); | ||
| 790 | if (s) { | ||
| 791 | usb_deregister_dev (intf, &dabusb_class); | ||
| 792 | s->remove_pending = 1; | ||
| 793 | wake_up (&s->wait); | ||
| 794 | add_wait_queue(&s->remove_ok, &__wait); | ||
| 795 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 796 | if (s->state == _started) | ||
| 797 | schedule(); | ||
| 798 | current->state = TASK_RUNNING; | ||
| 799 | remove_wait_queue(&s->remove_ok, &__wait); | ||
| 800 | |||
| 801 | s->usbdev = NULL; | ||
| 802 | s->overruns = 0; | ||
| 803 | } | ||
| 804 | } | ||
| 805 | |||
| 806 | static struct usb_device_id dabusb_ids [] = { | ||
| 807 | // { USB_DEVICE(0x0547, 0x2131) }, /* An2131 chip, no boot ROM */ | ||
| 808 | { USB_DEVICE(0x0547, 0x9999) }, | ||
| 809 | { } /* Terminating entry */ | ||
| 810 | }; | ||
| 811 | |||
| 812 | MODULE_DEVICE_TABLE (usb, dabusb_ids); | ||
| 813 | |||
| 814 | static struct usb_driver dabusb_driver = { | ||
| 815 | .name = "dabusb", | ||
| 816 | .probe = dabusb_probe, | ||
| 817 | .disconnect = dabusb_disconnect, | ||
| 818 | .id_table = dabusb_ids, | ||
| 819 | }; | ||
| 820 | |||
| 821 | /* --------------------------------------------------------------------- */ | ||
| 822 | |||
| 823 | static int __init dabusb_init (void) | ||
| 824 | { | ||
| 825 | int retval; | ||
| 826 | unsigned u; | ||
| 827 | |||
| 828 | /* initialize struct */ | ||
| 829 | for (u = 0; u < NRDABUSB; u++) { | ||
| 830 | pdabusb_t s = &dabusb[u]; | ||
| 831 | memset (s, 0, sizeof (dabusb_t)); | ||
| 832 | mutex_init (&s->mutex); | ||
| 833 | s->usbdev = NULL; | ||
| 834 | s->total_buffer_size = buffers; | ||
| 835 | init_waitqueue_head (&s->wait); | ||
| 836 | init_waitqueue_head (&s->remove_ok); | ||
| 837 | spin_lock_init (&s->lock); | ||
| 838 | INIT_LIST_HEAD (&s->free_buff_list); | ||
| 839 | INIT_LIST_HEAD (&s->rec_buff_list); | ||
| 840 | } | ||
| 841 | |||
| 842 | /* register misc device */ | ||
| 843 | retval = usb_register(&dabusb_driver); | ||
| 844 | if (retval) | ||
| 845 | goto out; | ||
| 846 | |||
| 847 | dbg("dabusb_init: driver registered"); | ||
| 848 | |||
| 849 | info(DRIVER_VERSION ":" DRIVER_DESC); | ||
| 850 | |||
| 851 | out: | ||
| 852 | return retval; | ||
| 853 | } | ||
| 854 | |||
| 855 | static void __exit dabusb_cleanup (void) | ||
| 856 | { | ||
| 857 | dbg("dabusb_cleanup"); | ||
| 858 | |||
| 859 | usb_deregister (&dabusb_driver); | ||
| 860 | } | ||
| 861 | |||
| 862 | /* --------------------------------------------------------------------- */ | ||
| 863 | |||
| 864 | MODULE_AUTHOR( DRIVER_AUTHOR ); | ||
| 865 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
| 866 | MODULE_LICENSE("GPL"); | ||
| 867 | |||
| 868 | module_param(buffers, int, 0); | ||
| 869 | MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); | ||
| 870 | |||
| 871 | module_init (dabusb_init); | ||
| 872 | module_exit (dabusb_cleanup); | ||
| 873 | |||
| 874 | /* --------------------------------------------------------------------- */ | ||
diff --git a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h deleted file mode 100644 index 96b03e4af8b9..000000000000 --- a/drivers/usb/media/dabusb.h +++ /dev/null | |||
| @@ -1,85 +0,0 @@ | |||
| 1 | #define _BULK_DATA_LEN 64 | ||
| 2 | typedef struct | ||
| 3 | { | ||
| 4 | unsigned char data[_BULK_DATA_LEN]; | ||
| 5 | unsigned int size; | ||
| 6 | unsigned int pipe; | ||
| 7 | }bulk_transfer_t,*pbulk_transfer_t; | ||
| 8 | |||
| 9 | #define DABUSB_MINOR 240 /* some unassigned USB minor */ | ||
| 10 | #define DABUSB_VERSION 0x1000 | ||
| 11 | #define IOCTL_DAB_BULK _IOWR('d', 0x30, bulk_transfer_t) | ||
| 12 | #define IOCTL_DAB_OVERRUNS _IOR('d', 0x15, int) | ||
| 13 | #define IOCTL_DAB_VERSION _IOR('d', 0x3f, int) | ||
| 14 | |||
| 15 | #ifdef __KERNEL__ | ||
| 16 | |||
| 17 | typedef enum { _stopped=0, _started } driver_state_t; | ||
| 18 | |||
| 19 | typedef struct | ||
| 20 | { | ||
| 21 | struct mutex mutex; | ||
| 22 | struct usb_device *usbdev; | ||
| 23 | wait_queue_head_t wait; | ||
| 24 | wait_queue_head_t remove_ok; | ||
| 25 | spinlock_t lock; | ||
| 26 | atomic_t pending_io; | ||
| 27 | driver_state_t state; | ||
| 28 | int remove_pending; | ||
| 29 | int got_mem; | ||
| 30 | int total_buffer_size; | ||
| 31 | unsigned int overruns; | ||
| 32 | int readptr; | ||
| 33 | int opened; | ||
| 34 | int devnum; | ||
| 35 | struct list_head free_buff_list; | ||
| 36 | struct list_head rec_buff_list; | ||
| 37 | } dabusb_t,*pdabusb_t; | ||
| 38 | |||
| 39 | typedef struct | ||
| 40 | { | ||
| 41 | pdabusb_t s; | ||
| 42 | struct urb *purb; | ||
| 43 | struct list_head buff_list; | ||
| 44 | } buff_t,*pbuff_t; | ||
| 45 | |||
| 46 | typedef struct | ||
| 47 | { | ||
| 48 | wait_queue_head_t wait; | ||
| 49 | } bulk_completion_context_t, *pbulk_completion_context_t; | ||
| 50 | |||
| 51 | |||
| 52 | #define _DABUSB_IF 2 | ||
| 53 | #define _DABUSB_ISOPIPE 0x09 | ||
| 54 | #define _ISOPIPESIZE 16384 | ||
| 55 | |||
| 56 | #define _BULK_DATA_LEN 64 | ||
| 57 | // Vendor specific request code for Anchor Upload/Download | ||
| 58 | // This one is implemented in the core | ||
| 59 | #define ANCHOR_LOAD_INTERNAL 0xA0 | ||
| 60 | |||
| 61 | // EZ-USB Control and Status Register. Bit 0 controls 8051 reset | ||
| 62 | #define CPUCS_REG 0x7F92 | ||
| 63 | #define _TOTAL_BUFFERS 384 | ||
| 64 | |||
| 65 | #define MAX_INTEL_HEX_RECORD_LENGTH 16 | ||
| 66 | |||
| 67 | #ifndef _BYTE_DEFINED | ||
| 68 | #define _BYTE_DEFINED | ||
| 69 | typedef unsigned char BYTE; | ||
| 70 | #endif // !_BYTE_DEFINED | ||
| 71 | |||
| 72 | #ifndef _WORD_DEFINED | ||
| 73 | #define _WORD_DEFINED | ||
| 74 | typedef unsigned short WORD; | ||
| 75 | #endif // !_WORD_DEFINED | ||
| 76 | |||
| 77 | typedef struct _INTEL_HEX_RECORD | ||
| 78 | { | ||
| 79 | BYTE Length; | ||
| 80 | WORD Address; | ||
| 81 | BYTE Type; | ||
| 82 | BYTE Data[MAX_INTEL_HEX_RECORD_LENGTH]; | ||
| 83 | } INTEL_HEX_RECORD, *PINTEL_HEX_RECORD; | ||
| 84 | |||
| 85 | #endif | ||
diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c deleted file mode 100644 index 25646804d5be..000000000000 --- a/drivers/usb/media/dsbr100.c +++ /dev/null | |||
| @@ -1,429 +0,0 @@ | |||
| 1 | /* A driver for the D-Link DSB-R100 USB radio. The R100 plugs | ||
| 2 | into both the USB and an analog audio input, so this thing | ||
| 3 | only deals with initialisation and frequency setting, the | ||
| 4 | audio data has to be handled by a sound driver. | ||
| 5 | |||
| 6 | Major issue: I can't find out where the device reports the signal | ||
| 7 | strength, and indeed the windows software appearantly just looks | ||
| 8 | at the stereo indicator as well. So, scanning will only find | ||
| 9 | stereo stations. Sad, but I can't help it. | ||
| 10 | |||
| 11 | Also, the windows program sends oodles of messages over to the | ||
| 12 | device, and I couldn't figure out their meaning. My suspicion | ||
| 13 | is that they don't have any:-) | ||
| 14 | |||
| 15 | You might find some interesting stuff about this module at | ||
| 16 | http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr | ||
| 17 | |||
| 18 | Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de> | ||
| 19 | |||
| 20 | This program is free software; you can redistribute it and/or modify | ||
| 21 | it under the terms of the GNU General Public License as published by | ||
| 22 | the Free Software Foundation; either version 2 of the License, or | ||
| 23 | (at your option) any later version. | ||
| 24 | |||
| 25 | This program is distributed in the hope that it will be useful, | ||
| 26 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 28 | GNU General Public License for more details. | ||
| 29 | |||
| 30 | You should have received a copy of the GNU General Public License | ||
| 31 | along with this program; if not, write to the Free Software | ||
| 32 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 33 | |||
| 34 | History: | ||
| 35 | |||
| 36 | Version 0.40: | ||
| 37 | Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing | ||
| 38 | |||
| 39 | Version 0.30: | ||
| 40 | Markus: Updates for 2.5.x kernel and more ISO compliant source | ||
| 41 | |||
| 42 | Version 0.25: | ||
| 43 | PSL and Markus: Cleanup, radio now doesn't stop on device close | ||
| 44 | |||
| 45 | Version 0.24: | ||
| 46 | Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally | ||
| 47 | right. Some minor cleanup, improved standalone compilation | ||
| 48 | |||
| 49 | Version 0.23: | ||
| 50 | Markus: Sign extension bug fixed by declaring transfer_buffer unsigned | ||
| 51 | |||
| 52 | Version 0.22: | ||
| 53 | Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, | ||
| 54 | thanks to Mike Cox for pointing the problem out. | ||
| 55 | |||
| 56 | Version 0.21: | ||
| 57 | Markus: Minor cleanup, warnings if something goes wrong, lame attempt | ||
| 58 | to adhere to Documentation/CodingStyle | ||
| 59 | |||
| 60 | Version 0.2: | ||
| 61 | Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module | ||
| 62 | Markus: Copyright clarification | ||
| 63 | |||
| 64 | Version 0.01: Markus: initial release | ||
| 65 | |||
| 66 | */ | ||
| 67 | |||
| 68 | |||
| 69 | #include <linux/kernel.h> | ||
| 70 | #include <linux/module.h> | ||
| 71 | #include <linux/init.h> | ||
| 72 | #include <linux/slab.h> | ||
| 73 | #include <linux/input.h> | ||
| 74 | #include <linux/videodev.h> | ||
| 75 | #include <linux/usb.h> | ||
| 76 | #include <linux/smp_lock.h> | ||
| 77 | |||
| 78 | /* | ||
| 79 | * Version Information | ||
| 80 | */ | ||
| 81 | #define DRIVER_VERSION "v0.40" | ||
| 82 | #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" | ||
| 83 | #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" | ||
| 84 | |||
| 85 | #define DSB100_VENDOR 0x04b4 | ||
| 86 | #define DSB100_PRODUCT 0x1002 | ||
| 87 | |||
| 88 | /* Commands the device appears to understand */ | ||
| 89 | #define DSB100_TUNE 1 | ||
| 90 | #define DSB100_ONOFF 2 | ||
| 91 | |||
| 92 | #define TB_LEN 16 | ||
| 93 | |||
| 94 | /* Frequency limits in MHz -- these are European values. For Japanese | ||
| 95 | devices, that would be 76 and 91. */ | ||
| 96 | #define FREQ_MIN 87.5 | ||
| 97 | #define FREQ_MAX 108.0 | ||
| 98 | #define FREQ_MUL 16000 | ||
| 99 | |||
| 100 | |||
| 101 | static int usb_dsbr100_probe(struct usb_interface *intf, | ||
| 102 | const struct usb_device_id *id); | ||
| 103 | static void usb_dsbr100_disconnect(struct usb_interface *intf); | ||
| 104 | static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, | ||
| 105 | unsigned int cmd, unsigned long arg); | ||
| 106 | static int usb_dsbr100_open(struct inode *inode, struct file *file); | ||
| 107 | static int usb_dsbr100_close(struct inode *inode, struct file *file); | ||
| 108 | |||
| 109 | static int radio_nr = -1; | ||
| 110 | module_param(radio_nr, int, 0); | ||
| 111 | |||
| 112 | /* Data for one (physical) device */ | ||
| 113 | typedef struct { | ||
| 114 | struct usb_device *usbdev; | ||
| 115 | struct video_device *videodev; | ||
| 116 | unsigned char transfer_buffer[TB_LEN]; | ||
| 117 | int curfreq; | ||
| 118 | int stereo; | ||
| 119 | int users; | ||
| 120 | int removed; | ||
| 121 | } dsbr100_device; | ||
| 122 | |||
| 123 | |||
| 124 | /* File system interface */ | ||
| 125 | static struct file_operations usb_dsbr100_fops = { | ||
| 126 | .owner = THIS_MODULE, | ||
| 127 | .open = usb_dsbr100_open, | ||
| 128 | .release = usb_dsbr100_close, | ||
| 129 | .ioctl = usb_dsbr100_ioctl, | ||
| 130 | .compat_ioctl = v4l_compat_ioctl32, | ||
| 131 | .llseek = no_llseek, | ||
| 132 | }; | ||
| 133 | |||
| 134 | /* V4L interface */ | ||
| 135 | static struct video_device dsbr100_videodev_template= | ||
| 136 | { | ||
| 137 | .owner = THIS_MODULE, | ||
| 138 | .name = "D-Link DSB-R 100", | ||
| 139 | .type = VID_TYPE_TUNER, | ||
| 140 | .hardware = VID_HARDWARE_AZTECH, | ||
| 141 | .fops = &usb_dsbr100_fops, | ||
| 142 | .release = video_device_release, | ||
| 143 | }; | ||
| 144 | |||
| 145 | static struct usb_device_id usb_dsbr100_device_table [] = { | ||
| 146 | { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, | ||
| 147 | { } /* Terminating entry */ | ||
| 148 | }; | ||
| 149 | |||
| 150 | MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); | ||
| 151 | |||
| 152 | /* USB subsystem interface */ | ||
| 153 | static struct usb_driver usb_dsbr100_driver = { | ||
| 154 | .name = "dsbr100", | ||
| 155 | .probe = usb_dsbr100_probe, | ||
| 156 | .disconnect = usb_dsbr100_disconnect, | ||
| 157 | .id_table = usb_dsbr100_device_table, | ||
| 158 | }; | ||
| 159 | |||
| 160 | /* Low-level device interface begins here */ | ||
| 161 | |||
| 162 | /* switch on radio */ | ||
| 163 | static int dsbr100_start(dsbr100_device *radio) | ||
| 164 | { | ||
| 165 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
| 166 | USB_REQ_GET_STATUS, | ||
| 167 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
| 168 | 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 || | ||
| 169 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
| 170 | DSB100_ONOFF, | ||
| 171 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
| 172 | 0x01, 0x00, radio->transfer_buffer, 8, 300)<0) | ||
| 173 | return -1; | ||
| 174 | return (radio->transfer_buffer)[0]; | ||
| 175 | } | ||
| 176 | |||
| 177 | |||
| 178 | /* switch off radio */ | ||
| 179 | static int dsbr100_stop(dsbr100_device *radio) | ||
| 180 | { | ||
| 181 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
| 182 | USB_REQ_GET_STATUS, | ||
| 183 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
| 184 | 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 || | ||
| 185 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
| 186 | DSB100_ONOFF, | ||
| 187 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
| 188 | 0x00, 0x00, radio->transfer_buffer, 8, 300)<0) | ||
| 189 | return -1; | ||
| 190 | return (radio->transfer_buffer)[0]; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ | ||
| 194 | static int dsbr100_setfreq(dsbr100_device *radio, int freq) | ||
| 195 | { | ||
| 196 | freq = (freq/16*80)/1000+856; | ||
| 197 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
| 198 | DSB100_TUNE, | ||
| 199 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
| 200 | (freq>>8)&0x00ff, freq&0xff, | ||
| 201 | radio->transfer_buffer, 8, 300)<0 || | ||
| 202 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
| 203 | USB_REQ_GET_STATUS, | ||
| 204 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
| 205 | 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 || | ||
| 206 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
| 207 | USB_REQ_GET_STATUS, | ||
| 208 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
| 209 | 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) { | ||
| 210 | radio->stereo = -1; | ||
| 211 | return -1; | ||
| 212 | } | ||
| 213 | radio->stereo = ! ((radio->transfer_buffer)[0]&0x01); | ||
| 214 | return (radio->transfer_buffer)[0]; | ||
| 215 | } | ||
| 216 | |||
| 217 | /* return the device status. This is, in effect, just whether it | ||
| 218 | sees a stereo signal or not. Pity. */ | ||
| 219 | static void dsbr100_getstat(dsbr100_device *radio) | ||
| 220 | { | ||
| 221 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
| 222 | USB_REQ_GET_STATUS, | ||
| 223 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
| 224 | 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0) | ||
| 225 | radio->stereo = -1; | ||
| 226 | else | ||
| 227 | radio->stereo = ! (radio->transfer_buffer[0]&0x01); | ||
| 228 | } | ||
| 229 | |||
| 230 | |||
| 231 | /* USB subsystem interface begins here */ | ||
| 232 | |||
| 233 | /* check if the device is present and register with v4l and | ||
| 234 | usb if it is */ | ||
| 235 | static int usb_dsbr100_probe(struct usb_interface *intf, | ||
| 236 | const struct usb_device_id *id) | ||
| 237 | { | ||
| 238 | dsbr100_device *radio; | ||
| 239 | |||
| 240 | if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL))) | ||
| 241 | return -ENOMEM; | ||
| 242 | if (!(radio->videodev = video_device_alloc())) { | ||
| 243 | kfree(radio); | ||
| 244 | return -ENOMEM; | ||
| 245 | } | ||
| 246 | memcpy(radio->videodev, &dsbr100_videodev_template, | ||
| 247 | sizeof(dsbr100_videodev_template)); | ||
| 248 | radio->removed = 0; | ||
| 249 | radio->users = 0; | ||
| 250 | radio->usbdev = interface_to_usbdev(intf); | ||
| 251 | radio->curfreq = FREQ_MIN*FREQ_MUL; | ||
| 252 | video_set_drvdata(radio->videodev, radio); | ||
| 253 | if (video_register_device(radio->videodev, VFL_TYPE_RADIO, | ||
| 254 | radio_nr)) { | ||
| 255 | warn("Could not register video device"); | ||
| 256 | video_device_release(radio->videodev); | ||
| 257 | kfree(radio); | ||
| 258 | return -EIO; | ||
| 259 | } | ||
| 260 | usb_set_intfdata(intf, radio); | ||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 264 | /* handle unplugging of the device, release data structures | ||
| 265 | if nothing keeps us from doing it. If something is still | ||
| 266 | keeping us busy, the release callback of v4l will take care | ||
| 267 | of releasing it. stv680.c does not relase its private | ||
| 268 | data, so I don't do this here either. Checking out the | ||
| 269 | code I'd expect I better did that, but if there's a memory | ||
| 270 | leak here it's tiny (~50 bytes per disconnect) */ | ||
| 271 | static void usb_dsbr100_disconnect(struct usb_interface *intf) | ||
| 272 | { | ||
| 273 | dsbr100_device *radio = usb_get_intfdata(intf); | ||
| 274 | |||
| 275 | usb_set_intfdata (intf, NULL); | ||
| 276 | if (radio) { | ||
| 277 | video_unregister_device(radio->videodev); | ||
| 278 | radio->videodev = NULL; | ||
| 279 | if (radio->users) { | ||
| 280 | kfree(radio); | ||
| 281 | } else { | ||
| 282 | radio->removed = 1; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | |||
| 288 | /* Video for Linux interface */ | ||
| 289 | |||
| 290 | static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file, | ||
| 291 | unsigned int cmd, void *arg) | ||
| 292 | { | ||
| 293 | dsbr100_device *radio=video_get_drvdata(video_devdata(file)); | ||
| 294 | |||
| 295 | if (!radio) | ||
| 296 | return -EIO; | ||
| 297 | |||
| 298 | switch(cmd) { | ||
| 299 | case VIDIOCGCAP: { | ||
| 300 | struct video_capability *v = arg; | ||
| 301 | |||
| 302 | memset(v, 0, sizeof(*v)); | ||
| 303 | v->type = VID_TYPE_TUNER; | ||
| 304 | v->channels = 1; | ||
| 305 | v->audios = 1; | ||
| 306 | strcpy(v->name, "D-Link R-100 USB FM Radio"); | ||
| 307 | return 0; | ||
| 308 | } | ||
| 309 | case VIDIOCGTUNER: { | ||
| 310 | struct video_tuner *v = arg; | ||
| 311 | |||
| 312 | dsbr100_getstat(radio); | ||
| 313 | if(v->tuner) /* Only 1 tuner */ | ||
| 314 | return -EINVAL; | ||
| 315 | v->rangelow = FREQ_MIN*FREQ_MUL; | ||
| 316 | v->rangehigh = FREQ_MAX*FREQ_MUL; | ||
| 317 | v->flags = VIDEO_TUNER_LOW; | ||
| 318 | v->mode = VIDEO_MODE_AUTO; | ||
| 319 | v->signal = radio->stereo*0x7000; | ||
| 320 | /* Don't know how to get signal strength */ | ||
| 321 | v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo; | ||
| 322 | strcpy(v->name, "DSB R-100"); | ||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | case VIDIOCSTUNER: { | ||
| 326 | struct video_tuner *v = arg; | ||
| 327 | |||
| 328 | if(v->tuner!=0) | ||
| 329 | return -EINVAL; | ||
| 330 | /* Only 1 tuner so no setting needed ! */ | ||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | case VIDIOCGFREQ: { | ||
| 334 | int *freq = arg; | ||
| 335 | |||
| 336 | if (radio->curfreq==-1) | ||
| 337 | return -EINVAL; | ||
| 338 | *freq = radio->curfreq; | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | case VIDIOCSFREQ: { | ||
| 342 | int *freq = arg; | ||
| 343 | |||
| 344 | radio->curfreq = *freq; | ||
| 345 | if (dsbr100_setfreq(radio, radio->curfreq)==-1) | ||
| 346 | warn("Set frequency failed"); | ||
| 347 | return 0; | ||
| 348 | } | ||
| 349 | case VIDIOCGAUDIO: { | ||
| 350 | struct video_audio *v = arg; | ||
| 351 | |||
| 352 | memset(v, 0, sizeof(*v)); | ||
| 353 | v->flags |= VIDEO_AUDIO_MUTABLE; | ||
| 354 | v->mode = VIDEO_SOUND_STEREO; | ||
| 355 | v->volume = 1; | ||
| 356 | v->step = 1; | ||
| 357 | strcpy(v->name, "Radio"); | ||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | case VIDIOCSAUDIO: { | ||
| 361 | struct video_audio *v = arg; | ||
| 362 | |||
| 363 | if (v->audio) | ||
| 364 | return -EINVAL; | ||
| 365 | if (v->flags&VIDEO_AUDIO_MUTE) { | ||
| 366 | if (dsbr100_stop(radio)==-1) | ||
| 367 | warn("Radio did not respond properly"); | ||
| 368 | } | ||
| 369 | else | ||
| 370 | if (dsbr100_start(radio)==-1) | ||
| 371 | warn("Radio did not respond properly"); | ||
| 372 | return 0; | ||
| 373 | } | ||
| 374 | default: | ||
| 375 | return -ENOIOCTLCMD; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, | ||
| 380 | unsigned int cmd, unsigned long arg) | ||
| 381 | { | ||
| 382 | return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl); | ||
| 383 | } | ||
| 384 | |||
| 385 | static int usb_dsbr100_open(struct inode *inode, struct file *file) | ||
| 386 | { | ||
| 387 | dsbr100_device *radio=video_get_drvdata(video_devdata(file)); | ||
| 388 | |||
| 389 | radio->users = 1; | ||
| 390 | if (dsbr100_start(radio)<0) { | ||
| 391 | warn("Radio did not start up properly"); | ||
| 392 | radio->users = 0; | ||
| 393 | return -EIO; | ||
| 394 | } | ||
| 395 | dsbr100_setfreq(radio, radio->curfreq); | ||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | static int usb_dsbr100_close(struct inode *inode, struct file *file) | ||
| 400 | { | ||
| 401 | dsbr100_device *radio=video_get_drvdata(video_devdata(file)); | ||
| 402 | |||
| 403 | if (!radio) | ||
| 404 | return -ENODEV; | ||
| 405 | radio->users = 0; | ||
| 406 | if (radio->removed) { | ||
| 407 | kfree(radio); | ||
| 408 | } | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 412 | static int __init dsbr100_init(void) | ||
| 413 | { | ||
| 414 | int retval = usb_register(&usb_dsbr100_driver); | ||
| 415 | info(DRIVER_VERSION ":" DRIVER_DESC); | ||
| 416 | return retval; | ||
| 417 | } | ||
| 418 | |||
| 419 | static void __exit dsbr100_exit(void) | ||
| 420 | { | ||
| 421 | usb_deregister(&usb_dsbr100_driver); | ||
| 422 | } | ||
| 423 | |||
| 424 | module_init (dsbr100_init); | ||
| 425 | module_exit (dsbr100_exit); | ||
| 426 | |||
| 427 | MODULE_AUTHOR( DRIVER_AUTHOR ); | ||
| 428 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
| 429 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/media/et61x251.h b/drivers/usb/media/et61x251.h deleted file mode 100644 index eee8afc9be72..000000000000 --- a/drivers/usb/media/et61x251.h +++ /dev/null | |||
| @@ -1,234 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * V4L2 driver for ET61X[12]51 PC Camera Controllers * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2006 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 _ET61X251_H_ | ||
| 22 | #define _ET61X251_H_ | ||
| 23 | |||
| 24 | #include <linux/version.h> | ||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <linux/videodev2.h> | ||
| 27 | #include <media/v4l2-common.h> | ||
| 28 | #include <linux/device.h> | ||
| 29 | #include <linux/list.h> | ||
| 30 | #include <linux/spinlock.h> | ||
| 31 | #include <linux/time.h> | ||
| 32 | #include <linux/wait.h> | ||
| 33 | #include <linux/types.h> | ||
| 34 | #include <linux/param.h> | ||
| 35 | #include <linux/rwsem.h> | ||
| 36 | #include <linux/mutex.h> | ||
| 37 | #include <linux/stddef.h> | ||
| 38 | #include <linux/string.h> | ||
| 39 | |||
| 40 | #include "et61x251_sensor.h" | ||
| 41 | |||
| 42 | /*****************************************************************************/ | ||
| 43 | |||
| 44 | #define ET61X251_DEBUG | ||
| 45 | #define ET61X251_DEBUG_LEVEL 2 | ||
| 46 | #define ET61X251_MAX_DEVICES 64 | ||
| 47 | #define ET61X251_PRESERVE_IMGSCALE 0 | ||
| 48 | #define ET61X251_FORCE_MUNMAP 0 | ||
| 49 | #define ET61X251_MAX_FRAMES 32 | ||
| 50 | #define ET61X251_COMPRESSION_QUALITY 0 | ||
| 51 | #define ET61X251_URBS 2 | ||
| 52 | #define ET61X251_ISO_PACKETS 7 | ||
| 53 | #define ET61X251_ALTERNATE_SETTING 13 | ||
| 54 | #define ET61X251_URB_TIMEOUT msecs_to_jiffies(2 * ET61X251_ISO_PACKETS) | ||
| 55 | #define ET61X251_CTRL_TIMEOUT 100 | ||
| 56 | #define ET61X251_FRAME_TIMEOUT 2 | ||
| 57 | |||
| 58 | /*****************************************************************************/ | ||
| 59 | |||
| 60 | static const struct usb_device_id et61x251_id_table[] = { | ||
| 61 | { USB_DEVICE(0x102c, 0x6151), }, | ||
| 62 | { USB_DEVICE(0x102c, 0x6251), }, | ||
| 63 | { USB_DEVICE(0x102c, 0x6253), }, | ||
| 64 | { USB_DEVICE(0x102c, 0x6254), }, | ||
| 65 | { USB_DEVICE(0x102c, 0x6255), }, | ||
| 66 | { USB_DEVICE(0x102c, 0x6256), }, | ||
| 67 | { USB_DEVICE(0x102c, 0x6257), }, | ||
| 68 | { USB_DEVICE(0x102c, 0x6258), }, | ||
| 69 | { USB_DEVICE(0x102c, 0x6259), }, | ||
| 70 | { USB_DEVICE(0x102c, 0x625a), }, | ||
| 71 | { USB_DEVICE(0x102c, 0x625b), }, | ||
| 72 | { USB_DEVICE(0x102c, 0x625c), }, | ||
| 73 | { USB_DEVICE(0x102c, 0x625d), }, | ||
| 74 | { USB_DEVICE(0x102c, 0x625e), }, | ||
| 75 | { USB_DEVICE(0x102c, 0x625f), }, | ||
| 76 | { USB_DEVICE(0x102c, 0x6260), }, | ||
| 77 | { USB_DEVICE(0x102c, 0x6261), }, | ||
| 78 | { USB_DEVICE(0x102c, 0x6262), }, | ||
| 79 | { USB_DEVICE(0x102c, 0x6263), }, | ||
| 80 | { USB_DEVICE(0x102c, 0x6264), }, | ||
| 81 | { USB_DEVICE(0x102c, 0x6265), }, | ||
| 82 | { USB_DEVICE(0x102c, 0x6266), }, | ||
| 83 | { USB_DEVICE(0x102c, 0x6267), }, | ||
| 84 | { USB_DEVICE(0x102c, 0x6268), }, | ||
| 85 | { USB_DEVICE(0x102c, 0x6269), }, | ||
| 86 | { } | ||
| 87 | }; | ||
| 88 | |||
| 89 | ET61X251_SENSOR_TABLE | ||
| 90 | |||
| 91 | /*****************************************************************************/ | ||
| 92 | |||
| 93 | enum et61x251_frame_state { | ||
| 94 | F_UNUSED, | ||
| 95 | F_QUEUED, | ||
| 96 | F_GRABBING, | ||
| 97 | F_DONE, | ||
| 98 | F_ERROR, | ||
| 99 | }; | ||
| 100 | |||
| 101 | struct et61x251_frame_t { | ||
| 102 | void* bufmem; | ||
| 103 | struct v4l2_buffer buf; | ||
| 104 | enum et61x251_frame_state state; | ||
| 105 | struct list_head frame; | ||
| 106 | unsigned long vma_use_count; | ||
| 107 | }; | ||
| 108 | |||
| 109 | enum et61x251_dev_state { | ||
| 110 | DEV_INITIALIZED = 0x01, | ||
| 111 | DEV_DISCONNECTED = 0x02, | ||
| 112 | DEV_MISCONFIGURED = 0x04, | ||
| 113 | }; | ||
| 114 | |||
| 115 | enum et61x251_io_method { | ||
| 116 | IO_NONE, | ||
| 117 | IO_READ, | ||
| 118 | IO_MMAP, | ||
| 119 | }; | ||
| 120 | |||
| 121 | enum et61x251_stream_state { | ||
| 122 | STREAM_OFF, | ||
| 123 | STREAM_INTERRUPT, | ||
| 124 | STREAM_ON, | ||
| 125 | }; | ||
| 126 | |||
| 127 | struct et61x251_sysfs_attr { | ||
| 128 | u8 reg, i2c_reg; | ||
| 129 | }; | ||
| 130 | |||
| 131 | struct et61x251_module_param { | ||
| 132 | u8 force_munmap; | ||
| 133 | u16 frame_timeout; | ||
| 134 | }; | ||
| 135 | |||
| 136 | static DEFINE_MUTEX(et61x251_sysfs_lock); | ||
| 137 | static DECLARE_RWSEM(et61x251_disconnect); | ||
| 138 | |||
| 139 | struct et61x251_device { | ||
| 140 | struct video_device* v4ldev; | ||
| 141 | |||
| 142 | struct et61x251_sensor sensor; | ||
| 143 | |||
| 144 | struct usb_device* usbdev; | ||
| 145 | struct urb* urb[ET61X251_URBS]; | ||
| 146 | void* transfer_buffer[ET61X251_URBS]; | ||
| 147 | u8* control_buffer; | ||
| 148 | |||
| 149 | struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES]; | ||
| 150 | struct list_head inqueue, outqueue; | ||
| 151 | u32 frame_count, nbuffers, nreadbuffers; | ||
| 152 | |||
| 153 | enum et61x251_io_method io; | ||
| 154 | enum et61x251_stream_state stream; | ||
| 155 | |||
| 156 | struct v4l2_jpegcompression compression; | ||
| 157 | |||
| 158 | struct et61x251_sysfs_attr sysfs; | ||
| 159 | struct et61x251_module_param module_param; | ||
| 160 | |||
| 161 | enum et61x251_dev_state state; | ||
| 162 | u8 users; | ||
| 163 | |||
| 164 | struct mutex dev_mutex, fileop_mutex; | ||
| 165 | spinlock_t queue_lock; | ||
| 166 | wait_queue_head_t open, wait_frame, wait_stream; | ||
| 167 | }; | ||
| 168 | |||
| 169 | /*****************************************************************************/ | ||
| 170 | |||
| 171 | struct et61x251_device* | ||
| 172 | et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id) | ||
| 173 | { | ||
| 174 | if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) | ||
| 175 | return cam; | ||
| 176 | |||
| 177 | return NULL; | ||
| 178 | } | ||
| 179 | |||
| 180 | |||
| 181 | void | ||
| 182 | et61x251_attach_sensor(struct et61x251_device* cam, | ||
| 183 | struct et61x251_sensor* sensor) | ||
| 184 | { | ||
| 185 | memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor)); | ||
| 186 | } | ||
| 187 | |||
| 188 | /*****************************************************************************/ | ||
| 189 | |||
| 190 | #undef DBG | ||
| 191 | #undef KDBG | ||
| 192 | #ifdef ET61X251_DEBUG | ||
| 193 | # define DBG(level, fmt, args...) \ | ||
| 194 | do { \ | ||
| 195 | if (debug >= (level)) { \ | ||
| 196 | if ((level) == 1) \ | ||
| 197 | dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
| 198 | else if ((level) == 2) \ | ||
| 199 | dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
| 200 | else if ((level) >= 3) \ | ||
| 201 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
| 202 | __FUNCTION__, __LINE__ , ## args); \ | ||
| 203 | } \ | ||
| 204 | } while (0) | ||
| 205 | # define KDBG(level, fmt, args...) \ | ||
| 206 | do { \ | ||
| 207 | if (debug >= (level)) { \ | ||
| 208 | if ((level) == 1 || (level) == 2) \ | ||
| 209 | pr_info("et61x251: " fmt "\n", ## args); \ | ||
| 210 | else if ((level) == 3) \ | ||
| 211 | pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
| 212 | __LINE__ , ## args); \ | ||
| 213 | } \ | ||
| 214 | } while (0) | ||
| 215 | # define V4LDBG(level, name, cmd) \ | ||
| 216 | do { \ | ||
| 217 | if (debug >= (level)) \ | ||
| 218 | v4l_print_ioctl(name, cmd); \ | ||
| 219 | } while (0) | ||
| 220 | #else | ||
| 221 | # define DBG(level, fmt, args...) do {;} while(0) | ||
| 222 | # define KDBG(level, fmt, args...) do {;} while(0) | ||
| 223 | # define V4LDBG(level, name, cmd) do {;} while(0) | ||
| 224 | #endif | ||
| 225 | |||
| 226 | #undef PDBG | ||
| 227 | #define PDBG(fmt, args...) \ | ||
| 228 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
| 229 | __FUNCTION__, __LINE__ , ## args) | ||
| 230 | |||
| 231 | #undef PDBGG | ||
| 232 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ | ||
| 233 | |||
| 234 | #endif /* _ET61X251_H_ */ | ||
diff --git a/drivers/usb/media/et61x251_core.c b/drivers/usb/media/et61x251_core.c deleted file mode 100644 index 7cc01b828b3d..000000000000 --- a/drivers/usb/media/et61x251_core.c +++ /dev/null | |||
| @@ -1,2630 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * V4L2 driver for ET61X[12]51 PC Camera Controllers * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2006 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 | #include <linux/module.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/param.h> | ||
| 25 | #include <linux/moduleparam.h> | ||
| 26 | #include <linux/errno.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/device.h> | ||
| 29 | #include <linux/fs.h> | ||
| 30 | #include <linux/delay.h> | ||
| 31 | #include <linux/compiler.h> | ||
| 32 | #include <linux/ioctl.h> | ||
| 33 | #include <linux/poll.h> | ||
| 34 | #include <linux/stat.h> | ||
| 35 | #include <linux/mm.h> | ||
| 36 | #include <linux/vmalloc.h> | ||
| 37 | #include <linux/page-flags.h> | ||
| 38 | #include <linux/byteorder/generic.h> | ||
| 39 | #include <asm/page.h> | ||
| 40 | #include <asm/uaccess.h> | ||
| 41 | |||
| 42 | #include "et61x251.h" | ||
| 43 | |||
| 44 | /*****************************************************************************/ | ||
| 45 | |||
| 46 | #define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \ | ||
| 47 | "PC Camera Controllers" | ||
| 48 | #define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia" | ||
| 49 | #define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
| 50 | #define ET61X251_MODULE_LICENSE "GPL" | ||
| 51 | #define ET61X251_MODULE_VERSION "1:1.02" | ||
| 52 | #define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2) | ||
| 53 | |||
| 54 | /*****************************************************************************/ | ||
| 55 | |||
| 56 | MODULE_DEVICE_TABLE(usb, et61x251_id_table); | ||
| 57 | |||
| 58 | MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL); | ||
| 59 | MODULE_DESCRIPTION(ET61X251_MODULE_NAME); | ||
| 60 | MODULE_VERSION(ET61X251_MODULE_VERSION); | ||
| 61 | MODULE_LICENSE(ET61X251_MODULE_LICENSE); | ||
| 62 | |||
| 63 | static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1}; | ||
| 64 | module_param_array(video_nr, short, NULL, 0444); | ||
| 65 | MODULE_PARM_DESC(video_nr, | ||
| 66 | "\n<-1|n[,...]> Specify V4L2 minor mode number." | ||
| 67 | "\n -1 = use next available (default)" | ||
| 68 | "\n n = use minor number n (integer >= 0)" | ||
| 69 | "\nYou can specify up to " | ||
| 70 | __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way." | ||
| 71 | "\nFor example:" | ||
| 72 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
| 73 | "\nthe second registered camera and use auto for the first" | ||
| 74 | "\none and for every other camera." | ||
| 75 | "\n"); | ||
| 76 | |||
| 77 | static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] = | ||
| 78 | ET61X251_FORCE_MUNMAP}; | ||
| 79 | module_param_array(force_munmap, bool, NULL, 0444); | ||
| 80 | MODULE_PARM_DESC(force_munmap, | ||
| 81 | "\n<0|1[,...]> Force the application to unmap previously" | ||
| 82 | "\nmapped buffer memory before calling any VIDIOC_S_CROP or" | ||
| 83 | "\nVIDIOC_S_FMT ioctl's. Not all the applications support" | ||
| 84 | "\nthis feature. This parameter is specific for each" | ||
| 85 | "\ndetected camera." | ||
| 86 | "\n 0 = do not force memory unmapping" | ||
| 87 | "\n 1 = force memory unmapping (save memory)" | ||
| 88 | "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." | ||
| 89 | "\n"); | ||
| 90 | |||
| 91 | static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] = | ||
| 92 | ET61X251_FRAME_TIMEOUT}; | ||
| 93 | module_param_array(frame_timeout, uint, NULL, 0644); | ||
| 94 | MODULE_PARM_DESC(frame_timeout, | ||
| 95 | "\n<n[,...]> Timeout for a video frame in seconds." | ||
| 96 | "\nThis parameter is specific for each detected camera." | ||
| 97 | "\nDefault value is " | ||
| 98 | __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"." | ||
| 99 | "\n"); | ||
| 100 | |||
| 101 | #ifdef ET61X251_DEBUG | ||
| 102 | static unsigned short debug = ET61X251_DEBUG_LEVEL; | ||
| 103 | module_param(debug, ushort, 0644); | ||
| 104 | MODULE_PARM_DESC(debug, | ||
| 105 | "\n<n> Debugging information level, from 0 to 3:" | ||
| 106 | "\n0 = none (use carefully)" | ||
| 107 | "\n1 = critical errors" | ||
| 108 | "\n2 = significant informations" | ||
| 109 | "\n3 = more verbose messages" | ||
| 110 | "\nLevel 3 is useful for testing only, when only " | ||
| 111 | "one device is used." | ||
| 112 | "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"." | ||
| 113 | "\n"); | ||
| 114 | #endif | ||
| 115 | |||
| 116 | /*****************************************************************************/ | ||
| 117 | |||
| 118 | static u32 | ||
| 119 | et61x251_request_buffers(struct et61x251_device* cam, u32 count, | ||
| 120 | enum et61x251_io_method io) | ||
| 121 | { | ||
| 122 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | ||
| 123 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | ||
| 124 | const size_t imagesize = cam->module_param.force_munmap || | ||
| 125 | io == IO_READ ? | ||
| 126 | (p->width * p->height * p->priv) / 8 : | ||
| 127 | (r->width * r->height * p->priv) / 8; | ||
| 128 | void* buff = NULL; | ||
| 129 | u32 i; | ||
| 130 | |||
| 131 | if (count > ET61X251_MAX_FRAMES) | ||
| 132 | count = ET61X251_MAX_FRAMES; | ||
| 133 | |||
| 134 | cam->nbuffers = count; | ||
| 135 | while (cam->nbuffers > 0) { | ||
| 136 | if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) | ||
| 137 | break; | ||
| 138 | cam->nbuffers--; | ||
| 139 | } | ||
| 140 | |||
| 141 | for (i = 0; i < cam->nbuffers; i++) { | ||
| 142 | cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); | ||
| 143 | cam->frame[i].buf.index = i; | ||
| 144 | cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); | ||
| 145 | cam->frame[i].buf.length = imagesize; | ||
| 146 | cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 147 | cam->frame[i].buf.sequence = 0; | ||
| 148 | cam->frame[i].buf.field = V4L2_FIELD_NONE; | ||
| 149 | cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; | ||
| 150 | cam->frame[i].buf.flags = 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | return cam->nbuffers; | ||
| 154 | } | ||
| 155 | |||
| 156 | |||
| 157 | static void et61x251_release_buffers(struct et61x251_device* cam) | ||
| 158 | { | ||
| 159 | if (cam->nbuffers) { | ||
| 160 | vfree(cam->frame[0].bufmem); | ||
| 161 | cam->nbuffers = 0; | ||
| 162 | } | ||
| 163 | cam->frame_current = NULL; | ||
| 164 | } | ||
| 165 | |||
| 166 | |||
| 167 | static void et61x251_empty_framequeues(struct et61x251_device* cam) | ||
| 168 | { | ||
| 169 | u32 i; | ||
| 170 | |||
| 171 | INIT_LIST_HEAD(&cam->inqueue); | ||
| 172 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 173 | |||
| 174 | for (i = 0; i < ET61X251_MAX_FRAMES; i++) { | ||
| 175 | cam->frame[i].state = F_UNUSED; | ||
| 176 | cam->frame[i].buf.bytesused = 0; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | |||
| 181 | static void et61x251_requeue_outqueue(struct et61x251_device* cam) | ||
| 182 | { | ||
| 183 | struct et61x251_frame_t *i; | ||
| 184 | |||
| 185 | list_for_each_entry(i, &cam->outqueue, frame) { | ||
| 186 | i->state = F_QUEUED; | ||
| 187 | list_add(&i->frame, &cam->inqueue); | ||
| 188 | } | ||
| 189 | |||
| 190 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 191 | } | ||
| 192 | |||
| 193 | |||
| 194 | static void et61x251_queue_unusedframes(struct et61x251_device* cam) | ||
| 195 | { | ||
| 196 | unsigned long lock_flags; | ||
| 197 | u32 i; | ||
| 198 | |||
| 199 | for (i = 0; i < cam->nbuffers; i++) | ||
| 200 | if (cam->frame[i].state == F_UNUSED) { | ||
| 201 | cam->frame[i].state = F_QUEUED; | ||
| 202 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 203 | list_add_tail(&cam->frame[i].frame, &cam->inqueue); | ||
| 204 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | /*****************************************************************************/ | ||
| 209 | |||
| 210 | int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index) | ||
| 211 | { | ||
| 212 | struct usb_device* udev = cam->usbdev; | ||
| 213 | u8* buff = cam->control_buffer; | ||
| 214 | int res; | ||
| 215 | |||
| 216 | *buff = value; | ||
| 217 | |||
| 218 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
| 219 | 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); | ||
| 220 | if (res < 0) { | ||
| 221 | DBG(3, "Failed to write a register (value 0x%02X, index " | ||
| 222 | "0x%02X, error %d)", value, index, res); | ||
| 223 | return -1; | ||
| 224 | } | ||
| 225 | |||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | |||
| 230 | int et61x251_read_reg(struct et61x251_device* cam, u16 index) | ||
| 231 | { | ||
| 232 | struct usb_device* udev = cam->usbdev; | ||
| 233 | u8* buff = cam->control_buffer; | ||
| 234 | int res; | ||
| 235 | |||
| 236 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
| 237 | 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); | ||
| 238 | if (res < 0) | ||
| 239 | DBG(3, "Failed to read a register (index 0x%02X, error %d)", | ||
| 240 | index, res); | ||
| 241 | |||
| 242 | return (res >= 0) ? (int)(*buff) : -1; | ||
| 243 | } | ||
| 244 | |||
| 245 | |||
| 246 | static int | ||
| 247 | et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor) | ||
| 248 | { | ||
| 249 | int i, r; | ||
| 250 | |||
| 251 | for (i = 1; i <= 8; i++) { | ||
| 252 | if (sensor->interface == ET61X251_I2C_3WIRES) { | ||
| 253 | r = et61x251_read_reg(cam, 0x8e); | ||
| 254 | if (!(r & 0x02) && (r >= 0)) | ||
| 255 | return 0; | ||
| 256 | } else { | ||
| 257 | r = et61x251_read_reg(cam, 0x8b); | ||
| 258 | if (!(r & 0x01) && (r >= 0)) | ||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | if (r < 0) | ||
| 262 | return -EIO; | ||
| 263 | udelay(8*8); /* minimum for sensors at 400kHz */ | ||
| 264 | } | ||
| 265 | |||
| 266 | return -EBUSY; | ||
| 267 | } | ||
| 268 | |||
| 269 | |||
| 270 | int | ||
| 271 | et61x251_i2c_try_read(struct et61x251_device* cam, | ||
| 272 | struct et61x251_sensor* sensor, u8 address) | ||
| 273 | { | ||
| 274 | struct usb_device* udev = cam->usbdev; | ||
| 275 | u8* data = cam->control_buffer; | ||
| 276 | int err = 0, res; | ||
| 277 | |||
| 278 | data[0] = address; | ||
| 279 | data[1] = cam->sensor.i2c_slave_id; | ||
| 280 | data[2] = cam->sensor.rsta | 0x10; | ||
| 281 | data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); | ||
| 282 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
| 283 | 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); | ||
| 284 | if (res < 0) | ||
| 285 | err += res; | ||
| 286 | |||
| 287 | err += et61x251_i2c_wait(cam, sensor); | ||
| 288 | |||
| 289 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
| 290 | 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT); | ||
| 291 | if (res < 0) | ||
| 292 | err += res; | ||
| 293 | |||
| 294 | if (err) | ||
| 295 | DBG(3, "I2C read failed for %s image sensor", sensor->name); | ||
| 296 | |||
| 297 | PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]); | ||
| 298 | |||
| 299 | return err ? -1 : (int)data[0]; | ||
| 300 | } | ||
| 301 | |||
| 302 | |||
| 303 | int | ||
| 304 | et61x251_i2c_try_write(struct et61x251_device* cam, | ||
| 305 | struct et61x251_sensor* sensor, u8 address, u8 value) | ||
| 306 | { | ||
| 307 | struct usb_device* udev = cam->usbdev; | ||
| 308 | u8* data = cam->control_buffer; | ||
| 309 | int err = 0, res; | ||
| 310 | |||
| 311 | data[0] = address; | ||
| 312 | data[1] = cam->sensor.i2c_slave_id; | ||
| 313 | data[2] = cam->sensor.rsta | 0x12; | ||
| 314 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
| 315 | 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); | ||
| 316 | if (res < 0) | ||
| 317 | err += res; | ||
| 318 | |||
| 319 | data[0] = value; | ||
| 320 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
| 321 | 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); | ||
| 322 | if (res < 0) | ||
| 323 | err += res; | ||
| 324 | |||
| 325 | err += et61x251_i2c_wait(cam, sensor); | ||
| 326 | |||
| 327 | if (err) | ||
| 328 | DBG(3, "I2C write failed for %s image sensor", sensor->name); | ||
| 329 | |||
| 330 | PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value); | ||
| 331 | |||
| 332 | return err ? -1 : 0; | ||
| 333 | } | ||
| 334 | |||
| 335 | |||
| 336 | int | ||
| 337 | et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, | ||
| 338 | u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, | ||
| 339 | u8 data8, u8 address) | ||
| 340 | { | ||
| 341 | struct usb_device* udev = cam->usbdev; | ||
| 342 | u8* data = cam->control_buffer; | ||
| 343 | int err = 0, res; | ||
| 344 | |||
| 345 | data[0] = data2; | ||
| 346 | data[1] = data3; | ||
| 347 | data[2] = data4; | ||
| 348 | data[3] = data5; | ||
| 349 | data[4] = data6; | ||
| 350 | data[5] = data7; | ||
| 351 | data[6] = data8; | ||
| 352 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
| 353 | 0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT); | ||
| 354 | if (res < 0) | ||
| 355 | err += res; | ||
| 356 | |||
| 357 | data[0] = address; | ||
| 358 | data[1] = cam->sensor.i2c_slave_id; | ||
| 359 | data[2] = cam->sensor.rsta | 0x02 | (n << 4); | ||
| 360 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
| 361 | 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); | ||
| 362 | if (res < 0) | ||
| 363 | err += res; | ||
| 364 | |||
| 365 | /* Start writing through the serial interface */ | ||
| 366 | data[0] = data1; | ||
| 367 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
| 368 | 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); | ||
| 369 | if (res < 0) | ||
| 370 | err += res; | ||
| 371 | |||
| 372 | err += et61x251_i2c_wait(cam, &cam->sensor); | ||
| 373 | |||
| 374 | if (err) | ||
| 375 | DBG(3, "I2C raw write failed for %s image sensor", | ||
| 376 | cam->sensor.name); | ||
| 377 | |||
| 378 | PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, " | ||
| 379 | "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X," | ||
| 380 | " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address, | ||
| 381 | data1, data2, data3, data4, data5, data6, data7, data8); | ||
| 382 | |||
| 383 | return err ? -1 : 0; | ||
| 384 | |||
| 385 | } | ||
| 386 | |||
| 387 | |||
| 388 | int et61x251_i2c_read(struct et61x251_device* cam, u8 address) | ||
| 389 | { | ||
| 390 | return et61x251_i2c_try_read(cam, &cam->sensor, address); | ||
| 391 | } | ||
| 392 | |||
| 393 | |||
| 394 | int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) | ||
| 395 | { | ||
| 396 | return et61x251_i2c_try_write(cam, &cam->sensor, address, value); | ||
| 397 | } | ||
| 398 | |||
| 399 | /*****************************************************************************/ | ||
| 400 | |||
| 401 | static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs) | ||
| 402 | { | ||
| 403 | struct et61x251_device* cam = urb->context; | ||
| 404 | struct et61x251_frame_t** f; | ||
| 405 | size_t imagesize; | ||
| 406 | u8 i; | ||
| 407 | int err = 0; | ||
| 408 | |||
| 409 | if (urb->status == -ENOENT) | ||
| 410 | return; | ||
| 411 | |||
| 412 | f = &cam->frame_current; | ||
| 413 | |||
| 414 | if (cam->stream == STREAM_INTERRUPT) { | ||
| 415 | cam->stream = STREAM_OFF; | ||
| 416 | if ((*f)) | ||
| 417 | (*f)->state = F_QUEUED; | ||
| 418 | DBG(3, "Stream interrupted"); | ||
| 419 | wake_up(&cam->wait_stream); | ||
| 420 | } | ||
| 421 | |||
| 422 | if (cam->state & DEV_DISCONNECTED) | ||
| 423 | return; | ||
| 424 | |||
| 425 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 426 | wake_up_interruptible(&cam->wait_frame); | ||
| 427 | return; | ||
| 428 | } | ||
| 429 | |||
| 430 | if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) | ||
| 431 | goto resubmit_urb; | ||
| 432 | |||
| 433 | if (!(*f)) | ||
| 434 | (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t, | ||
| 435 | frame); | ||
| 436 | |||
| 437 | imagesize = (cam->sensor.pix_format.width * | ||
| 438 | cam->sensor.pix_format.height * | ||
| 439 | cam->sensor.pix_format.priv) / 8; | ||
| 440 | |||
| 441 | for (i = 0; i < urb->number_of_packets; i++) { | ||
| 442 | unsigned int len, status; | ||
| 443 | void *pos; | ||
| 444 | u8* b1, * b2, sof; | ||
| 445 | const u8 VOID_BYTES = 6; | ||
| 446 | size_t imglen; | ||
| 447 | |||
| 448 | len = urb->iso_frame_desc[i].actual_length; | ||
| 449 | status = urb->iso_frame_desc[i].status; | ||
| 450 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
| 451 | |||
| 452 | if (status) { | ||
| 453 | DBG(3, "Error in isochronous frame"); | ||
| 454 | (*f)->state = F_ERROR; | ||
| 455 | continue; | ||
| 456 | } | ||
| 457 | |||
| 458 | b1 = pos++; | ||
| 459 | b2 = pos++; | ||
| 460 | sof = ((*b1 & 0x3f) == 63); | ||
| 461 | imglen = ((*b1 & 0xc0) << 2) | *b2; | ||
| 462 | |||
| 463 | PDBGG("Isochrnous frame: length %u, #%u i, image length %zu", | ||
| 464 | len, i, imglen); | ||
| 465 | |||
| 466 | if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) | ||
| 467 | start_of_frame: | ||
| 468 | if (sof) { | ||
| 469 | (*f)->state = F_GRABBING; | ||
| 470 | (*f)->buf.bytesused = 0; | ||
| 471 | do_gettimeofday(&(*f)->buf.timestamp); | ||
| 472 | pos += 22; | ||
| 473 | DBG(3, "SOF detected: new video frame"); | ||
| 474 | } | ||
| 475 | |||
| 476 | if ((*f)->state == F_GRABBING) { | ||
| 477 | if (sof && (*f)->buf.bytesused) { | ||
| 478 | if (cam->sensor.pix_format.pixelformat == | ||
| 479 | V4L2_PIX_FMT_ET61X251) | ||
| 480 | goto end_of_frame; | ||
| 481 | else { | ||
| 482 | DBG(3, "Not expected SOF detected " | ||
| 483 | "after %lu bytes", | ||
| 484 | (unsigned long)(*f)->buf.bytesused); | ||
| 485 | (*f)->state = F_ERROR; | ||
| 486 | continue; | ||
| 487 | } | ||
| 488 | } | ||
| 489 | |||
| 490 | if ((*f)->buf.bytesused + imglen > imagesize) { | ||
| 491 | DBG(3, "Video frame size exceeded"); | ||
| 492 | (*f)->state = F_ERROR; | ||
| 493 | continue; | ||
| 494 | } | ||
| 495 | |||
| 496 | pos += VOID_BYTES; | ||
| 497 | |||
| 498 | memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen); | ||
| 499 | (*f)->buf.bytesused += imglen; | ||
| 500 | |||
| 501 | if ((*f)->buf.bytesused == imagesize) { | ||
| 502 | u32 b; | ||
| 503 | end_of_frame: | ||
| 504 | b = (*f)->buf.bytesused; | ||
| 505 | (*f)->state = F_DONE; | ||
| 506 | (*f)->buf.sequence= ++cam->frame_count; | ||
| 507 | spin_lock(&cam->queue_lock); | ||
| 508 | list_move_tail(&(*f)->frame, &cam->outqueue); | ||
| 509 | if (!list_empty(&cam->inqueue)) | ||
| 510 | (*f) = list_entry(cam->inqueue.next, | ||
| 511 | struct et61x251_frame_t, | ||
| 512 | frame); | ||
| 513 | else | ||
| 514 | (*f) = NULL; | ||
| 515 | spin_unlock(&cam->queue_lock); | ||
| 516 | DBG(3, "Video frame captured: : %lu bytes", | ||
| 517 | (unsigned long)(b)); | ||
| 518 | |||
| 519 | if (!(*f)) | ||
| 520 | goto resubmit_urb; | ||
| 521 | |||
| 522 | if (sof && | ||
| 523 | cam->sensor.pix_format.pixelformat == | ||
| 524 | V4L2_PIX_FMT_ET61X251) | ||
| 525 | goto start_of_frame; | ||
| 526 | } | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | resubmit_urb: | ||
| 531 | urb->dev = cam->usbdev; | ||
| 532 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 533 | if (err < 0 && err != -EPERM) { | ||
| 534 | cam->state |= DEV_MISCONFIGURED; | ||
| 535 | DBG(1, "usb_submit_urb() failed"); | ||
| 536 | } | ||
| 537 | |||
| 538 | wake_up_interruptible(&cam->wait_frame); | ||
| 539 | } | ||
| 540 | |||
| 541 | |||
| 542 | static int et61x251_start_transfer(struct et61x251_device* cam) | ||
| 543 | { | ||
| 544 | struct usb_device *udev = cam->usbdev; | ||
| 545 | struct urb* urb; | ||
| 546 | const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832, | ||
| 547 | 864, 896, 920, 956, 980, 1000, | ||
| 548 | 1022}; | ||
| 549 | const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING]; | ||
| 550 | s8 i, j; | ||
| 551 | int err = 0; | ||
| 552 | |||
| 553 | for (i = 0; i < ET61X251_URBS; i++) { | ||
| 554 | cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz, | ||
| 555 | GFP_KERNEL); | ||
| 556 | if (!cam->transfer_buffer[i]) { | ||
| 557 | err = -ENOMEM; | ||
| 558 | DBG(1, "Not enough memory"); | ||
| 559 | goto free_buffers; | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | for (i = 0; i < ET61X251_URBS; i++) { | ||
| 564 | urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL); | ||
| 565 | cam->urb[i] = urb; | ||
| 566 | if (!urb) { | ||
| 567 | err = -ENOMEM; | ||
| 568 | DBG(1, "usb_alloc_urb() failed"); | ||
| 569 | goto free_urbs; | ||
| 570 | } | ||
| 571 | urb->dev = udev; | ||
| 572 | urb->context = cam; | ||
| 573 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
| 574 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 575 | urb->number_of_packets = ET61X251_ISO_PACKETS; | ||
| 576 | urb->complete = et61x251_urb_complete; | ||
| 577 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
| 578 | urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS; | ||
| 579 | urb->interval = 1; | ||
| 580 | for (j = 0; j < ET61X251_ISO_PACKETS; j++) { | ||
| 581 | urb->iso_frame_desc[j].offset = psz * j; | ||
| 582 | urb->iso_frame_desc[j].length = psz; | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | err = et61x251_write_reg(cam, 0x01, 0x03); | ||
| 587 | err = et61x251_write_reg(cam, 0x00, 0x03); | ||
| 588 | err = et61x251_write_reg(cam, 0x08, 0x03); | ||
| 589 | if (err) { | ||
| 590 | err = -EIO; | ||
| 591 | DBG(1, "I/O hardware error"); | ||
| 592 | goto free_urbs; | ||
| 593 | } | ||
| 594 | |||
| 595 | err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING); | ||
| 596 | if (err) { | ||
| 597 | DBG(1, "usb_set_interface() failed"); | ||
| 598 | goto free_urbs; | ||
| 599 | } | ||
| 600 | |||
| 601 | cam->frame_current = NULL; | ||
| 602 | |||
| 603 | for (i = 0; i < ET61X251_URBS; i++) { | ||
| 604 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
| 605 | if (err) { | ||
| 606 | for (j = i-1; j >= 0; j--) | ||
| 607 | usb_kill_urb(cam->urb[j]); | ||
| 608 | DBG(1, "usb_submit_urb() failed, error %d", err); | ||
| 609 | goto free_urbs; | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | return 0; | ||
| 614 | |||
| 615 | free_urbs: | ||
| 616 | for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++) | ||
| 617 | usb_free_urb(cam->urb[i]); | ||
| 618 | |||
| 619 | free_buffers: | ||
| 620 | for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++) | ||
| 621 | kfree(cam->transfer_buffer[i]); | ||
| 622 | |||
| 623 | return err; | ||
| 624 | } | ||
| 625 | |||
| 626 | |||
| 627 | static int et61x251_stop_transfer(struct et61x251_device* cam) | ||
| 628 | { | ||
| 629 | struct usb_device *udev = cam->usbdev; | ||
| 630 | s8 i; | ||
| 631 | int err = 0; | ||
| 632 | |||
| 633 | if (cam->state & DEV_DISCONNECTED) | ||
| 634 | return 0; | ||
| 635 | |||
| 636 | for (i = ET61X251_URBS-1; i >= 0; i--) { | ||
| 637 | usb_kill_urb(cam->urb[i]); | ||
| 638 | usb_free_urb(cam->urb[i]); | ||
| 639 | kfree(cam->transfer_buffer[i]); | ||
| 640 | } | ||
| 641 | |||
| 642 | err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
| 643 | if (err) | ||
| 644 | DBG(3, "usb_set_interface() failed"); | ||
| 645 | |||
| 646 | return err; | ||
| 647 | } | ||
| 648 | |||
| 649 | |||
| 650 | static int et61x251_stream_interrupt(struct et61x251_device* cam) | ||
| 651 | { | ||
| 652 | long timeout; | ||
| 653 | |||
| 654 | cam->stream = STREAM_INTERRUPT; | ||
| 655 | timeout = wait_event_timeout(cam->wait_stream, | ||
| 656 | (cam->stream == STREAM_OFF) || | ||
| 657 | (cam->state & DEV_DISCONNECTED), | ||
| 658 | ET61X251_URB_TIMEOUT); | ||
| 659 | if (cam->state & DEV_DISCONNECTED) | ||
| 660 | return -ENODEV; | ||
| 661 | else if (cam->stream != STREAM_OFF) { | ||
| 662 | cam->state |= DEV_MISCONFIGURED; | ||
| 663 | DBG(1, "URB timeout reached. The camera is misconfigured. To " | ||
| 664 | "use it, close and open /dev/video%d again.", | ||
| 665 | cam->v4ldev->minor); | ||
| 666 | return -EIO; | ||
| 667 | } | ||
| 668 | |||
| 669 | return 0; | ||
| 670 | } | ||
| 671 | |||
| 672 | /*****************************************************************************/ | ||
| 673 | |||
| 674 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
| 675 | static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) | ||
| 676 | { | ||
| 677 | char str[5]; | ||
| 678 | char* endp; | ||
| 679 | unsigned long val; | ||
| 680 | |||
| 681 | if (len < 4) { | ||
| 682 | strncpy(str, buff, len); | ||
| 683 | str[len+1] = '\0'; | ||
| 684 | } else { | ||
| 685 | strncpy(str, buff, 4); | ||
| 686 | str[4] = '\0'; | ||
| 687 | } | ||
| 688 | |||
| 689 | val = simple_strtoul(str, &endp, 0); | ||
| 690 | |||
| 691 | *count = 0; | ||
| 692 | if (val <= 0xff) | ||
| 693 | *count = (ssize_t)(endp - str); | ||
| 694 | if ((*count) && (len == *count+1) && (buff[*count] == '\n')) | ||
| 695 | *count += 1; | ||
| 696 | |||
| 697 | return (u8)val; | ||
| 698 | } | ||
| 699 | |||
| 700 | /* | ||
| 701 | NOTE 1: being inside one of the following methods implies that the v4l | ||
| 702 | device exists for sure (see kobjects and reference counters) | ||
| 703 | NOTE 2: buffers are PAGE_SIZE long | ||
| 704 | */ | ||
| 705 | |||
| 706 | static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) | ||
| 707 | { | ||
| 708 | struct et61x251_device* cam; | ||
| 709 | ssize_t count; | ||
| 710 | |||
| 711 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
| 712 | return -ERESTARTSYS; | ||
| 713 | |||
| 714 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 715 | if (!cam) { | ||
| 716 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 717 | return -ENODEV; | ||
| 718 | } | ||
| 719 | |||
| 720 | count = sprintf(buf, "%u\n", cam->sysfs.reg); | ||
| 721 | |||
| 722 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 723 | |||
| 724 | return count; | ||
| 725 | } | ||
| 726 | |||
| 727 | |||
| 728 | static ssize_t | ||
| 729 | et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) | ||
| 730 | { | ||
| 731 | struct et61x251_device* cam; | ||
| 732 | u8 index; | ||
| 733 | ssize_t count; | ||
| 734 | |||
| 735 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
| 736 | return -ERESTARTSYS; | ||
| 737 | |||
| 738 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 739 | if (!cam) { | ||
| 740 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 741 | return -ENODEV; | ||
| 742 | } | ||
| 743 | |||
| 744 | index = et61x251_strtou8(buf, len, &count); | ||
| 745 | if (index > 0x8e || !count) { | ||
| 746 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 747 | return -EINVAL; | ||
| 748 | } | ||
| 749 | |||
| 750 | cam->sysfs.reg = index; | ||
| 751 | |||
| 752 | DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg); | ||
| 753 | DBG(3, "Written bytes: %zd", count); | ||
| 754 | |||
| 755 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 756 | |||
| 757 | return count; | ||
| 758 | } | ||
| 759 | |||
| 760 | |||
| 761 | static ssize_t et61x251_show_val(struct class_device* cd, char* buf) | ||
| 762 | { | ||
| 763 | struct et61x251_device* cam; | ||
| 764 | ssize_t count; | ||
| 765 | int val; | ||
| 766 | |||
| 767 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
| 768 | return -ERESTARTSYS; | ||
| 769 | |||
| 770 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 771 | if (!cam) { | ||
| 772 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 773 | return -ENODEV; | ||
| 774 | } | ||
| 775 | |||
| 776 | if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) { | ||
| 777 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 778 | return -EIO; | ||
| 779 | } | ||
| 780 | |||
| 781 | count = sprintf(buf, "%d\n", val); | ||
| 782 | |||
| 783 | DBG(3, "Read bytes: %zd", count); | ||
| 784 | |||
| 785 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 786 | |||
| 787 | return count; | ||
| 788 | } | ||
| 789 | |||
| 790 | |||
| 791 | static ssize_t | ||
| 792 | et61x251_store_val(struct class_device* cd, const char* buf, size_t len) | ||
| 793 | { | ||
| 794 | struct et61x251_device* cam; | ||
| 795 | u8 value; | ||
| 796 | ssize_t count; | ||
| 797 | int err; | ||
| 798 | |||
| 799 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
| 800 | return -ERESTARTSYS; | ||
| 801 | |||
| 802 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 803 | if (!cam) { | ||
| 804 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 805 | return -ENODEV; | ||
| 806 | } | ||
| 807 | |||
| 808 | value = et61x251_strtou8(buf, len, &count); | ||
| 809 | if (!count) { | ||
| 810 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 811 | return -EINVAL; | ||
| 812 | } | ||
| 813 | |||
| 814 | err = et61x251_write_reg(cam, value, cam->sysfs.reg); | ||
| 815 | if (err) { | ||
| 816 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 817 | return -EIO; | ||
| 818 | } | ||
| 819 | |||
| 820 | DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X", | ||
| 821 | cam->sysfs.reg, value); | ||
| 822 | DBG(3, "Written bytes: %zd", count); | ||
| 823 | |||
| 824 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 825 | |||
| 826 | return count; | ||
| 827 | } | ||
| 828 | |||
| 829 | |||
| 830 | static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) | ||
| 831 | { | ||
| 832 | struct et61x251_device* cam; | ||
| 833 | ssize_t count; | ||
| 834 | |||
| 835 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
| 836 | return -ERESTARTSYS; | ||
| 837 | |||
| 838 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 839 | if (!cam) { | ||
| 840 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 841 | return -ENODEV; | ||
| 842 | } | ||
| 843 | |||
| 844 | count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); | ||
| 845 | |||
| 846 | DBG(3, "Read bytes: %zd", count); | ||
| 847 | |||
| 848 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 849 | |||
| 850 | return count; | ||
| 851 | } | ||
| 852 | |||
| 853 | |||
| 854 | static ssize_t | ||
| 855 | et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) | ||
| 856 | { | ||
| 857 | struct et61x251_device* cam; | ||
| 858 | u8 index; | ||
| 859 | ssize_t count; | ||
| 860 | |||
| 861 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
| 862 | return -ERESTARTSYS; | ||
| 863 | |||
| 864 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 865 | if (!cam) { | ||
| 866 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 867 | return -ENODEV; | ||
| 868 | } | ||
| 869 | |||
| 870 | index = et61x251_strtou8(buf, len, &count); | ||
| 871 | if (!count) { | ||
| 872 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 873 | return -EINVAL; | ||
| 874 | } | ||
| 875 | |||
| 876 | cam->sysfs.i2c_reg = index; | ||
| 877 | |||
| 878 | DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); | ||
| 879 | DBG(3, "Written bytes: %zd", count); | ||
| 880 | |||
| 881 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 882 | |||
| 883 | return count; | ||
| 884 | } | ||
| 885 | |||
| 886 | |||
| 887 | static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) | ||
| 888 | { | ||
| 889 | struct et61x251_device* cam; | ||
| 890 | ssize_t count; | ||
| 891 | int val; | ||
| 892 | |||
| 893 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
| 894 | return -ERESTARTSYS; | ||
| 895 | |||
| 896 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 897 | if (!cam) { | ||
| 898 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 899 | return -ENODEV; | ||
| 900 | } | ||
| 901 | |||
| 902 | if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { | ||
| 903 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 904 | return -ENOSYS; | ||
| 905 | } | ||
| 906 | |||
| 907 | if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { | ||
| 908 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 909 | return -EIO; | ||
| 910 | } | ||
| 911 | |||
| 912 | count = sprintf(buf, "%d\n", val); | ||
| 913 | |||
| 914 | DBG(3, "Read bytes: %zd", count); | ||
| 915 | |||
| 916 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 917 | |||
| 918 | return count; | ||
| 919 | } | ||
| 920 | |||
| 921 | |||
| 922 | static ssize_t | ||
| 923 | et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) | ||
| 924 | { | ||
| 925 | struct et61x251_device* cam; | ||
| 926 | u8 value; | ||
| 927 | ssize_t count; | ||
| 928 | int err; | ||
| 929 | |||
| 930 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
| 931 | return -ERESTARTSYS; | ||
| 932 | |||
| 933 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 934 | if (!cam) { | ||
| 935 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 936 | return -ENODEV; | ||
| 937 | } | ||
| 938 | |||
| 939 | if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { | ||
| 940 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 941 | return -ENOSYS; | ||
| 942 | } | ||
| 943 | |||
| 944 | value = et61x251_strtou8(buf, len, &count); | ||
| 945 | if (!count) { | ||
| 946 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 947 | return -EINVAL; | ||
| 948 | } | ||
| 949 | |||
| 950 | err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value); | ||
| 951 | if (err) { | ||
| 952 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 953 | return -EIO; | ||
| 954 | } | ||
| 955 | |||
| 956 | DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", | ||
| 957 | cam->sysfs.i2c_reg, value); | ||
| 958 | DBG(3, "Written bytes: %zd", count); | ||
| 959 | |||
| 960 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 961 | |||
| 962 | return count; | ||
| 963 | } | ||
| 964 | |||
| 965 | |||
| 966 | static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, | ||
| 967 | et61x251_show_reg, et61x251_store_reg); | ||
| 968 | static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, | ||
| 969 | et61x251_show_val, et61x251_store_val); | ||
| 970 | static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, | ||
| 971 | et61x251_show_i2c_reg, et61x251_store_i2c_reg); | ||
| 972 | static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, | ||
| 973 | et61x251_show_i2c_val, et61x251_store_i2c_val); | ||
| 974 | |||
| 975 | |||
| 976 | static void et61x251_create_sysfs(struct et61x251_device* cam) | ||
| 977 | { | ||
| 978 | struct video_device *v4ldev = cam->v4ldev; | ||
| 979 | |||
| 980 | video_device_create_file(v4ldev, &class_device_attr_reg); | ||
| 981 | video_device_create_file(v4ldev, &class_device_attr_val); | ||
| 982 | if (cam->sensor.sysfs_ops) { | ||
| 983 | video_device_create_file(v4ldev, &class_device_attr_i2c_reg); | ||
| 984 | video_device_create_file(v4ldev, &class_device_attr_i2c_val); | ||
| 985 | } | ||
| 986 | } | ||
| 987 | #endif /* CONFIG_VIDEO_ADV_DEBUG */ | ||
| 988 | |||
| 989 | /*****************************************************************************/ | ||
| 990 | |||
| 991 | static int | ||
| 992 | et61x251_set_pix_format(struct et61x251_device* cam, | ||
| 993 | struct v4l2_pix_format* pix) | ||
| 994 | { | ||
| 995 | int r, err = 0; | ||
| 996 | |||
| 997 | if ((r = et61x251_read_reg(cam, 0x12)) < 0) | ||
| 998 | err += r; | ||
| 999 | if (pix->pixelformat == V4L2_PIX_FMT_ET61X251) | ||
| 1000 | err += et61x251_write_reg(cam, r & 0xfd, 0x12); | ||
| 1001 | else | ||
| 1002 | err += et61x251_write_reg(cam, r | 0x02, 0x12); | ||
| 1003 | |||
| 1004 | return err ? -EIO : 0; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | |||
| 1008 | static int | ||
| 1009 | et61x251_set_compression(struct et61x251_device* cam, | ||
| 1010 | struct v4l2_jpegcompression* compression) | ||
| 1011 | { | ||
| 1012 | int r, err = 0; | ||
| 1013 | |||
| 1014 | if ((r = et61x251_read_reg(cam, 0x12)) < 0) | ||
| 1015 | err += r; | ||
| 1016 | if (compression->quality == 0) | ||
| 1017 | err += et61x251_write_reg(cam, r & 0xfb, 0x12); | ||
| 1018 | else | ||
| 1019 | err += et61x251_write_reg(cam, r | 0x04, 0x12); | ||
| 1020 | |||
| 1021 | return err ? -EIO : 0; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | |||
| 1025 | static int et61x251_set_scale(struct et61x251_device* cam, u8 scale) | ||
| 1026 | { | ||
| 1027 | int r = 0, err = 0; | ||
| 1028 | |||
| 1029 | r = et61x251_read_reg(cam, 0x12); | ||
| 1030 | if (r < 0) | ||
| 1031 | err += r; | ||
| 1032 | |||
| 1033 | if (scale == 1) | ||
| 1034 | err += et61x251_write_reg(cam, r & ~0x01, 0x12); | ||
| 1035 | else if (scale == 2) | ||
| 1036 | err += et61x251_write_reg(cam, r | 0x01, 0x12); | ||
| 1037 | |||
| 1038 | if (err) | ||
| 1039 | return -EIO; | ||
| 1040 | |||
| 1041 | PDBGG("Scaling factor: %u", scale); | ||
| 1042 | |||
| 1043 | return 0; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | |||
| 1047 | static int | ||
| 1048 | et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect) | ||
| 1049 | { | ||
| 1050 | struct et61x251_sensor* s = &cam->sensor; | ||
| 1051 | u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left + | ||
| 1052 | s->active_pixel.left), | ||
| 1053 | fmw_sy = (u16)(rect->top - s->cropcap.bounds.top + | ||
| 1054 | s->active_pixel.top), | ||
| 1055 | fmw_length = (u16)(rect->width), | ||
| 1056 | fmw_height = (u16)(rect->height); | ||
| 1057 | int err = 0; | ||
| 1058 | |||
| 1059 | err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69); | ||
| 1060 | err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a); | ||
| 1061 | err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b); | ||
| 1062 | err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c); | ||
| 1063 | err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6) | ||
| 1064 | | ((fmw_length & 0x300) >> 4) | ||
| 1065 | | ((fmw_height & 0x300) >> 2), 0x6d); | ||
| 1066 | if (err) | ||
| 1067 | return -EIO; | ||
| 1068 | |||
| 1069 | PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u", | ||
| 1070 | fmw_sx, fmw_sy, fmw_length, fmw_height); | ||
| 1071 | |||
| 1072 | return 0; | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | |||
| 1076 | static int et61x251_init(struct et61x251_device* cam) | ||
| 1077 | { | ||
| 1078 | struct et61x251_sensor* s = &cam->sensor; | ||
| 1079 | struct v4l2_control ctrl; | ||
| 1080 | struct v4l2_queryctrl *qctrl; | ||
| 1081 | struct v4l2_rect* rect; | ||
| 1082 | u8 i = 0; | ||
| 1083 | int err = 0; | ||
| 1084 | |||
| 1085 | if (!(cam->state & DEV_INITIALIZED)) { | ||
| 1086 | init_waitqueue_head(&cam->open); | ||
| 1087 | qctrl = s->qctrl; | ||
| 1088 | rect = &(s->cropcap.defrect); | ||
| 1089 | cam->compression.quality = ET61X251_COMPRESSION_QUALITY; | ||
| 1090 | } else { /* use current values */ | ||
| 1091 | qctrl = s->_qctrl; | ||
| 1092 | rect = &(s->_rect); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | err += et61x251_set_scale(cam, rect->width / s->pix_format.width); | ||
| 1096 | err += et61x251_set_crop(cam, rect); | ||
| 1097 | if (err) | ||
| 1098 | return err; | ||
| 1099 | |||
| 1100 | if (s->init) { | ||
| 1101 | err = s->init(cam); | ||
| 1102 | if (err) { | ||
| 1103 | DBG(3, "Sensor initialization failed"); | ||
| 1104 | return err; | ||
| 1105 | } | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | err += et61x251_set_compression(cam, &cam->compression); | ||
| 1109 | err += et61x251_set_pix_format(cam, &s->pix_format); | ||
| 1110 | if (s->set_pix_format) | ||
| 1111 | err += s->set_pix_format(cam, &s->pix_format); | ||
| 1112 | if (err) | ||
| 1113 | return err; | ||
| 1114 | |||
| 1115 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251) | ||
| 1116 | DBG(3, "Compressed video format is active, quality %d", | ||
| 1117 | cam->compression.quality); | ||
| 1118 | else | ||
| 1119 | DBG(3, "Uncompressed video format is active"); | ||
| 1120 | |||
| 1121 | if (s->set_crop) | ||
| 1122 | if ((err = s->set_crop(cam, rect))) { | ||
| 1123 | DBG(3, "set_crop() failed"); | ||
| 1124 | return err; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | if (s->set_ctrl) { | ||
| 1128 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1129 | if (s->qctrl[i].id != 0 && | ||
| 1130 | !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { | ||
| 1131 | ctrl.id = s->qctrl[i].id; | ||
| 1132 | ctrl.value = qctrl[i].default_value; | ||
| 1133 | err = s->set_ctrl(cam, &ctrl); | ||
| 1134 | if (err) { | ||
| 1135 | DBG(3, "Set %s control failed", | ||
| 1136 | s->qctrl[i].name); | ||
| 1137 | return err; | ||
| 1138 | } | ||
| 1139 | DBG(3, "Image sensor supports '%s' control", | ||
| 1140 | s->qctrl[i].name); | ||
| 1141 | } | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | if (!(cam->state & DEV_INITIALIZED)) { | ||
| 1145 | mutex_init(&cam->fileop_mutex); | ||
| 1146 | spin_lock_init(&cam->queue_lock); | ||
| 1147 | init_waitqueue_head(&cam->wait_frame); | ||
| 1148 | init_waitqueue_head(&cam->wait_stream); | ||
| 1149 | cam->nreadbuffers = 2; | ||
| 1150 | memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); | ||
| 1151 | memcpy(&(s->_rect), &(s->cropcap.defrect), | ||
| 1152 | sizeof(struct v4l2_rect)); | ||
| 1153 | cam->state |= DEV_INITIALIZED; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | DBG(2, "Initialization succeeded"); | ||
| 1157 | return 0; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | |||
| 1161 | static void et61x251_release_resources(struct et61x251_device* cam) | ||
| 1162 | { | ||
| 1163 | mutex_lock(&et61x251_sysfs_lock); | ||
| 1164 | |||
| 1165 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); | ||
| 1166 | video_set_drvdata(cam->v4ldev, NULL); | ||
| 1167 | video_unregister_device(cam->v4ldev); | ||
| 1168 | |||
| 1169 | usb_put_dev(cam->usbdev); | ||
| 1170 | |||
| 1171 | mutex_unlock(&et61x251_sysfs_lock); | ||
| 1172 | |||
| 1173 | kfree(cam->control_buffer); | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | /*****************************************************************************/ | ||
| 1177 | |||
| 1178 | static int et61x251_open(struct inode* inode, struct file* filp) | ||
| 1179 | { | ||
| 1180 | struct et61x251_device* cam; | ||
| 1181 | int err = 0; | ||
| 1182 | |||
| 1183 | /* | ||
| 1184 | This is the only safe way to prevent race conditions with | ||
| 1185 | disconnect | ||
| 1186 | */ | ||
| 1187 | if (!down_read_trylock(&et61x251_disconnect)) | ||
| 1188 | return -ERESTARTSYS; | ||
| 1189 | |||
| 1190 | cam = video_get_drvdata(video_devdata(filp)); | ||
| 1191 | |||
| 1192 | if (mutex_lock_interruptible(&cam->dev_mutex)) { | ||
| 1193 | up_read(&et61x251_disconnect); | ||
| 1194 | return -ERESTARTSYS; | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | if (cam->users) { | ||
| 1198 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); | ||
| 1199 | if ((filp->f_flags & O_NONBLOCK) || | ||
| 1200 | (filp->f_flags & O_NDELAY)) { | ||
| 1201 | err = -EWOULDBLOCK; | ||
| 1202 | goto out; | ||
| 1203 | } | ||
| 1204 | mutex_unlock(&cam->dev_mutex); | ||
| 1205 | err = wait_event_interruptible_exclusive(cam->open, | ||
| 1206 | cam->state & DEV_DISCONNECTED | ||
| 1207 | || !cam->users); | ||
| 1208 | if (err) { | ||
| 1209 | up_read(&et61x251_disconnect); | ||
| 1210 | return err; | ||
| 1211 | } | ||
| 1212 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1213 | up_read(&et61x251_disconnect); | ||
| 1214 | return -ENODEV; | ||
| 1215 | } | ||
| 1216 | mutex_lock(&cam->dev_mutex); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | |||
| 1220 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 1221 | err = et61x251_init(cam); | ||
| 1222 | if (err) { | ||
| 1223 | DBG(1, "Initialization failed again. " | ||
| 1224 | "I will retry on next open()."); | ||
| 1225 | goto out; | ||
| 1226 | } | ||
| 1227 | cam->state &= ~DEV_MISCONFIGURED; | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | if ((err = et61x251_start_transfer(cam))) | ||
| 1231 | goto out; | ||
| 1232 | |||
| 1233 | filp->private_data = cam; | ||
| 1234 | cam->users++; | ||
| 1235 | cam->io = IO_NONE; | ||
| 1236 | cam->stream = STREAM_OFF; | ||
| 1237 | cam->nbuffers = 0; | ||
| 1238 | cam->frame_count = 0; | ||
| 1239 | et61x251_empty_framequeues(cam); | ||
| 1240 | |||
| 1241 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); | ||
| 1242 | |||
| 1243 | out: | ||
| 1244 | mutex_unlock(&cam->dev_mutex); | ||
| 1245 | up_read(&et61x251_disconnect); | ||
| 1246 | return err; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | |||
| 1250 | static int et61x251_release(struct inode* inode, struct file* filp) | ||
| 1251 | { | ||
| 1252 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1253 | |||
| 1254 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ | ||
| 1255 | |||
| 1256 | et61x251_stop_transfer(cam); | ||
| 1257 | |||
| 1258 | et61x251_release_buffers(cam); | ||
| 1259 | |||
| 1260 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1261 | et61x251_release_resources(cam); | ||
| 1262 | mutex_unlock(&cam->dev_mutex); | ||
| 1263 | kfree(cam); | ||
| 1264 | return 0; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | cam->users--; | ||
| 1268 | wake_up_interruptible_nr(&cam->open, 1); | ||
| 1269 | |||
| 1270 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); | ||
| 1271 | |||
| 1272 | mutex_unlock(&cam->dev_mutex); | ||
| 1273 | |||
| 1274 | return 0; | ||
| 1275 | } | ||
| 1276 | |||
| 1277 | |||
| 1278 | static ssize_t | ||
| 1279 | et61x251_read(struct file* filp, char __user * buf, | ||
| 1280 | size_t count, loff_t* f_pos) | ||
| 1281 | { | ||
| 1282 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1283 | struct et61x251_frame_t* f, * i; | ||
| 1284 | unsigned long lock_flags; | ||
| 1285 | long timeout; | ||
| 1286 | int err = 0; | ||
| 1287 | |||
| 1288 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 1289 | return -ERESTARTSYS; | ||
| 1290 | |||
| 1291 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1292 | DBG(1, "Device not present"); | ||
| 1293 | mutex_unlock(&cam->fileop_mutex); | ||
| 1294 | return -ENODEV; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 1298 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 1299 | "again."); | ||
| 1300 | mutex_unlock(&cam->fileop_mutex); | ||
| 1301 | return -EIO; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | if (cam->io == IO_MMAP) { | ||
| 1305 | DBG(3, "Close and open the device again to choose the read " | ||
| 1306 | "method"); | ||
| 1307 | mutex_unlock(&cam->fileop_mutex); | ||
| 1308 | return -EINVAL; | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | if (cam->io == IO_NONE) { | ||
| 1312 | if (!et61x251_request_buffers(cam, cam->nreadbuffers, | ||
| 1313 | IO_READ)) { | ||
| 1314 | DBG(1, "read() failed, not enough memory"); | ||
| 1315 | mutex_unlock(&cam->fileop_mutex); | ||
| 1316 | return -ENOMEM; | ||
| 1317 | } | ||
| 1318 | cam->io = IO_READ; | ||
| 1319 | cam->stream = STREAM_ON; | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | if (list_empty(&cam->inqueue)) { | ||
| 1323 | if (!list_empty(&cam->outqueue)) | ||
| 1324 | et61x251_empty_framequeues(cam); | ||
| 1325 | et61x251_queue_unusedframes(cam); | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | if (!count) { | ||
| 1329 | mutex_unlock(&cam->fileop_mutex); | ||
| 1330 | return 0; | ||
| 1331 | } | ||
| 1332 | |||
| 1333 | if (list_empty(&cam->outqueue)) { | ||
| 1334 | if (filp->f_flags & O_NONBLOCK) { | ||
| 1335 | mutex_unlock(&cam->fileop_mutex); | ||
| 1336 | return -EAGAIN; | ||
| 1337 | } | ||
| 1338 | timeout = wait_event_interruptible_timeout | ||
| 1339 | ( cam->wait_frame, | ||
| 1340 | (!list_empty(&cam->outqueue)) || | ||
| 1341 | (cam->state & DEV_DISCONNECTED) || | ||
| 1342 | (cam->state & DEV_MISCONFIGURED), | ||
| 1343 | cam->module_param.frame_timeout * | ||
| 1344 | 1000 * msecs_to_jiffies(1) ); | ||
| 1345 | if (timeout < 0) { | ||
| 1346 | mutex_unlock(&cam->fileop_mutex); | ||
| 1347 | return timeout; | ||
| 1348 | } | ||
| 1349 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1350 | mutex_unlock(&cam->fileop_mutex); | ||
| 1351 | return -ENODEV; | ||
| 1352 | } | ||
| 1353 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) { | ||
| 1354 | mutex_unlock(&cam->fileop_mutex); | ||
| 1355 | return -EIO; | ||
| 1356 | } | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame); | ||
| 1360 | |||
| 1361 | if (count > f->buf.bytesused) | ||
| 1362 | count = f->buf.bytesused; | ||
| 1363 | |||
| 1364 | if (copy_to_user(buf, f->bufmem, count)) { | ||
| 1365 | err = -EFAULT; | ||
| 1366 | goto exit; | ||
| 1367 | } | ||
| 1368 | *f_pos += count; | ||
| 1369 | |||
| 1370 | exit: | ||
| 1371 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 1372 | list_for_each_entry(i, &cam->outqueue, frame) | ||
| 1373 | i->state = F_UNUSED; | ||
| 1374 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 1375 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 1376 | |||
| 1377 | et61x251_queue_unusedframes(cam); | ||
| 1378 | |||
| 1379 | PDBGG("Frame #%lu, bytes read: %zu", | ||
| 1380 | (unsigned long)f->buf.index, count); | ||
| 1381 | |||
| 1382 | mutex_unlock(&cam->fileop_mutex); | ||
| 1383 | |||
| 1384 | return err ? err : count; | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | |||
| 1388 | static unsigned int et61x251_poll(struct file *filp, poll_table *wait) | ||
| 1389 | { | ||
| 1390 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1391 | struct et61x251_frame_t* f; | ||
| 1392 | unsigned long lock_flags; | ||
| 1393 | unsigned int mask = 0; | ||
| 1394 | |||
| 1395 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 1396 | return POLLERR; | ||
| 1397 | |||
| 1398 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1399 | DBG(1, "Device not present"); | ||
| 1400 | goto error; | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 1404 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 1405 | "again."); | ||
| 1406 | goto error; | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | if (cam->io == IO_NONE) { | ||
| 1410 | if (!et61x251_request_buffers(cam, cam->nreadbuffers, | ||
| 1411 | IO_READ)) { | ||
| 1412 | DBG(1, "poll() failed, not enough memory"); | ||
| 1413 | goto error; | ||
| 1414 | } | ||
| 1415 | cam->io = IO_READ; | ||
| 1416 | cam->stream = STREAM_ON; | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | if (cam->io == IO_READ) { | ||
| 1420 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 1421 | list_for_each_entry(f, &cam->outqueue, frame) | ||
| 1422 | f->state = F_UNUSED; | ||
| 1423 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 1424 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 1425 | et61x251_queue_unusedframes(cam); | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | poll_wait(filp, &cam->wait_frame, wait); | ||
| 1429 | |||
| 1430 | if (!list_empty(&cam->outqueue)) | ||
| 1431 | mask |= POLLIN | POLLRDNORM; | ||
| 1432 | |||
| 1433 | mutex_unlock(&cam->fileop_mutex); | ||
| 1434 | |||
| 1435 | return mask; | ||
| 1436 | |||
| 1437 | error: | ||
| 1438 | mutex_unlock(&cam->fileop_mutex); | ||
| 1439 | return POLLERR; | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | |||
| 1443 | static void et61x251_vm_open(struct vm_area_struct* vma) | ||
| 1444 | { | ||
| 1445 | struct et61x251_frame_t* f = vma->vm_private_data; | ||
| 1446 | f->vma_use_count++; | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | |||
| 1450 | static void et61x251_vm_close(struct vm_area_struct* vma) | ||
| 1451 | { | ||
| 1452 | /* NOTE: buffers are not freed here */ | ||
| 1453 | struct et61x251_frame_t* f = vma->vm_private_data; | ||
| 1454 | f->vma_use_count--; | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | |||
| 1458 | static struct vm_operations_struct et61x251_vm_ops = { | ||
| 1459 | .open = et61x251_vm_open, | ||
| 1460 | .close = et61x251_vm_close, | ||
| 1461 | }; | ||
| 1462 | |||
| 1463 | |||
| 1464 | static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) | ||
| 1465 | { | ||
| 1466 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1467 | unsigned long size = vma->vm_end - vma->vm_start, | ||
| 1468 | start = vma->vm_start; | ||
| 1469 | void *pos; | ||
| 1470 | u32 i; | ||
| 1471 | |||
| 1472 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 1473 | return -ERESTARTSYS; | ||
| 1474 | |||
| 1475 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1476 | DBG(1, "Device not present"); | ||
| 1477 | mutex_unlock(&cam->fileop_mutex); | ||
| 1478 | return -ENODEV; | ||
| 1479 | } | ||
| 1480 | |||
| 1481 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 1482 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 1483 | "again."); | ||
| 1484 | mutex_unlock(&cam->fileop_mutex); | ||
| 1485 | return -EIO; | ||
| 1486 | } | ||
| 1487 | |||
| 1488 | if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | ||
| 1489 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | ||
| 1490 | mutex_unlock(&cam->fileop_mutex); | ||
| 1491 | return -EINVAL; | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | for (i = 0; i < cam->nbuffers; i++) { | ||
| 1495 | if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) | ||
| 1496 | break; | ||
| 1497 | } | ||
| 1498 | if (i == cam->nbuffers) { | ||
| 1499 | mutex_unlock(&cam->fileop_mutex); | ||
| 1500 | return -EINVAL; | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | vma->vm_flags |= VM_IO; | ||
| 1504 | vma->vm_flags |= VM_RESERVED; | ||
| 1505 | |||
| 1506 | pos = cam->frame[i].bufmem; | ||
| 1507 | while (size > 0) { /* size is page-aligned */ | ||
| 1508 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { | ||
| 1509 | mutex_unlock(&cam->fileop_mutex); | ||
| 1510 | return -EAGAIN; | ||
| 1511 | } | ||
| 1512 | start += PAGE_SIZE; | ||
| 1513 | pos += PAGE_SIZE; | ||
| 1514 | size -= PAGE_SIZE; | ||
| 1515 | } | ||
| 1516 | |||
| 1517 | vma->vm_ops = &et61x251_vm_ops; | ||
| 1518 | vma->vm_private_data = &cam->frame[i]; | ||
| 1519 | |||
| 1520 | et61x251_vm_open(vma); | ||
| 1521 | |||
| 1522 | mutex_unlock(&cam->fileop_mutex); | ||
| 1523 | |||
| 1524 | return 0; | ||
| 1525 | } | ||
| 1526 | |||
| 1527 | /*****************************************************************************/ | ||
| 1528 | |||
| 1529 | static int | ||
| 1530 | et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg) | ||
| 1531 | { | ||
| 1532 | struct v4l2_capability cap = { | ||
| 1533 | .driver = "et61x251", | ||
| 1534 | .version = ET61X251_MODULE_VERSION_CODE, | ||
| 1535 | .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
| 1536 | V4L2_CAP_STREAMING, | ||
| 1537 | }; | ||
| 1538 | |||
| 1539 | strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); | ||
| 1540 | if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) | ||
| 1541 | strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, | ||
| 1542 | sizeof(cap.bus_info)); | ||
| 1543 | |||
| 1544 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
| 1545 | return -EFAULT; | ||
| 1546 | |||
| 1547 | return 0; | ||
| 1548 | } | ||
| 1549 | |||
| 1550 | |||
| 1551 | static int | ||
| 1552 | et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg) | ||
| 1553 | { | ||
| 1554 | struct v4l2_input i; | ||
| 1555 | |||
| 1556 | if (copy_from_user(&i, arg, sizeof(i))) | ||
| 1557 | return -EFAULT; | ||
| 1558 | |||
| 1559 | if (i.index) | ||
| 1560 | return -EINVAL; | ||
| 1561 | |||
| 1562 | memset(&i, 0, sizeof(i)); | ||
| 1563 | strcpy(i.name, "Camera"); | ||
| 1564 | i.type = V4L2_INPUT_TYPE_CAMERA; | ||
| 1565 | |||
| 1566 | if (copy_to_user(arg, &i, sizeof(i))) | ||
| 1567 | return -EFAULT; | ||
| 1568 | |||
| 1569 | return 0; | ||
| 1570 | } | ||
| 1571 | |||
| 1572 | |||
| 1573 | static int | ||
| 1574 | et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg) | ||
| 1575 | { | ||
| 1576 | int index = 0; | ||
| 1577 | |||
| 1578 | if (copy_to_user(arg, &index, sizeof(index))) | ||
| 1579 | return -EFAULT; | ||
| 1580 | |||
| 1581 | return 0; | ||
| 1582 | } | ||
| 1583 | |||
| 1584 | |||
| 1585 | static int | ||
| 1586 | et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg) | ||
| 1587 | { | ||
| 1588 | int index; | ||
| 1589 | |||
| 1590 | if (copy_from_user(&index, arg, sizeof(index))) | ||
| 1591 | return -EFAULT; | ||
| 1592 | |||
| 1593 | if (index != 0) | ||
| 1594 | return -EINVAL; | ||
| 1595 | |||
| 1596 | return 0; | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | |||
| 1600 | static int | ||
| 1601 | et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg) | ||
| 1602 | { | ||
| 1603 | struct et61x251_sensor* s = &cam->sensor; | ||
| 1604 | struct v4l2_queryctrl qc; | ||
| 1605 | u8 i; | ||
| 1606 | |||
| 1607 | if (copy_from_user(&qc, arg, sizeof(qc))) | ||
| 1608 | return -EFAULT; | ||
| 1609 | |||
| 1610 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1611 | if (qc.id && qc.id == s->qctrl[i].id) { | ||
| 1612 | memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); | ||
| 1613 | if (copy_to_user(arg, &qc, sizeof(qc))) | ||
| 1614 | return -EFAULT; | ||
| 1615 | return 0; | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | return -EINVAL; | ||
| 1619 | } | ||
| 1620 | |||
| 1621 | |||
| 1622 | static int | ||
| 1623 | et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg) | ||
| 1624 | { | ||
| 1625 | struct et61x251_sensor* s = &cam->sensor; | ||
| 1626 | struct v4l2_control ctrl; | ||
| 1627 | int err = 0; | ||
| 1628 | u8 i; | ||
| 1629 | |||
| 1630 | if (!s->get_ctrl && !s->set_ctrl) | ||
| 1631 | return -EINVAL; | ||
| 1632 | |||
| 1633 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
| 1634 | return -EFAULT; | ||
| 1635 | |||
| 1636 | if (!s->get_ctrl) { | ||
| 1637 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1638 | if (ctrl.id == s->qctrl[i].id) { | ||
| 1639 | ctrl.value = s->_qctrl[i].default_value; | ||
| 1640 | goto exit; | ||
| 1641 | } | ||
| 1642 | return -EINVAL; | ||
| 1643 | } else | ||
| 1644 | err = s->get_ctrl(cam, &ctrl); | ||
| 1645 | |||
| 1646 | exit: | ||
| 1647 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) | ||
| 1648 | return -EFAULT; | ||
| 1649 | |||
| 1650 | return err; | ||
| 1651 | } | ||
| 1652 | |||
| 1653 | |||
| 1654 | static int | ||
| 1655 | et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) | ||
| 1656 | { | ||
| 1657 | struct et61x251_sensor* s = &cam->sensor; | ||
| 1658 | struct v4l2_control ctrl; | ||
| 1659 | u8 i; | ||
| 1660 | int err = 0; | ||
| 1661 | |||
| 1662 | if (!s->set_ctrl) | ||
| 1663 | return -EINVAL; | ||
| 1664 | |||
| 1665 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
| 1666 | return -EFAULT; | ||
| 1667 | |||
| 1668 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1669 | if (ctrl.id == s->qctrl[i].id) { | ||
| 1670 | if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) | ||
| 1671 | return -EINVAL; | ||
| 1672 | if (ctrl.value < s->qctrl[i].minimum || | ||
| 1673 | ctrl.value > s->qctrl[i].maximum) | ||
| 1674 | return -ERANGE; | ||
| 1675 | ctrl.value -= ctrl.value % s->qctrl[i].step; | ||
| 1676 | break; | ||
| 1677 | } | ||
| 1678 | |||
| 1679 | if ((err = s->set_ctrl(cam, &ctrl))) | ||
| 1680 | return err; | ||
| 1681 | |||
| 1682 | s->_qctrl[i].default_value = ctrl.value; | ||
| 1683 | |||
| 1684 | return 0; | ||
| 1685 | } | ||
| 1686 | |||
| 1687 | |||
| 1688 | static int | ||
| 1689 | et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg) | ||
| 1690 | { | ||
| 1691 | struct v4l2_cropcap* cc = &(cam->sensor.cropcap); | ||
| 1692 | |||
| 1693 | cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 1694 | cc->pixelaspect.numerator = 1; | ||
| 1695 | cc->pixelaspect.denominator = 1; | ||
| 1696 | |||
| 1697 | if (copy_to_user(arg, cc, sizeof(*cc))) | ||
| 1698 | return -EFAULT; | ||
| 1699 | |||
| 1700 | return 0; | ||
| 1701 | } | ||
| 1702 | |||
| 1703 | |||
| 1704 | static int | ||
| 1705 | et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg) | ||
| 1706 | { | ||
| 1707 | struct et61x251_sensor* s = &cam->sensor; | ||
| 1708 | struct v4l2_crop crop = { | ||
| 1709 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
| 1710 | }; | ||
| 1711 | |||
| 1712 | memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); | ||
| 1713 | |||
| 1714 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
| 1715 | return -EFAULT; | ||
| 1716 | |||
| 1717 | return 0; | ||
| 1718 | } | ||
| 1719 | |||
| 1720 | |||
| 1721 | static int | ||
| 1722 | et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) | ||
| 1723 | { | ||
| 1724 | struct et61x251_sensor* s = &cam->sensor; | ||
| 1725 | struct v4l2_crop crop; | ||
| 1726 | struct v4l2_rect* rect; | ||
| 1727 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
| 1728 | struct v4l2_pix_format* pix_format = &(s->pix_format); | ||
| 1729 | u8 scale; | ||
| 1730 | const enum et61x251_stream_state stream = cam->stream; | ||
| 1731 | const u32 nbuffers = cam->nbuffers; | ||
| 1732 | u32 i; | ||
| 1733 | int err = 0; | ||
| 1734 | |||
| 1735 | if (copy_from_user(&crop, arg, sizeof(crop))) | ||
| 1736 | return -EFAULT; | ||
| 1737 | |||
| 1738 | rect = &(crop.c); | ||
| 1739 | |||
| 1740 | if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1741 | return -EINVAL; | ||
| 1742 | |||
| 1743 | if (cam->module_param.force_munmap) | ||
| 1744 | for (i = 0; i < cam->nbuffers; i++) | ||
| 1745 | if (cam->frame[i].vma_use_count) { | ||
| 1746 | DBG(3, "VIDIOC_S_CROP failed. " | ||
| 1747 | "Unmap the buffers first."); | ||
| 1748 | return -EINVAL; | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | /* Preserve R,G or B origin */ | ||
| 1752 | rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; | ||
| 1753 | rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; | ||
| 1754 | |||
| 1755 | if (rect->width < 4) | ||
| 1756 | rect->width = 4; | ||
| 1757 | if (rect->height < 4) | ||
| 1758 | rect->height = 4; | ||
| 1759 | if (rect->width > bounds->width) | ||
| 1760 | rect->width = bounds->width; | ||
| 1761 | if (rect->height > bounds->height) | ||
| 1762 | rect->height = bounds->height; | ||
| 1763 | if (rect->left < bounds->left) | ||
| 1764 | rect->left = bounds->left; | ||
| 1765 | if (rect->top < bounds->top) | ||
| 1766 | rect->top = bounds->top; | ||
| 1767 | if (rect->left + rect->width > bounds->left + bounds->width) | ||
| 1768 | rect->left = bounds->left+bounds->width - rect->width; | ||
| 1769 | if (rect->top + rect->height > bounds->top + bounds->height) | ||
| 1770 | rect->top = bounds->top+bounds->height - rect->height; | ||
| 1771 | |||
| 1772 | rect->width &= ~3L; | ||
| 1773 | rect->height &= ~3L; | ||
| 1774 | |||
| 1775 | if (ET61X251_PRESERVE_IMGSCALE) { | ||
| 1776 | /* Calculate the actual scaling factor */ | ||
| 1777 | u32 a, b; | ||
| 1778 | a = rect->width * rect->height; | ||
| 1779 | b = pix_format->width * pix_format->height; | ||
| 1780 | scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; | ||
| 1781 | } else | ||
| 1782 | scale = 1; | ||
| 1783 | |||
| 1784 | if (cam->stream == STREAM_ON) | ||
| 1785 | if ((err = et61x251_stream_interrupt(cam))) | ||
| 1786 | return err; | ||
| 1787 | |||
| 1788 | if (copy_to_user(arg, &crop, sizeof(crop))) { | ||
| 1789 | cam->stream = stream; | ||
| 1790 | return -EFAULT; | ||
| 1791 | } | ||
| 1792 | |||
| 1793 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
| 1794 | et61x251_release_buffers(cam); | ||
| 1795 | |||
| 1796 | err = et61x251_set_crop(cam, rect); | ||
| 1797 | if (s->set_crop) | ||
| 1798 | err += s->set_crop(cam, rect); | ||
| 1799 | err += et61x251_set_scale(cam, scale); | ||
| 1800 | |||
| 1801 | if (err) { /* atomic, no rollback in ioctl() */ | ||
| 1802 | cam->state |= DEV_MISCONFIGURED; | ||
| 1803 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | ||
| 1804 | "use the camera, close and open /dev/video%d again.", | ||
| 1805 | cam->v4ldev->minor); | ||
| 1806 | return -EIO; | ||
| 1807 | } | ||
| 1808 | |||
| 1809 | s->pix_format.width = rect->width/scale; | ||
| 1810 | s->pix_format.height = rect->height/scale; | ||
| 1811 | memcpy(&(s->_rect), rect, sizeof(*rect)); | ||
| 1812 | |||
| 1813 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
| 1814 | nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { | ||
| 1815 | cam->state |= DEV_MISCONFIGURED; | ||
| 1816 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | ||
| 1817 | "use the camera, close and open /dev/video%d again.", | ||
| 1818 | cam->v4ldev->minor); | ||
| 1819 | return -ENOMEM; | ||
| 1820 | } | ||
| 1821 | |||
| 1822 | if (cam->io == IO_READ) | ||
| 1823 | et61x251_empty_framequeues(cam); | ||
| 1824 | else if (cam->module_param.force_munmap) | ||
| 1825 | et61x251_requeue_outqueue(cam); | ||
| 1826 | |||
| 1827 | cam->stream = stream; | ||
| 1828 | |||
| 1829 | return 0; | ||
| 1830 | } | ||
| 1831 | |||
| 1832 | |||
| 1833 | static int | ||
| 1834 | et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg) | ||
| 1835 | { | ||
| 1836 | struct v4l2_fmtdesc fmtd; | ||
| 1837 | |||
| 1838 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) | ||
| 1839 | return -EFAULT; | ||
| 1840 | |||
| 1841 | if (fmtd.index == 0) { | ||
| 1842 | strcpy(fmtd.description, "bayer rgb"); | ||
| 1843 | fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
| 1844 | } else if (fmtd.index == 1) { | ||
| 1845 | strcpy(fmtd.description, "compressed"); | ||
| 1846 | fmtd.pixelformat = V4L2_PIX_FMT_ET61X251; | ||
| 1847 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; | ||
| 1848 | } else | ||
| 1849 | return -EINVAL; | ||
| 1850 | |||
| 1851 | fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 1852 | memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); | ||
| 1853 | |||
| 1854 | if (copy_to_user(arg, &fmtd, sizeof(fmtd))) | ||
| 1855 | return -EFAULT; | ||
| 1856 | |||
| 1857 | return 0; | ||
| 1858 | } | ||
| 1859 | |||
| 1860 | |||
| 1861 | static int | ||
| 1862 | et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg) | ||
| 1863 | { | ||
| 1864 | struct v4l2_format format; | ||
| 1865 | struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); | ||
| 1866 | |||
| 1867 | if (copy_from_user(&format, arg, sizeof(format))) | ||
| 1868 | return -EFAULT; | ||
| 1869 | |||
| 1870 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1871 | return -EINVAL; | ||
| 1872 | |||
| 1873 | pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251) | ||
| 1874 | ? 0 : (pfmt->width * pfmt->priv) / 8; | ||
| 1875 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | ||
| 1876 | pfmt->field = V4L2_FIELD_NONE; | ||
| 1877 | memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); | ||
| 1878 | |||
| 1879 | if (copy_to_user(arg, &format, sizeof(format))) | ||
| 1880 | return -EFAULT; | ||
| 1881 | |||
| 1882 | return 0; | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | |||
| 1886 | static int | ||
| 1887 | et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, | ||
| 1888 | void __user * arg) | ||
| 1889 | { | ||
| 1890 | struct et61x251_sensor* s = &cam->sensor; | ||
| 1891 | struct v4l2_format format; | ||
| 1892 | struct v4l2_pix_format* pix; | ||
| 1893 | struct v4l2_pix_format* pfmt = &(s->pix_format); | ||
| 1894 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
| 1895 | struct v4l2_rect rect; | ||
| 1896 | u8 scale; | ||
| 1897 | const enum et61x251_stream_state stream = cam->stream; | ||
| 1898 | const u32 nbuffers = cam->nbuffers; | ||
| 1899 | u32 i; | ||
| 1900 | int err = 0; | ||
| 1901 | |||
| 1902 | if (copy_from_user(&format, arg, sizeof(format))) | ||
| 1903 | return -EFAULT; | ||
| 1904 | |||
| 1905 | pix = &(format.fmt.pix); | ||
| 1906 | |||
| 1907 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1908 | return -EINVAL; | ||
| 1909 | |||
| 1910 | memcpy(&rect, &(s->_rect), sizeof(rect)); | ||
| 1911 | |||
| 1912 | { /* calculate the actual scaling factor */ | ||
| 1913 | u32 a, b; | ||
| 1914 | a = rect.width * rect.height; | ||
| 1915 | b = pix->width * pix->height; | ||
| 1916 | scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; | ||
| 1917 | } | ||
| 1918 | |||
| 1919 | rect.width = scale * pix->width; | ||
| 1920 | rect.height = scale * pix->height; | ||
| 1921 | |||
| 1922 | if (rect.width < 4) | ||
| 1923 | rect.width = 4; | ||
| 1924 | if (rect.height < 4) | ||
| 1925 | rect.height = 4; | ||
| 1926 | if (rect.width > bounds->left + bounds->width - rect.left) | ||
| 1927 | rect.width = bounds->left + bounds->width - rect.left; | ||
| 1928 | if (rect.height > bounds->top + bounds->height - rect.top) | ||
| 1929 | rect.height = bounds->top + bounds->height - rect.top; | ||
| 1930 | |||
| 1931 | rect.width &= ~3L; | ||
| 1932 | rect.height &= ~3L; | ||
| 1933 | |||
| 1934 | { /* adjust the scaling factor */ | ||
| 1935 | u32 a, b; | ||
| 1936 | a = rect.width * rect.height; | ||
| 1937 | b = pix->width * pix->height; | ||
| 1938 | scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; | ||
| 1939 | } | ||
| 1940 | |||
| 1941 | pix->width = rect.width / scale; | ||
| 1942 | pix->height = rect.height / scale; | ||
| 1943 | |||
| 1944 | if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 && | ||
| 1945 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | ||
| 1946 | pix->pixelformat = pfmt->pixelformat; | ||
| 1947 | pix->priv = pfmt->priv; /* bpp */ | ||
| 1948 | pix->colorspace = pfmt->colorspace; | ||
| 1949 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) | ||
| 1950 | ? 0 : (pix->width * pix->priv) / 8; | ||
| 1951 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); | ||
| 1952 | pix->field = V4L2_FIELD_NONE; | ||
| 1953 | |||
| 1954 | if (cmd == VIDIOC_TRY_FMT) { | ||
| 1955 | if (copy_to_user(arg, &format, sizeof(format))) | ||
| 1956 | return -EFAULT; | ||
| 1957 | return 0; | ||
| 1958 | } | ||
| 1959 | |||
| 1960 | if (cam->module_param.force_munmap) | ||
| 1961 | for (i = 0; i < cam->nbuffers; i++) | ||
| 1962 | if (cam->frame[i].vma_use_count) { | ||
| 1963 | DBG(3, "VIDIOC_S_FMT failed. " | ||
| 1964 | "Unmap the buffers first."); | ||
| 1965 | return -EINVAL; | ||
| 1966 | } | ||
| 1967 | |||
| 1968 | if (cam->stream == STREAM_ON) | ||
| 1969 | if ((err = et61x251_stream_interrupt(cam))) | ||
| 1970 | return err; | ||
| 1971 | |||
| 1972 | if (copy_to_user(arg, &format, sizeof(format))) { | ||
| 1973 | cam->stream = stream; | ||
| 1974 | return -EFAULT; | ||
| 1975 | } | ||
| 1976 | |||
| 1977 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
| 1978 | et61x251_release_buffers(cam); | ||
| 1979 | |||
| 1980 | err += et61x251_set_pix_format(cam, pix); | ||
| 1981 | err += et61x251_set_crop(cam, &rect); | ||
| 1982 | if (s->set_pix_format) | ||
| 1983 | err += s->set_pix_format(cam, pix); | ||
| 1984 | if (s->set_crop) | ||
| 1985 | err += s->set_crop(cam, &rect); | ||
| 1986 | err += et61x251_set_scale(cam, scale); | ||
| 1987 | |||
| 1988 | if (err) { /* atomic, no rollback in ioctl() */ | ||
| 1989 | cam->state |= DEV_MISCONFIGURED; | ||
| 1990 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | ||
| 1991 | "use the camera, close and open /dev/video%d again.", | ||
| 1992 | cam->v4ldev->minor); | ||
| 1993 | return -EIO; | ||
| 1994 | } | ||
| 1995 | |||
| 1996 | memcpy(pfmt, pix, sizeof(*pix)); | ||
| 1997 | memcpy(&(s->_rect), &rect, sizeof(rect)); | ||
| 1998 | |||
| 1999 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
| 2000 | nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { | ||
| 2001 | cam->state |= DEV_MISCONFIGURED; | ||
| 2002 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | ||
| 2003 | "use the camera, close and open /dev/video%d again.", | ||
| 2004 | cam->v4ldev->minor); | ||
| 2005 | return -ENOMEM; | ||
| 2006 | } | ||
| 2007 | |||
| 2008 | if (cam->io == IO_READ) | ||
| 2009 | et61x251_empty_framequeues(cam); | ||
| 2010 | else if (cam->module_param.force_munmap) | ||
| 2011 | et61x251_requeue_outqueue(cam); | ||
| 2012 | |||
| 2013 | cam->stream = stream; | ||
| 2014 | |||
| 2015 | return 0; | ||
| 2016 | } | ||
| 2017 | |||
| 2018 | |||
| 2019 | static int | ||
| 2020 | et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg) | ||
| 2021 | { | ||
| 2022 | if (copy_to_user(arg, &cam->compression, | ||
| 2023 | sizeof(cam->compression))) | ||
| 2024 | return -EFAULT; | ||
| 2025 | |||
| 2026 | return 0; | ||
| 2027 | } | ||
| 2028 | |||
| 2029 | |||
| 2030 | static int | ||
| 2031 | et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg) | ||
| 2032 | { | ||
| 2033 | struct v4l2_jpegcompression jc; | ||
| 2034 | const enum et61x251_stream_state stream = cam->stream; | ||
| 2035 | int err = 0; | ||
| 2036 | |||
| 2037 | if (copy_from_user(&jc, arg, sizeof(jc))) | ||
| 2038 | return -EFAULT; | ||
| 2039 | |||
| 2040 | if (jc.quality != 0 && jc.quality != 1) | ||
| 2041 | return -EINVAL; | ||
| 2042 | |||
| 2043 | if (cam->stream == STREAM_ON) | ||
| 2044 | if ((err = et61x251_stream_interrupt(cam))) | ||
| 2045 | return err; | ||
| 2046 | |||
| 2047 | err += et61x251_set_compression(cam, &jc); | ||
| 2048 | if (err) { /* atomic, no rollback in ioctl() */ | ||
| 2049 | cam->state |= DEV_MISCONFIGURED; | ||
| 2050 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | ||
| 2051 | "problems. To use the camera, close and open " | ||
| 2052 | "/dev/video%d again.", cam->v4ldev->minor); | ||
| 2053 | return -EIO; | ||
| 2054 | } | ||
| 2055 | |||
| 2056 | cam->compression.quality = jc.quality; | ||
| 2057 | |||
| 2058 | cam->stream = stream; | ||
| 2059 | |||
| 2060 | return 0; | ||
| 2061 | } | ||
| 2062 | |||
| 2063 | |||
| 2064 | static int | ||
| 2065 | et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg) | ||
| 2066 | { | ||
| 2067 | struct v4l2_requestbuffers rb; | ||
| 2068 | u32 i; | ||
| 2069 | int err; | ||
| 2070 | |||
| 2071 | if (copy_from_user(&rb, arg, sizeof(rb))) | ||
| 2072 | return -EFAULT; | ||
| 2073 | |||
| 2074 | if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
| 2075 | rb.memory != V4L2_MEMORY_MMAP) | ||
| 2076 | return -EINVAL; | ||
| 2077 | |||
| 2078 | if (cam->io == IO_READ) { | ||
| 2079 | DBG(3, "Close and open the device again to choose the mmap " | ||
| 2080 | "I/O method"); | ||
| 2081 | return -EINVAL; | ||
| 2082 | } | ||
| 2083 | |||
| 2084 | for (i = 0; i < cam->nbuffers; i++) | ||
| 2085 | if (cam->frame[i].vma_use_count) { | ||
| 2086 | DBG(3, "VIDIOC_REQBUFS failed. " | ||
| 2087 | "Previous buffers are still mapped."); | ||
| 2088 | return -EINVAL; | ||
| 2089 | } | ||
| 2090 | |||
| 2091 | if (cam->stream == STREAM_ON) | ||
| 2092 | if ((err = et61x251_stream_interrupt(cam))) | ||
| 2093 | return err; | ||
| 2094 | |||
| 2095 | et61x251_empty_framequeues(cam); | ||
| 2096 | |||
| 2097 | et61x251_release_buffers(cam); | ||
| 2098 | if (rb.count) | ||
| 2099 | rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP); | ||
| 2100 | |||
| 2101 | if (copy_to_user(arg, &rb, sizeof(rb))) { | ||
| 2102 | et61x251_release_buffers(cam); | ||
| 2103 | cam->io = IO_NONE; | ||
| 2104 | return -EFAULT; | ||
| 2105 | } | ||
| 2106 | |||
| 2107 | cam->io = rb.count ? IO_MMAP : IO_NONE; | ||
| 2108 | |||
| 2109 | return 0; | ||
| 2110 | } | ||
| 2111 | |||
| 2112 | |||
| 2113 | static int | ||
| 2114 | et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg) | ||
| 2115 | { | ||
| 2116 | struct v4l2_buffer b; | ||
| 2117 | |||
| 2118 | if (copy_from_user(&b, arg, sizeof(b))) | ||
| 2119 | return -EFAULT; | ||
| 2120 | |||
| 2121 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
| 2122 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
| 2123 | return -EINVAL; | ||
| 2124 | |||
| 2125 | memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); | ||
| 2126 | |||
| 2127 | if (cam->frame[b.index].vma_use_count) | ||
| 2128 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
| 2129 | |||
| 2130 | if (cam->frame[b.index].state == F_DONE) | ||
| 2131 | b.flags |= V4L2_BUF_FLAG_DONE; | ||
| 2132 | else if (cam->frame[b.index].state != F_UNUSED) | ||
| 2133 | b.flags |= V4L2_BUF_FLAG_QUEUED; | ||
| 2134 | |||
| 2135 | if (copy_to_user(arg, &b, sizeof(b))) | ||
| 2136 | return -EFAULT; | ||
| 2137 | |||
| 2138 | return 0; | ||
| 2139 | } | ||
| 2140 | |||
| 2141 | |||
| 2142 | static int | ||
| 2143 | et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg) | ||
| 2144 | { | ||
| 2145 | struct v4l2_buffer b; | ||
| 2146 | unsigned long lock_flags; | ||
| 2147 | |||
| 2148 | if (copy_from_user(&b, arg, sizeof(b))) | ||
| 2149 | return -EFAULT; | ||
| 2150 | |||
| 2151 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
| 2152 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
| 2153 | return -EINVAL; | ||
| 2154 | |||
| 2155 | if (cam->frame[b.index].state != F_UNUSED) | ||
| 2156 | return -EINVAL; | ||
| 2157 | |||
| 2158 | cam->frame[b.index].state = F_QUEUED; | ||
| 2159 | |||
| 2160 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 2161 | list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); | ||
| 2162 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 2163 | |||
| 2164 | PDBGG("Frame #%lu queued", (unsigned long)b.index); | ||
| 2165 | |||
| 2166 | return 0; | ||
| 2167 | } | ||
| 2168 | |||
| 2169 | |||
| 2170 | static int | ||
| 2171 | et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp, | ||
| 2172 | void __user * arg) | ||
| 2173 | { | ||
| 2174 | struct v4l2_buffer b; | ||
| 2175 | struct et61x251_frame_t *f; | ||
| 2176 | unsigned long lock_flags; | ||
| 2177 | long timeout; | ||
| 2178 | |||
| 2179 | if (copy_from_user(&b, arg, sizeof(b))) | ||
| 2180 | return -EFAULT; | ||
| 2181 | |||
| 2182 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) | ||
| 2183 | return -EINVAL; | ||
| 2184 | |||
| 2185 | if (list_empty(&cam->outqueue)) { | ||
| 2186 | if (cam->stream == STREAM_OFF) | ||
| 2187 | return -EINVAL; | ||
| 2188 | if (filp->f_flags & O_NONBLOCK) | ||
| 2189 | return -EAGAIN; | ||
| 2190 | timeout = wait_event_interruptible_timeout | ||
| 2191 | ( cam->wait_frame, | ||
| 2192 | (!list_empty(&cam->outqueue)) || | ||
| 2193 | (cam->state & DEV_DISCONNECTED) || | ||
| 2194 | (cam->state & DEV_MISCONFIGURED), | ||
| 2195 | cam->module_param.frame_timeout * | ||
| 2196 | 1000 * msecs_to_jiffies(1) ); | ||
| 2197 | if (timeout < 0) | ||
| 2198 | return timeout; | ||
| 2199 | if (cam->state & DEV_DISCONNECTED) | ||
| 2200 | return -ENODEV; | ||
| 2201 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) | ||
| 2202 | return -EIO; | ||
| 2203 | } | ||
| 2204 | |||
| 2205 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 2206 | f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame); | ||
| 2207 | list_del(cam->outqueue.next); | ||
| 2208 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 2209 | |||
| 2210 | f->state = F_UNUSED; | ||
| 2211 | |||
| 2212 | memcpy(&b, &f->buf, sizeof(b)); | ||
| 2213 | if (f->vma_use_count) | ||
| 2214 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
| 2215 | |||
| 2216 | if (copy_to_user(arg, &b, sizeof(b))) | ||
| 2217 | return -EFAULT; | ||
| 2218 | |||
| 2219 | PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); | ||
| 2220 | |||
| 2221 | return 0; | ||
| 2222 | } | ||
| 2223 | |||
| 2224 | |||
| 2225 | static int | ||
| 2226 | et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg) | ||
| 2227 | { | ||
| 2228 | int type; | ||
| 2229 | |||
| 2230 | if (copy_from_user(&type, arg, sizeof(type))) | ||
| 2231 | return -EFAULT; | ||
| 2232 | |||
| 2233 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
| 2234 | return -EINVAL; | ||
| 2235 | |||
| 2236 | if (list_empty(&cam->inqueue)) | ||
| 2237 | return -EINVAL; | ||
| 2238 | |||
| 2239 | cam->stream = STREAM_ON; | ||
| 2240 | |||
| 2241 | DBG(3, "Stream on"); | ||
| 2242 | |||
| 2243 | return 0; | ||
| 2244 | } | ||
| 2245 | |||
| 2246 | |||
| 2247 | static int | ||
| 2248 | et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg) | ||
| 2249 | { | ||
| 2250 | int type, err; | ||
| 2251 | |||
| 2252 | if (copy_from_user(&type, arg, sizeof(type))) | ||
| 2253 | return -EFAULT; | ||
| 2254 | |||
| 2255 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
| 2256 | return -EINVAL; | ||
| 2257 | |||
| 2258 | if (cam->stream == STREAM_ON) | ||
| 2259 | if ((err = et61x251_stream_interrupt(cam))) | ||
| 2260 | return err; | ||
| 2261 | |||
| 2262 | et61x251_empty_framequeues(cam); | ||
| 2263 | |||
| 2264 | DBG(3, "Stream off"); | ||
| 2265 | |||
| 2266 | return 0; | ||
| 2267 | } | ||
| 2268 | |||
| 2269 | |||
| 2270 | static int | ||
| 2271 | et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg) | ||
| 2272 | { | ||
| 2273 | struct v4l2_streamparm sp; | ||
| 2274 | |||
| 2275 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
| 2276 | return -EFAULT; | ||
| 2277 | |||
| 2278 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 2279 | return -EINVAL; | ||
| 2280 | |||
| 2281 | sp.parm.capture.extendedmode = 0; | ||
| 2282 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
| 2283 | |||
| 2284 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
| 2285 | return -EFAULT; | ||
| 2286 | |||
| 2287 | return 0; | ||
| 2288 | } | ||
| 2289 | |||
| 2290 | |||
| 2291 | static int | ||
| 2292 | et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg) | ||
| 2293 | { | ||
| 2294 | struct v4l2_streamparm sp; | ||
| 2295 | |||
| 2296 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
| 2297 | return -EFAULT; | ||
| 2298 | |||
| 2299 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 2300 | return -EINVAL; | ||
| 2301 | |||
| 2302 | sp.parm.capture.extendedmode = 0; | ||
| 2303 | |||
| 2304 | if (sp.parm.capture.readbuffers == 0) | ||
| 2305 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
| 2306 | |||
| 2307 | if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES) | ||
| 2308 | sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES; | ||
| 2309 | |||
| 2310 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
| 2311 | return -EFAULT; | ||
| 2312 | |||
| 2313 | cam->nreadbuffers = sp.parm.capture.readbuffers; | ||
| 2314 | |||
| 2315 | return 0; | ||
| 2316 | } | ||
| 2317 | |||
| 2318 | |||
| 2319 | static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp, | ||
| 2320 | unsigned int cmd, void __user * arg) | ||
| 2321 | { | ||
| 2322 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 2323 | |||
| 2324 | switch (cmd) { | ||
| 2325 | |||
| 2326 | case VIDIOC_QUERYCAP: | ||
| 2327 | return et61x251_vidioc_querycap(cam, arg); | ||
| 2328 | |||
| 2329 | case VIDIOC_ENUMINPUT: | ||
| 2330 | return et61x251_vidioc_enuminput(cam, arg); | ||
| 2331 | |||
| 2332 | case VIDIOC_G_INPUT: | ||
| 2333 | return et61x251_vidioc_g_input(cam, arg); | ||
| 2334 | |||
| 2335 | case VIDIOC_S_INPUT: | ||
| 2336 | return et61x251_vidioc_s_input(cam, arg); | ||
| 2337 | |||
| 2338 | case VIDIOC_QUERYCTRL: | ||
| 2339 | return et61x251_vidioc_query_ctrl(cam, arg); | ||
| 2340 | |||
| 2341 | case VIDIOC_G_CTRL: | ||
| 2342 | return et61x251_vidioc_g_ctrl(cam, arg); | ||
| 2343 | |||
| 2344 | case VIDIOC_S_CTRL_OLD: | ||
| 2345 | case VIDIOC_S_CTRL: | ||
| 2346 | return et61x251_vidioc_s_ctrl(cam, arg); | ||
| 2347 | |||
| 2348 | case VIDIOC_CROPCAP_OLD: | ||
| 2349 | case VIDIOC_CROPCAP: | ||
| 2350 | return et61x251_vidioc_cropcap(cam, arg); | ||
| 2351 | |||
| 2352 | case VIDIOC_G_CROP: | ||
| 2353 | return et61x251_vidioc_g_crop(cam, arg); | ||
| 2354 | |||
| 2355 | case VIDIOC_S_CROP: | ||
| 2356 | return et61x251_vidioc_s_crop(cam, arg); | ||
| 2357 | |||
| 2358 | case VIDIOC_ENUM_FMT: | ||
| 2359 | return et61x251_vidioc_enum_fmt(cam, arg); | ||
| 2360 | |||
| 2361 | case VIDIOC_G_FMT: | ||
| 2362 | return et61x251_vidioc_g_fmt(cam, arg); | ||
| 2363 | |||
| 2364 | case VIDIOC_TRY_FMT: | ||
| 2365 | case VIDIOC_S_FMT: | ||
| 2366 | return et61x251_vidioc_try_s_fmt(cam, cmd, arg); | ||
| 2367 | |||
| 2368 | case VIDIOC_G_JPEGCOMP: | ||
| 2369 | return et61x251_vidioc_g_jpegcomp(cam, arg); | ||
| 2370 | |||
| 2371 | case VIDIOC_S_JPEGCOMP: | ||
| 2372 | return et61x251_vidioc_s_jpegcomp(cam, arg); | ||
| 2373 | |||
| 2374 | case VIDIOC_REQBUFS: | ||
| 2375 | return et61x251_vidioc_reqbufs(cam, arg); | ||
| 2376 | |||
| 2377 | case VIDIOC_QUERYBUF: | ||
| 2378 | return et61x251_vidioc_querybuf(cam, arg); | ||
| 2379 | |||
| 2380 | case VIDIOC_QBUF: | ||
| 2381 | return et61x251_vidioc_qbuf(cam, arg); | ||
| 2382 | |||
| 2383 | case VIDIOC_DQBUF: | ||
| 2384 | return et61x251_vidioc_dqbuf(cam, filp, arg); | ||
| 2385 | |||
| 2386 | case VIDIOC_STREAMON: | ||
| 2387 | return et61x251_vidioc_streamon(cam, arg); | ||
| 2388 | |||
| 2389 | case VIDIOC_STREAMOFF: | ||
| 2390 | return et61x251_vidioc_streamoff(cam, arg); | ||
| 2391 | |||
| 2392 | case VIDIOC_G_PARM: | ||
| 2393 | return et61x251_vidioc_g_parm(cam, arg); | ||
| 2394 | |||
| 2395 | case VIDIOC_S_PARM_OLD: | ||
| 2396 | case VIDIOC_S_PARM: | ||
| 2397 | return et61x251_vidioc_s_parm(cam, arg); | ||
| 2398 | |||
| 2399 | case VIDIOC_G_STD: | ||
| 2400 | case VIDIOC_S_STD: | ||
| 2401 | case VIDIOC_QUERYSTD: | ||
| 2402 | case VIDIOC_ENUMSTD: | ||
| 2403 | case VIDIOC_QUERYMENU: | ||
| 2404 | return -EINVAL; | ||
| 2405 | |||
| 2406 | default: | ||
| 2407 | return -EINVAL; | ||
| 2408 | |||
| 2409 | } | ||
| 2410 | } | ||
| 2411 | |||
| 2412 | |||
| 2413 | static int et61x251_ioctl(struct inode* inode, struct file* filp, | ||
| 2414 | unsigned int cmd, unsigned long arg) | ||
| 2415 | { | ||
| 2416 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 2417 | int err = 0; | ||
| 2418 | |||
| 2419 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 2420 | return -ERESTARTSYS; | ||
| 2421 | |||
| 2422 | if (cam->state & DEV_DISCONNECTED) { | ||
| 2423 | DBG(1, "Device not present"); | ||
| 2424 | mutex_unlock(&cam->fileop_mutex); | ||
| 2425 | return -ENODEV; | ||
| 2426 | } | ||
| 2427 | |||
| 2428 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 2429 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 2430 | "again."); | ||
| 2431 | mutex_unlock(&cam->fileop_mutex); | ||
| 2432 | return -EIO; | ||
| 2433 | } | ||
| 2434 | |||
| 2435 | V4LDBG(3, "et61x251", cmd); | ||
| 2436 | |||
| 2437 | err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); | ||
| 2438 | |||
| 2439 | mutex_unlock(&cam->fileop_mutex); | ||
| 2440 | |||
| 2441 | return err; | ||
| 2442 | } | ||
| 2443 | |||
| 2444 | |||
| 2445 | static struct file_operations et61x251_fops = { | ||
| 2446 | .owner = THIS_MODULE, | ||
| 2447 | .open = et61x251_open, | ||
| 2448 | .release = et61x251_release, | ||
| 2449 | .ioctl = et61x251_ioctl, | ||
| 2450 | .read = et61x251_read, | ||
| 2451 | .poll = et61x251_poll, | ||
| 2452 | .mmap = et61x251_mmap, | ||
| 2453 | .llseek = no_llseek, | ||
| 2454 | }; | ||
| 2455 | |||
| 2456 | /*****************************************************************************/ | ||
| 2457 | |||
| 2458 | /* It exists a single interface only. We do not need to validate anything. */ | ||
| 2459 | static int | ||
| 2460 | et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
| 2461 | { | ||
| 2462 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 2463 | struct et61x251_device* cam; | ||
| 2464 | static unsigned int dev_nr = 0; | ||
| 2465 | unsigned int i; | ||
| 2466 | int err = 0; | ||
| 2467 | |||
| 2468 | if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL))) | ||
| 2469 | return -ENOMEM; | ||
| 2470 | |||
| 2471 | cam->usbdev = udev; | ||
| 2472 | |||
| 2473 | if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { | ||
| 2474 | DBG(1, "kmalloc() failed"); | ||
| 2475 | err = -ENOMEM; | ||
| 2476 | goto fail; | ||
| 2477 | } | ||
| 2478 | |||
| 2479 | if (!(cam->v4ldev = video_device_alloc())) { | ||
| 2480 | DBG(1, "video_device_alloc() failed"); | ||
| 2481 | err = -ENOMEM; | ||
| 2482 | goto fail; | ||
| 2483 | } | ||
| 2484 | |||
| 2485 | mutex_init(&cam->dev_mutex); | ||
| 2486 | |||
| 2487 | DBG(2, "ET61X[12]51 PC Camera Controller detected " | ||
| 2488 | "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct); | ||
| 2489 | |||
| 2490 | for (i = 0; et61x251_sensor_table[i]; i++) { | ||
| 2491 | err = et61x251_sensor_table[i](cam); | ||
| 2492 | if (!err) | ||
| 2493 | break; | ||
| 2494 | } | ||
| 2495 | |||
| 2496 | if (!err) | ||
| 2497 | DBG(2, "%s image sensor detected", cam->sensor.name); | ||
| 2498 | else { | ||
| 2499 | DBG(1, "No supported image sensor detected"); | ||
| 2500 | err = -ENODEV; | ||
| 2501 | goto fail; | ||
| 2502 | } | ||
| 2503 | |||
| 2504 | if (et61x251_init(cam)) { | ||
| 2505 | DBG(1, "Initialization failed. I will retry on open()."); | ||
| 2506 | cam->state |= DEV_MISCONFIGURED; | ||
| 2507 | } | ||
| 2508 | |||
| 2509 | strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); | ||
| 2510 | cam->v4ldev->owner = THIS_MODULE; | ||
| 2511 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
| 2512 | cam->v4ldev->hardware = 0; | ||
| 2513 | cam->v4ldev->fops = &et61x251_fops; | ||
| 2514 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
| 2515 | cam->v4ldev->release = video_device_release; | ||
| 2516 | video_set_drvdata(cam->v4ldev, cam); | ||
| 2517 | |||
| 2518 | mutex_lock(&cam->dev_mutex); | ||
| 2519 | |||
| 2520 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
| 2521 | video_nr[dev_nr]); | ||
| 2522 | if (err) { | ||
| 2523 | DBG(1, "V4L2 device registration failed"); | ||
| 2524 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
| 2525 | DBG(1, "Free /dev/videoX node not found"); | ||
| 2526 | video_nr[dev_nr] = -1; | ||
| 2527 | dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
| 2528 | mutex_unlock(&cam->dev_mutex); | ||
| 2529 | goto fail; | ||
| 2530 | } | ||
| 2531 | |||
| 2532 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); | ||
| 2533 | |||
| 2534 | cam->module_param.force_munmap = force_munmap[dev_nr]; | ||
| 2535 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; | ||
| 2536 | |||
| 2537 | dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
| 2538 | |||
| 2539 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
| 2540 | et61x251_create_sysfs(cam); | ||
| 2541 | DBG(2, "Optional device control through 'sysfs' interface ready"); | ||
| 2542 | #endif | ||
| 2543 | |||
| 2544 | usb_set_intfdata(intf, cam); | ||
| 2545 | |||
| 2546 | mutex_unlock(&cam->dev_mutex); | ||
| 2547 | |||
| 2548 | return 0; | ||
| 2549 | |||
| 2550 | fail: | ||
| 2551 | if (cam) { | ||
| 2552 | kfree(cam->control_buffer); | ||
| 2553 | if (cam->v4ldev) | ||
| 2554 | video_device_release(cam->v4ldev); | ||
| 2555 | kfree(cam); | ||
| 2556 | } | ||
| 2557 | return err; | ||
| 2558 | } | ||
| 2559 | |||
| 2560 | |||
| 2561 | static void et61x251_usb_disconnect(struct usb_interface* intf) | ||
| 2562 | { | ||
| 2563 | struct et61x251_device* cam = usb_get_intfdata(intf); | ||
| 2564 | |||
| 2565 | if (!cam) | ||
| 2566 | return; | ||
| 2567 | |||
| 2568 | down_write(&et61x251_disconnect); | ||
| 2569 | |||
| 2570 | mutex_lock(&cam->dev_mutex); | ||
| 2571 | |||
| 2572 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | ||
| 2573 | |||
| 2574 | wake_up_interruptible_all(&cam->open); | ||
| 2575 | |||
| 2576 | if (cam->users) { | ||
| 2577 | DBG(2, "Device /dev/video%d is open! Deregistration and " | ||
| 2578 | "memory deallocation are deferred on close.", | ||
| 2579 | cam->v4ldev->minor); | ||
| 2580 | cam->state |= DEV_MISCONFIGURED; | ||
| 2581 | et61x251_stop_transfer(cam); | ||
| 2582 | cam->state |= DEV_DISCONNECTED; | ||
| 2583 | wake_up_interruptible(&cam->wait_frame); | ||
| 2584 | wake_up(&cam->wait_stream); | ||
| 2585 | usb_get_dev(cam->usbdev); | ||
| 2586 | } else { | ||
| 2587 | cam->state |= DEV_DISCONNECTED; | ||
| 2588 | et61x251_release_resources(cam); | ||
| 2589 | } | ||
| 2590 | |||
| 2591 | mutex_unlock(&cam->dev_mutex); | ||
| 2592 | |||
| 2593 | if (!cam->users) | ||
| 2594 | kfree(cam); | ||
| 2595 | |||
| 2596 | up_write(&et61x251_disconnect); | ||
| 2597 | } | ||
| 2598 | |||
| 2599 | |||
| 2600 | static struct usb_driver et61x251_usb_driver = { | ||
| 2601 | .name = "et61x251", | ||
| 2602 | .id_table = et61x251_id_table, | ||
| 2603 | .probe = et61x251_usb_probe, | ||
| 2604 | .disconnect = et61x251_usb_disconnect, | ||
| 2605 | }; | ||
| 2606 | |||
| 2607 | /*****************************************************************************/ | ||
| 2608 | |||
| 2609 | static int __init et61x251_module_init(void) | ||
| 2610 | { | ||
| 2611 | int err = 0; | ||
| 2612 | |||
| 2613 | KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION); | ||
| 2614 | KDBG(3, ET61X251_MODULE_AUTHOR); | ||
| 2615 | |||
| 2616 | if ((err = usb_register(&et61x251_usb_driver))) | ||
| 2617 | KDBG(1, "usb_register() failed"); | ||
| 2618 | |||
| 2619 | return err; | ||
| 2620 | } | ||
| 2621 | |||
| 2622 | |||
| 2623 | static void __exit et61x251_module_exit(void) | ||
| 2624 | { | ||
| 2625 | usb_deregister(&et61x251_usb_driver); | ||
| 2626 | } | ||
| 2627 | |||
| 2628 | |||
| 2629 | module_init(et61x251_module_init); | ||
| 2630 | module_exit(et61x251_module_exit); | ||
diff --git a/drivers/usb/media/et61x251_sensor.h b/drivers/usb/media/et61x251_sensor.h deleted file mode 100644 index 56841ae8a207..000000000000 --- a/drivers/usb/media/et61x251_sensor.h +++ /dev/null | |||
| @@ -1,116 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * API for image sensors connected to ET61X[12]51 PC Camera Controllers * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2006 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 _ET61X251_SENSOR_H_ | ||
| 22 | #define _ET61X251_SENSOR_H_ | ||
| 23 | |||
| 24 | #include <linux/usb.h> | ||
| 25 | #include <linux/videodev.h> | ||
| 26 | #include <linux/device.h> | ||
| 27 | #include <linux/stddef.h> | ||
| 28 | #include <linux/errno.h> | ||
| 29 | #include <asm/types.h> | ||
| 30 | |||
| 31 | struct et61x251_device; | ||
| 32 | struct et61x251_sensor; | ||
| 33 | |||
| 34 | /*****************************************************************************/ | ||
| 35 | |||
| 36 | extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam); | ||
| 37 | |||
| 38 | #define ET61X251_SENSOR_TABLE \ | ||
| 39 | /* Weak detections must go at the end of the list */ \ | ||
| 40 | static int (*et61x251_sensor_table[])(struct et61x251_device*) = { \ | ||
| 41 | &et61x251_probe_tas5130d1b, \ | ||
| 42 | NULL, \ | ||
| 43 | }; | ||
| 44 | |||
| 45 | extern struct et61x251_device* | ||
| 46 | et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id); | ||
| 47 | |||
| 48 | extern void | ||
| 49 | et61x251_attach_sensor(struct et61x251_device* cam, | ||
| 50 | struct et61x251_sensor* sensor); | ||
| 51 | |||
| 52 | /*****************************************************************************/ | ||
| 53 | |||
| 54 | extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index); | ||
| 55 | extern int et61x251_read_reg(struct et61x251_device*, u16 index); | ||
| 56 | extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value); | ||
| 57 | extern int et61x251_i2c_read(struct et61x251_device*, u8 address); | ||
| 58 | extern int et61x251_i2c_try_write(struct et61x251_device*, | ||
| 59 | struct et61x251_sensor*, u8 address, | ||
| 60 | u8 value); | ||
| 61 | extern int et61x251_i2c_try_read(struct et61x251_device*, | ||
| 62 | struct et61x251_sensor*, u8 address); | ||
| 63 | extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1, | ||
| 64 | u8 data2, u8 data3, u8 data4, u8 data5, | ||
| 65 | u8 data6, u8 data7, u8 data8, u8 address); | ||
| 66 | |||
| 67 | /*****************************************************************************/ | ||
| 68 | |||
| 69 | enum et61x251_i2c_sysfs_ops { | ||
| 70 | ET61X251_I2C_READ = 0x01, | ||
| 71 | ET61X251_I2C_WRITE = 0x02, | ||
| 72 | }; | ||
| 73 | |||
| 74 | enum et61x251_i2c_interface { | ||
| 75 | ET61X251_I2C_2WIRES, | ||
| 76 | ET61X251_I2C_3WIRES, | ||
| 77 | }; | ||
| 78 | |||
| 79 | /* Repeat start condition when RSTA is high */ | ||
| 80 | enum et61x251_i2c_rsta { | ||
| 81 | ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */ | ||
| 82 | ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */ | ||
| 83 | }; | ||
| 84 | |||
| 85 | #define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 | ||
| 86 | |||
| 87 | struct et61x251_sensor { | ||
| 88 | char name[32]; | ||
| 89 | |||
| 90 | enum et61x251_i2c_sysfs_ops sysfs_ops; | ||
| 91 | |||
| 92 | enum et61x251_i2c_interface interface; | ||
| 93 | u8 i2c_slave_id; | ||
| 94 | enum et61x251_i2c_rsta rsta; | ||
| 95 | struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */ | ||
| 96 | |||
| 97 | struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS]; | ||
| 98 | struct v4l2_cropcap cropcap; | ||
| 99 | struct v4l2_pix_format pix_format; | ||
| 100 | |||
| 101 | int (*init)(struct et61x251_device* cam); | ||
| 102 | int (*get_ctrl)(struct et61x251_device* cam, | ||
| 103 | struct v4l2_control* ctrl); | ||
| 104 | int (*set_ctrl)(struct et61x251_device* cam, | ||
| 105 | const struct v4l2_control* ctrl); | ||
| 106 | int (*set_crop)(struct et61x251_device* cam, | ||
| 107 | const struct v4l2_rect* rect); | ||
| 108 | int (*set_pix_format)(struct et61x251_device* cam, | ||
| 109 | const struct v4l2_pix_format* pix); | ||
| 110 | |||
| 111 | /* Private */ | ||
| 112 | struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS]; | ||
| 113 | struct v4l2_rect _rect; | ||
| 114 | }; | ||
| 115 | |||
| 116 | #endif /* _ET61X251_SENSOR_H_ */ | ||
diff --git a/drivers/usb/media/et61x251_tas5130d1b.c b/drivers/usb/media/et61x251_tas5130d1b.c deleted file mode 100644 index 3998d76a307a..000000000000 --- a/drivers/usb/media/et61x251_tas5130d1b.c +++ /dev/null | |||
| @@ -1,141 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51 * | ||
| 3 | * PC Camera 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 "et61x251_sensor.h" | ||
| 23 | |||
| 24 | |||
| 25 | static int tas5130d1b_init(struct et61x251_device* cam) | ||
| 26 | { | ||
| 27 | int err = 0; | ||
| 28 | |||
| 29 | err += et61x251_write_reg(cam, 0x14, 0x01); | ||
| 30 | err += et61x251_write_reg(cam, 0x1b, 0x02); | ||
| 31 | err += et61x251_write_reg(cam, 0x02, 0x12); | ||
| 32 | err += et61x251_write_reg(cam, 0x0e, 0x60); | ||
| 33 | err += et61x251_write_reg(cam, 0x80, 0x61); | ||
| 34 | err += et61x251_write_reg(cam, 0xf0, 0x62); | ||
| 35 | err += et61x251_write_reg(cam, 0x03, 0x63); | ||
| 36 | err += et61x251_write_reg(cam, 0x14, 0x64); | ||
| 37 | err += et61x251_write_reg(cam, 0xf4, 0x65); | ||
| 38 | err += et61x251_write_reg(cam, 0x01, 0x66); | ||
| 39 | err += et61x251_write_reg(cam, 0x05, 0x67); | ||
| 40 | err += et61x251_write_reg(cam, 0x8f, 0x68); | ||
| 41 | err += et61x251_write_reg(cam, 0x0f, 0x8d); | ||
| 42 | err += et61x251_write_reg(cam, 0x08, 0x8e); | ||
| 43 | |||
| 44 | return err; | ||
| 45 | } | ||
| 46 | |||
| 47 | |||
| 48 | static int tas5130d1b_set_ctrl(struct et61x251_device* cam, | ||
| 49 | const struct v4l2_control* ctrl) | ||
| 50 | { | ||
| 51 | int err = 0; | ||
| 52 | |||
| 53 | switch (ctrl->id) { | ||
| 54 | case V4L2_CID_GAIN: | ||
| 55 | err += et61x251_i2c_raw_write(cam, 2, 0x20, | ||
| 56 | 0xf6-ctrl->value, 0, 0, 0, | ||
| 57 | 0, 0, 0, 0); | ||
| 58 | break; | ||
| 59 | case V4L2_CID_EXPOSURE: | ||
| 60 | err += et61x251_i2c_raw_write(cam, 2, 0x40, | ||
| 61 | 0x47-ctrl->value, 0, 0, 0, | ||
| 62 | 0, 0, 0, 0); | ||
| 63 | break; | ||
| 64 | default: | ||
| 65 | return -EINVAL; | ||
| 66 | } | ||
| 67 | |||
| 68 | return err ? -EIO : 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | |||
| 72 | static struct et61x251_sensor tas5130d1b = { | ||
| 73 | .name = "TAS5130D1B", | ||
| 74 | .interface = ET61X251_I2C_3WIRES, | ||
| 75 | .rsta = ET61X251_I2C_RSTA_STOP, | ||
| 76 | .active_pixel = { | ||
| 77 | .left = 106, | ||
| 78 | .top = 13, | ||
| 79 | }, | ||
| 80 | .init = &tas5130d1b_init, | ||
| 81 | .qctrl = { | ||
| 82 | { | ||
| 83 | .id = V4L2_CID_GAIN, | ||
| 84 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 85 | .name = "global gain", | ||
| 86 | .minimum = 0x00, | ||
| 87 | .maximum = 0xf6, | ||
| 88 | .step = 0x02, | ||
| 89 | .default_value = 0x0d, | ||
| 90 | .flags = 0, | ||
| 91 | }, | ||
| 92 | { | ||
| 93 | .id = V4L2_CID_EXPOSURE, | ||
| 94 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 95 | .name = "exposure", | ||
| 96 | .minimum = 0x00, | ||
| 97 | .maximum = 0x47, | ||
| 98 | .step = 0x01, | ||
| 99 | .default_value = 0x23, | ||
| 100 | .flags = 0, | ||
| 101 | }, | ||
| 102 | }, | ||
| 103 | .set_ctrl = &tas5130d1b_set_ctrl, | ||
| 104 | .cropcap = { | ||
| 105 | .bounds = { | ||
| 106 | .left = 0, | ||
| 107 | .top = 0, | ||
| 108 | .width = 640, | ||
| 109 | .height = 480, | ||
| 110 | }, | ||
| 111 | .defrect = { | ||
| 112 | .left = 0, | ||
| 113 | .top = 0, | ||
| 114 | .width = 640, | ||
| 115 | .height = 480, | ||
| 116 | }, | ||
| 117 | }, | ||
| 118 | .pix_format = { | ||
| 119 | .width = 640, | ||
| 120 | .height = 480, | ||
| 121 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
| 122 | .priv = 8, | ||
| 123 | }, | ||
| 124 | }; | ||
| 125 | |||
| 126 | |||
| 127 | int et61x251_probe_tas5130d1b(struct et61x251_device* cam) | ||
| 128 | { | ||
| 129 | const struct usb_device_id tas5130d1b_id_table[] = { | ||
| 130 | { USB_DEVICE(0x102c, 0x6251), }, | ||
| 131 | { } | ||
| 132 | }; | ||
| 133 | |||
| 134 | /* Sensor detection is based on USB pid/vid */ | ||
| 135 | if (!et61x251_match_id(cam, tas5130d1b_id_table)) | ||
| 136 | return -ENODEV; | ||
| 137 | |||
| 138 | et61x251_attach_sensor(cam, &tas5130d1b); | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
diff --git a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c deleted file mode 100644 index a42c22294124..000000000000 --- a/drivers/usb/media/ibmcam.c +++ /dev/null | |||
| @@ -1,3932 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * USB IBM C-It Video Camera driver | ||
| 3 | * | ||
| 4 | * Supports Xirlink C-It Video Camera, IBM PC Camera, | ||
| 5 | * IBM NetCamera and Veo Stingray. | ||
| 6 | * | ||
| 7 | * This driver is based on earlier work of: | ||
| 8 | * | ||
| 9 | * (C) Copyright 1999 Johannes Erdfelt | ||
| 10 | * (C) Copyright 1999 Randy Dunlap | ||
| 11 | * | ||
| 12 | * 5/24/00 Removed optional (and unnecessary) locking of the driver while | ||
| 13 | * the device remains plugged in. Corrected race conditions in ibmcam_open | ||
| 14 | * and ibmcam_probe() routines using this as a guideline: | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/sched.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | |||
| 22 | #include "usbvideo.h" | ||
| 23 | |||
| 24 | #define IBMCAM_VENDOR_ID 0x0545 | ||
| 25 | #define IBMCAM_PRODUCT_ID 0x8080 | ||
| 26 | #define NETCAM_PRODUCT_ID 0x8002 /* IBM NetCamera, close to model 2 */ | ||
| 27 | #define VEO_800C_PRODUCT_ID 0x800C /* Veo Stingray, repackaged Model 2 */ | ||
| 28 | #define VEO_800D_PRODUCT_ID 0x800D /* Veo Stingray, repackaged Model 4 */ | ||
| 29 | |||
| 30 | #define MAX_IBMCAM 4 /* How many devices we allow to connect */ | ||
| 31 | #define USES_IBMCAM_PUTPIXEL 0 /* 0=Fast/oops 1=Slow/secure */ | ||
| 32 | |||
| 33 | /* Header signatures */ | ||
| 34 | |||
| 35 | /* Model 1 header: 00 FF 00 xx */ | ||
| 36 | #define HDRSIG_MODEL1_128x96 0x06 /* U Y V Y ... */ | ||
| 37 | #define HDRSIG_MODEL1_176x144 0x0e /* U Y V Y ... */ | ||
| 38 | #define HDRSIG_MODEL1_352x288 0x00 /* V Y U Y ... */ | ||
| 39 | |||
| 40 | #define IBMCAM_MODEL_1 1 /* XVP-501, 3 interfaces, rev. 0.02 */ | ||
| 41 | #define IBMCAM_MODEL_2 2 /* KSX-X9903, 2 interfaces, rev. 3.0a */ | ||
| 42 | #define IBMCAM_MODEL_3 3 /* KSX-X9902, 2 interfaces, rev. 3.01 */ | ||
| 43 | #define IBMCAM_MODEL_4 4 /* IBM NetCamera, 0545/8002/3.0a */ | ||
| 44 | |||
| 45 | /* Video sizes supported */ | ||
| 46 | #define VIDEOSIZE_128x96 VIDEOSIZE(128, 96) | ||
| 47 | #define VIDEOSIZE_176x144 VIDEOSIZE(176,144) | ||
| 48 | #define VIDEOSIZE_352x288 VIDEOSIZE(352,288) | ||
| 49 | #define VIDEOSIZE_320x240 VIDEOSIZE(320,240) | ||
| 50 | #define VIDEOSIZE_352x240 VIDEOSIZE(352,240) | ||
| 51 | #define VIDEOSIZE_640x480 VIDEOSIZE(640,480) | ||
| 52 | #define VIDEOSIZE_160x120 VIDEOSIZE(160,120) | ||
| 53 | |||
| 54 | /* Video sizes supported */ | ||
| 55 | enum { | ||
| 56 | SIZE_128x96 = 0, | ||
| 57 | SIZE_160x120, | ||
| 58 | SIZE_176x144, | ||
| 59 | SIZE_320x240, | ||
| 60 | SIZE_352x240, | ||
| 61 | SIZE_352x288, | ||
| 62 | SIZE_640x480, | ||
| 63 | /* Add/remove/rearrange items before this line */ | ||
| 64 | SIZE_LastItem | ||
| 65 | }; | ||
| 66 | |||
| 67 | /* | ||
| 68 | * This structure lives in uvd->user field. | ||
| 69 | */ | ||
| 70 | typedef struct { | ||
| 71 | int initialized; /* Had we already sent init sequence? */ | ||
| 72 | int camera_model; /* What type of IBM camera we got? */ | ||
| 73 | int has_hdr; | ||
| 74 | } ibmcam_t; | ||
| 75 | #define IBMCAM_T(uvd) ((ibmcam_t *)((uvd)->user_data)) | ||
| 76 | |||
| 77 | static struct usbvideo *cams; | ||
| 78 | |||
| 79 | static int debug; | ||
| 80 | |||
| 81 | static int flags; /* = FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ | ||
| 82 | |||
| 83 | static const int min_canvasWidth = 8; | ||
| 84 | static const int min_canvasHeight = 4; | ||
| 85 | |||
| 86 | static int lighting = 1; /* Medium */ | ||
| 87 | |||
| 88 | #define SHARPNESS_MIN 0 | ||
| 89 | #define SHARPNESS_MAX 6 | ||
| 90 | static int sharpness = 4; /* Low noise, good details */ | ||
| 91 | |||
| 92 | #define FRAMERATE_MIN 0 | ||
| 93 | #define FRAMERATE_MAX 6 | ||
| 94 | static int framerate = -1; | ||
| 95 | |||
| 96 | static int size = SIZE_352x288; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Here we define several initialization variables. They may | ||
| 100 | * be used to automatically set color, hue, brightness and | ||
| 101 | * contrast to desired values. This is particularly useful in | ||
| 102 | * case of webcams (which have no controls and no on-screen | ||
| 103 | * output) and also when a client V4L software is used that | ||
| 104 | * does not have some of those controls. In any case it's | ||
| 105 | * good to have startup values as options. | ||
| 106 | * | ||
| 107 | * These values are all in [0..255] range. This simplifies | ||
| 108 | * operation. Note that actual values of V4L variables may | ||
| 109 | * be scaled up (as much as << 8). User can see that only | ||
| 110 | * on overlay output, however, or through a V4L client. | ||
| 111 | */ | ||
| 112 | static int init_brightness = 128; | ||
| 113 | static int init_contrast = 192; | ||
| 114 | static int init_color = 128; | ||
| 115 | static int init_hue = 128; | ||
| 116 | static int hue_correction = 128; | ||
| 117 | |||
| 118 | /* Settings for camera model 2 */ | ||
| 119 | static int init_model2_rg2 = -1; | ||
| 120 | static int init_model2_sat = -1; | ||
| 121 | static int init_model2_yb = -1; | ||
| 122 | |||
| 123 | /* 01.01.08 - Added for RCA video in support -LO */ | ||
| 124 | /* Settings for camera model 3 */ | ||
| 125 | static int init_model3_input = 0; | ||
| 126 | |||
| 127 | module_param(debug, int, 0); | ||
| 128 | MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); | ||
| 129 | module_param(flags, int, 0); | ||
| 130 | MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames"); | ||
| 131 | module_param(framerate, int, 0); | ||
| 132 | MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); | ||
| 133 | module_param(lighting, int, 0); | ||
| 134 | MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light"); | ||
| 135 | module_param(sharpness, int, 0); | ||
| 136 | MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)"); | ||
| 137 | module_param(size, int, 0); | ||
| 138 | MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)"); | ||
| 139 | module_param(init_brightness, int, 0); | ||
| 140 | MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); | ||
| 141 | module_param(init_contrast, int, 0); | ||
| 142 | MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); | ||
| 143 | module_param(init_color, int, 0); | ||
| 144 | MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); | ||
| 145 | module_param(init_hue, int, 0); | ||
| 146 | MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); | ||
| 147 | module_param(hue_correction, int, 0); | ||
| 148 | MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); | ||
| 149 | |||
| 150 | module_param(init_model2_rg2, int, 0); | ||
| 151 | MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)"); | ||
| 152 | module_param(init_model2_sat, int, 0); | ||
| 153 | MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)"); | ||
| 154 | module_param(init_model2_yb, int, 0); | ||
| 155 | MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)"); | ||
| 156 | |||
| 157 | /* 01.01.08 - Added for RCA video in support -LO */ | ||
| 158 | module_param(init_model3_input, int, 0); | ||
| 159 | MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA"); | ||
| 160 | |||
| 161 | MODULE_AUTHOR ("Dmitri"); | ||
| 162 | MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000"); | ||
| 163 | MODULE_LICENSE("GPL"); | ||
| 164 | |||
| 165 | /* Still mysterious i2c commands */ | ||
| 166 | static const unsigned short unknown_88 = 0x0088; | ||
| 167 | static const unsigned short unknown_89 = 0x0089; | ||
| 168 | static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 }; | ||
| 169 | static const unsigned short contrast_14 = 0x0014; | ||
| 170 | static const unsigned short light_27 = 0x0027; | ||
| 171 | static const unsigned short sharp_13 = 0x0013; | ||
| 172 | |||
| 173 | /* i2c commands for Model 2 cameras */ | ||
| 174 | static const unsigned short mod2_brightness = 0x001a; /* $5b .. $ee; default=$5a */ | ||
| 175 | static const unsigned short mod2_set_framerate = 0x001c; /* 0 (fast).. $1F (slow) */ | ||
| 176 | static const unsigned short mod2_color_balance_rg2 = 0x001e; /* 0 (red) .. $7F (green) */ | ||
| 177 | static const unsigned short mod2_saturation = 0x0020; /* 0 (b/w) - $7F (full color) */ | ||
| 178 | static const unsigned short mod2_color_balance_yb = 0x0022; /* 0..$7F, $50 is about right */ | ||
| 179 | static const unsigned short mod2_hue = 0x0024; /* 0..$7F, $70 is about right */ | ||
| 180 | static const unsigned short mod2_sensitivity = 0x0028; /* 0 (min) .. $1F (max) */ | ||
| 181 | |||
| 182 | struct struct_initData { | ||
| 183 | unsigned char req; | ||
| 184 | unsigned short value; | ||
| 185 | unsigned short index; | ||
| 186 | }; | ||
| 187 | |||
| 188 | /* | ||
| 189 | * ibmcam_size_to_videosize() | ||
| 190 | * | ||
| 191 | * This procedure converts module option 'size' into the actual | ||
| 192 | * videosize_t that defines the image size in pixels. We need | ||
| 193 | * simplified 'size' because user wants a simple enumerated list | ||
| 194 | * of choices, not an infinite set of possibilities. | ||
| 195 | */ | ||
| 196 | static videosize_t ibmcam_size_to_videosize(int size) | ||
| 197 | { | ||
| 198 | videosize_t vs = VIDEOSIZE_352x288; | ||
| 199 | RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1)); | ||
| 200 | switch (size) { | ||
| 201 | case SIZE_128x96: | ||
| 202 | vs = VIDEOSIZE_128x96; | ||
| 203 | break; | ||
| 204 | case SIZE_160x120: | ||
| 205 | vs = VIDEOSIZE_160x120; | ||
| 206 | break; | ||
| 207 | case SIZE_176x144: | ||
| 208 | vs = VIDEOSIZE_176x144; | ||
| 209 | break; | ||
| 210 | case SIZE_320x240: | ||
| 211 | vs = VIDEOSIZE_320x240; | ||
| 212 | break; | ||
| 213 | case SIZE_352x240: | ||
| 214 | vs = VIDEOSIZE_352x240; | ||
| 215 | break; | ||
| 216 | case SIZE_352x288: | ||
| 217 | vs = VIDEOSIZE_352x288; | ||
| 218 | break; | ||
| 219 | case SIZE_640x480: | ||
| 220 | vs = VIDEOSIZE_640x480; | ||
| 221 | break; | ||
| 222 | default: | ||
| 223 | err("size=%d. is not valid", size); | ||
| 224 | break; | ||
| 225 | } | ||
| 226 | return vs; | ||
| 227 | } | ||
| 228 | |||
| 229 | /* | ||
| 230 | * ibmcam_find_header() | ||
| 231 | * | ||
| 232 | * Locate one of supported header markers in the queue. | ||
| 233 | * Once found, remove all preceding bytes AND the marker (4 bytes) | ||
| 234 | * from the data pump queue. Whatever follows must be video lines. | ||
| 235 | * | ||
| 236 | * History: | ||
| 237 | * 1/21/00 Created. | ||
| 238 | */ | ||
| 239 | static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */ | ||
| 240 | { | ||
| 241 | struct usbvideo_frame *frame; | ||
| 242 | ibmcam_t *icam; | ||
| 243 | |||
| 244 | if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { | ||
| 245 | err("ibmcam_find_header: Illegal frame %d.", uvd->curframe); | ||
| 246 | return scan_EndParse; | ||
| 247 | } | ||
| 248 | icam = IBMCAM_T(uvd); | ||
| 249 | assert(icam != NULL); | ||
| 250 | frame = &uvd->frame[uvd->curframe]; | ||
| 251 | icam->has_hdr = 0; | ||
| 252 | switch (icam->camera_model) { | ||
| 253 | case IBMCAM_MODEL_1: | ||
| 254 | { | ||
| 255 | const int marker_len = 4; | ||
| 256 | while (RingQueue_GetLength(&uvd->dp) >= marker_len) { | ||
| 257 | if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && | ||
| 258 | (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && | ||
| 259 | (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00)) | ||
| 260 | { | ||
| 261 | #if 0 /* This code helps to detect new frame markers */ | ||
| 262 | info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3)); | ||
| 263 | #endif | ||
| 264 | frame->header = RING_QUEUE_PEEK(&uvd->dp, 3); | ||
| 265 | if ((frame->header == HDRSIG_MODEL1_128x96) || | ||
| 266 | (frame->header == HDRSIG_MODEL1_176x144) || | ||
| 267 | (frame->header == HDRSIG_MODEL1_352x288)) | ||
| 268 | { | ||
| 269 | #if 0 | ||
| 270 | info("Header found."); | ||
| 271 | #endif | ||
| 272 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); | ||
| 273 | icam->has_hdr = 1; | ||
| 274 | break; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | /* If we are still here then this doesn't look like a header */ | ||
| 278 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); | ||
| 279 | } | ||
| 280 | break; | ||
| 281 | } | ||
| 282 | case IBMCAM_MODEL_2: | ||
| 283 | case IBMCAM_MODEL_4: | ||
| 284 | { | ||
| 285 | int marker_len = 0; | ||
| 286 | switch (uvd->videosize) { | ||
| 287 | case VIDEOSIZE_176x144: | ||
| 288 | marker_len = 10; | ||
| 289 | break; | ||
| 290 | default: | ||
| 291 | marker_len = 2; | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | while (RingQueue_GetLength(&uvd->dp) >= marker_len) { | ||
| 295 | if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && | ||
| 296 | (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF)) | ||
| 297 | { | ||
| 298 | #if 0 | ||
| 299 | info("Header found."); | ||
| 300 | #endif | ||
| 301 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); | ||
| 302 | icam->has_hdr = 1; | ||
| 303 | frame->header = HDRSIG_MODEL1_176x144; | ||
| 304 | break; | ||
| 305 | } | ||
| 306 | /* If we are still here then this doesn't look like a header */ | ||
| 307 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); | ||
| 308 | } | ||
| 309 | break; | ||
| 310 | } | ||
| 311 | case IBMCAM_MODEL_3: | ||
| 312 | { /* | ||
| 313 | * Headers: (one precedes every frame). nc=no compression, | ||
| 314 | * bq=best quality bf=best frame rate. | ||
| 315 | * | ||
| 316 | * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf } | ||
| 317 | * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf } | ||
| 318 | * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf } | ||
| 319 | * | ||
| 320 | * Bytes '00 FF' seem to indicate header. Other two bytes | ||
| 321 | * encode the frame type. This is a set of bit fields that | ||
| 322 | * encode image size, compression type etc. These fields | ||
| 323 | * do NOT contain frame number because all frames carry | ||
| 324 | * the same header. | ||
| 325 | */ | ||
| 326 | const int marker_len = 4; | ||
| 327 | while (RingQueue_GetLength(&uvd->dp) >= marker_len) { | ||
| 328 | if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && | ||
| 329 | (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && | ||
| 330 | (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF)) | ||
| 331 | { | ||
| 332 | /* | ||
| 333 | * Combine 2 bytes of frame type into one | ||
| 334 | * easy to use value | ||
| 335 | */ | ||
| 336 | unsigned long byte3, byte4; | ||
| 337 | |||
| 338 | byte3 = RING_QUEUE_PEEK(&uvd->dp, 2); | ||
| 339 | byte4 = RING_QUEUE_PEEK(&uvd->dp, 3); | ||
| 340 | frame->header = (byte3 << 8) | byte4; | ||
| 341 | #if 0 | ||
| 342 | info("Header found."); | ||
| 343 | #endif | ||
| 344 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); | ||
| 345 | icam->has_hdr = 1; | ||
| 346 | break; | ||
| 347 | } | ||
| 348 | /* If we are still here then this doesn't look like a header */ | ||
| 349 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); | ||
| 350 | } | ||
| 351 | break; | ||
| 352 | } | ||
| 353 | default: | ||
| 354 | break; | ||
| 355 | } | ||
| 356 | if (!icam->has_hdr) { | ||
| 357 | if (uvd->debug > 2) | ||
| 358 | info("Skipping frame, no header"); | ||
| 359 | return scan_EndParse; | ||
| 360 | } | ||
| 361 | |||
| 362 | /* Header found */ | ||
| 363 | icam->has_hdr = 1; | ||
| 364 | uvd->stats.header_count++; | ||
| 365 | frame->scanstate = ScanState_Lines; | ||
| 366 | frame->curline = 0; | ||
| 367 | |||
| 368 | if (flags & FLAGS_FORCE_TESTPATTERN) { | ||
| 369 | usbvideo_TestPattern(uvd, 1, 1); | ||
| 370 | return scan_NextFrame; | ||
| 371 | } | ||
| 372 | return scan_Continue; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* | ||
| 376 | * ibmcam_parse_lines() | ||
| 377 | * | ||
| 378 | * Parse one line (interlaced) from the buffer, put | ||
| 379 | * decoded RGB value into the current frame buffer | ||
| 380 | * and add the written number of bytes (RGB) to | ||
| 381 | * the *pcopylen. | ||
| 382 | * | ||
| 383 | * History: | ||
| 384 | * 21-Jan-2000 Created. | ||
| 385 | * 12-Oct-2000 Reworked to reflect interlaced nature of the data. | ||
| 386 | */ | ||
| 387 | static enum ParseState ibmcam_parse_lines( | ||
| 388 | struct uvd *uvd, | ||
| 389 | struct usbvideo_frame *frame, | ||
| 390 | long *pcopylen) | ||
| 391 | { | ||
| 392 | unsigned char *f; | ||
| 393 | ibmcam_t *icam; | ||
| 394 | unsigned int len, scanLength, scanHeight, order_uv, order_yc; | ||
| 395 | int v4l_linesize; /* V4L line offset */ | ||
| 396 | const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */ | ||
| 397 | const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ | ||
| 398 | const int ccm = 128; /* Color correction median - see below */ | ||
| 399 | int y, u, v, i, frame_done=0, color_corr; | ||
| 400 | static unsigned char lineBuffer[640*3]; | ||
| 401 | unsigned const char *chromaLine, *lumaLine; | ||
| 402 | |||
| 403 | assert(uvd != NULL); | ||
| 404 | assert(frame != NULL); | ||
| 405 | icam = IBMCAM_T(uvd); | ||
| 406 | assert(icam != NULL); | ||
| 407 | color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ | ||
| 408 | RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); | ||
| 409 | |||
| 410 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
| 411 | |||
| 412 | if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) { | ||
| 413 | /* Model 4 frame markers do not carry image size identification */ | ||
| 414 | switch (uvd->videosize) { | ||
| 415 | case VIDEOSIZE_128x96: | ||
| 416 | case VIDEOSIZE_160x120: | ||
| 417 | case VIDEOSIZE_176x144: | ||
| 418 | scanLength = VIDEOSIZE_X(uvd->videosize); | ||
| 419 | scanHeight = VIDEOSIZE_Y(uvd->videosize); | ||
| 420 | break; | ||
| 421 | default: | ||
| 422 | err("ibmcam_parse_lines: Wrong mode."); | ||
| 423 | return scan_Out; | ||
| 424 | } | ||
| 425 | order_yc = 1; /* order_yc: true=Yc false=cY ('c'=either U or V) */ | ||
| 426 | order_uv = 1; /* Always true in this algorithm */ | ||
| 427 | } else { | ||
| 428 | switch (frame->header) { | ||
| 429 | case HDRSIG_MODEL1_128x96: | ||
| 430 | scanLength = 128; | ||
| 431 | scanHeight = 96; | ||
| 432 | order_uv = 1; /* U Y V Y ... */ | ||
| 433 | break; | ||
| 434 | case HDRSIG_MODEL1_176x144: | ||
| 435 | scanLength = 176; | ||
| 436 | scanHeight = 144; | ||
| 437 | order_uv = 1; /* U Y V Y ... */ | ||
| 438 | break; | ||
| 439 | case HDRSIG_MODEL1_352x288: | ||
| 440 | scanLength = 352; | ||
| 441 | scanHeight = 288; | ||
| 442 | order_uv = 0; /* Y V Y V ... */ | ||
| 443 | break; | ||
| 444 | default: | ||
| 445 | err("Unknown header signature 00 FF 00 %02lX", frame->header); | ||
| 446 | return scan_NextFrame; | ||
| 447 | } | ||
| 448 | /* order_yc: true=Yc false=cY ('c'=either U or V) */ | ||
| 449 | order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2); | ||
| 450 | } | ||
| 451 | |||
| 452 | len = scanLength * 3; | ||
| 453 | assert(len <= sizeof(lineBuffer)); | ||
| 454 | |||
| 455 | /* | ||
| 456 | * Lines are organized this way: | ||
| 457 | * | ||
| 458 | * I420: | ||
| 459 | * ~~~~ | ||
| 460 | * <scanLength-> | ||
| 461 | * ___________________________________ | ||
| 462 | * |-----Y-----|---UVUVUV...UVUV-----| \ | ||
| 463 | * |-----------+---------------------| \ | ||
| 464 | * |<-- 176 -->|<------ 176*2 ------>| Total 72. lines (interlaced) | ||
| 465 | * |... ... | ... | / | ||
| 466 | * |<-- 352 -->|<------ 352*2 ------>| Total 144. lines (interlaced) | ||
| 467 | * |___________|_____________________| / | ||
| 468 | * \ \ | ||
| 469 | * lumaLine chromaLine | ||
| 470 | */ | ||
| 471 | |||
| 472 | /* Make sure there's enough data for the entire line */ | ||
| 473 | if (RingQueue_GetLength(&uvd->dp) < len) | ||
| 474 | return scan_Out; | ||
| 475 | |||
| 476 | /* Suck one line out of the ring queue */ | ||
| 477 | RingQueue_Dequeue(&uvd->dp, lineBuffer, len); | ||
| 478 | |||
| 479 | /* | ||
| 480 | * Make sure that our writing into output buffer | ||
| 481 | * will not exceed the buffer. Mind that we may write | ||
| 482 | * not into current output scanline but in several after | ||
| 483 | * it as well (if we enlarge image vertically.) | ||
| 484 | */ | ||
| 485 | if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request)) | ||
| 486 | return scan_NextFrame; | ||
| 487 | |||
| 488 | /* | ||
| 489 | * Now we are sure that entire line (representing all 'scanLength' | ||
| 490 | * pixels from the camera) is available in the buffer. We | ||
| 491 | * start copying the line left-aligned to the V4L buffer. | ||
| 492 | * If the camera line is shorter then we should pad the V4L | ||
| 493 | * buffer with something (black) to complete the line. | ||
| 494 | */ | ||
| 495 | assert(frame->data != NULL); | ||
| 496 | f = frame->data + (v4l_linesize * frame->curline); | ||
| 497 | |||
| 498 | /* | ||
| 499 | * To obtain chrominance data from the 'chromaLine' use this: | ||
| 500 | * v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]... | ||
| 501 | * u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]... | ||
| 502 | * | ||
| 503 | * Indices must be calculated this way: | ||
| 504 | * v_index = (i >> 1) << 2; | ||
| 505 | * u_index = (i >> 1) << 2 + 2; | ||
| 506 | * | ||
| 507 | * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1] | ||
| 508 | */ | ||
| 509 | lumaLine = lineBuffer; | ||
| 510 | chromaLine = lineBuffer + scanLength; | ||
| 511 | for (i = 0; i < VIDEOSIZE_X(frame->request); i++) | ||
| 512 | { | ||
| 513 | unsigned char rv, gv, bv; /* RGB components */ | ||
| 514 | |||
| 515 | /* Check for various visual debugging hints (colorized pixels) */ | ||
| 516 | if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) { | ||
| 517 | /* | ||
| 518 | * This is bad and should not happen. This means that | ||
| 519 | * we somehow overshoot the line and encountered new | ||
| 520 | * frame! Obviously our camera/V4L frame size is out | ||
| 521 | * of whack. This cyan dot will help you to figure | ||
| 522 | * out where exactly the new frame arrived. | ||
| 523 | */ | ||
| 524 | if (icam->has_hdr == 1) { | ||
| 525 | bv = 0; /* Yellow marker */ | ||
| 526 | gv = 0xFF; | ||
| 527 | rv = 0xFF; | ||
| 528 | } else { | ||
| 529 | bv = 0xFF; /* Cyan marker */ | ||
| 530 | gv = 0xFF; | ||
| 531 | rv = 0; | ||
| 532 | } | ||
| 533 | icam->has_hdr = 0; | ||
| 534 | goto make_pixel; | ||
| 535 | } | ||
| 536 | |||
| 537 | /* | ||
| 538 | * Check if we are still in range. We may be out of range if our | ||
| 539 | * V4L canvas is wider or taller than the camera "native" image. | ||
| 540 | * Then we quickly fill the remainder of the line with zeros to | ||
| 541 | * make black color and quit the horizontal scanning loop. | ||
| 542 | */ | ||
| 543 | if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { | ||
| 544 | const int j = i * V4L_BYTES_PER_PIXEL; | ||
| 545 | #if USES_IBMCAM_PUTPIXEL | ||
| 546 | /* Refresh 'f' because we don't use it much with PUTPIXEL */ | ||
| 547 | f = frame->data + (v4l_linesize * frame->curline) + j; | ||
| 548 | #endif | ||
| 549 | memset(f, 0, v4l_linesize - j); | ||
| 550 | break; | ||
| 551 | } | ||
| 552 | |||
| 553 | y = lumaLine[i]; | ||
| 554 | if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */ | ||
| 555 | rv = gv = bv = y; | ||
| 556 | else { | ||
| 557 | int off_0, off_2; | ||
| 558 | |||
| 559 | off_0 = (i >> 1) << 2; | ||
| 560 | off_2 = off_0 + 2; | ||
| 561 | |||
| 562 | if (order_yc) { | ||
| 563 | off_0++; | ||
| 564 | off_2++; | ||
| 565 | } | ||
| 566 | if (!order_uv) { | ||
| 567 | off_0 += 2; | ||
| 568 | off_2 -= 2; | ||
| 569 | } | ||
| 570 | u = chromaLine[off_0] + hue_corr; | ||
| 571 | v = chromaLine[off_2] + hue2_corr; | ||
| 572 | |||
| 573 | /* Apply color correction */ | ||
| 574 | if (color_corr != 0) { | ||
| 575 | /* Magnify up to 2 times, reduce down to zero saturation */ | ||
| 576 | u = 128 + ((ccm + color_corr) * (u - 128)) / ccm; | ||
| 577 | v = 128 + ((ccm + color_corr) * (v - 128)) / ccm; | ||
| 578 | } | ||
| 579 | YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); | ||
| 580 | } | ||
| 581 | |||
| 582 | make_pixel: | ||
| 583 | /* | ||
| 584 | * The purpose of creating the pixel here, in one, | ||
| 585 | * dedicated place is that we may need to make the | ||
| 586 | * pixel wider and taller than it actually is. This | ||
| 587 | * may be used if camera generates small frames for | ||
| 588 | * sake of frame rate (or any other reason.) | ||
| 589 | * | ||
| 590 | * The output data consists of B, G, R bytes | ||
| 591 | * (in this order). | ||
| 592 | */ | ||
| 593 | #if USES_IBMCAM_PUTPIXEL | ||
| 594 | RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); | ||
| 595 | #else | ||
| 596 | *f++ = bv; | ||
| 597 | *f++ = gv; | ||
| 598 | *f++ = rv; | ||
| 599 | #endif | ||
| 600 | /* | ||
| 601 | * Typically we do not decide within a legitimate frame | ||
| 602 | * that we want to end the frame. However debugging code | ||
| 603 | * may detect marker of new frame within the data. Then | ||
| 604 | * this condition activates. The 'data' pointer is already | ||
| 605 | * pointing at the new marker, so we'd better leave it as is. | ||
| 606 | */ | ||
| 607 | if (frame_done) | ||
| 608 | break; /* End scanning of lines */ | ||
| 609 | } | ||
| 610 | /* | ||
| 611 | * Account for number of bytes that we wrote into output V4L frame. | ||
| 612 | * We do it here, after we are done with the scanline, because we | ||
| 613 | * may fill more than one output scanline if we do vertical | ||
| 614 | * enlargement. | ||
| 615 | */ | ||
| 616 | frame->curline += 2; | ||
| 617 | if (pcopylen != NULL) | ||
| 618 | *pcopylen += 2 * v4l_linesize; | ||
| 619 | frame->deinterlace = Deinterlace_FillOddLines; | ||
| 620 | |||
| 621 | if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request))) | ||
| 622 | return scan_NextFrame; | ||
| 623 | else | ||
| 624 | return scan_Continue; | ||
| 625 | } | ||
| 626 | |||
| 627 | /* | ||
| 628 | * ibmcam_model2_320x240_parse_lines() | ||
| 629 | * | ||
| 630 | * This procedure deals with a weird RGB format that is produced by IBM | ||
| 631 | * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175, | ||
| 632 | * depending on horizontal size of the picture: | ||
| 633 | * | ||
| 634 | * <--- 160 or 176 pairs of RA,RB bytes -----> | ||
| 635 | * *-----------------------------------------* \ | ||
| 636 | * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx | \ This is pair of horizontal lines, | ||
| 637 | * |-----+-----+-----+-----+ ... +-----+-----| *- or one interlaced line, total | ||
| 638 | * | B0 | G0 | B1 | G1 | ... | Bx | Gx | / 120 or 144 such pairs which yield | ||
| 639 | * |=====+=====+=====+=====+ ... +=====+=====| / 240 or 288 lines after deinterlacing. | ||
| 640 | * | ||
| 641 | * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1 | ||
| 642 | * defines ONE pixel. Therefore this format yields 176x144 "decoded" | ||
| 643 | * resolution at best. I do not know why camera sends such format - the | ||
| 644 | * previous model (1) just used interlaced I420 and everyone was happy. | ||
| 645 | * | ||
| 646 | * I do not know what is the difference between RAi and RBi bytes. Both | ||
| 647 | * seemingly represent R component, but slightly vary in value (so that | ||
| 648 | * the picture looks a bit colored if one or another is used). I use | ||
| 649 | * them both as R component in attempt to at least partially recover the | ||
| 650 | * lost resolution. | ||
| 651 | */ | ||
| 652 | static enum ParseState ibmcam_model2_320x240_parse_lines( | ||
| 653 | struct uvd *uvd, | ||
| 654 | struct usbvideo_frame *frame, | ||
| 655 | long *pcopylen) | ||
| 656 | { | ||
| 657 | unsigned char *f, *la, *lb; | ||
| 658 | unsigned int len; | ||
| 659 | int v4l_linesize; /* V4L line offset */ | ||
| 660 | int i, j, frame_done=0, color_corr; | ||
| 661 | int scanLength, scanHeight; | ||
| 662 | static unsigned char lineBuffer[352*2]; | ||
| 663 | |||
| 664 | switch (uvd->videosize) { | ||
| 665 | case VIDEOSIZE_320x240: | ||
| 666 | case VIDEOSIZE_352x240: | ||
| 667 | case VIDEOSIZE_352x288: | ||
| 668 | scanLength = VIDEOSIZE_X(uvd->videosize); | ||
| 669 | scanHeight = VIDEOSIZE_Y(uvd->videosize); | ||
| 670 | break; | ||
| 671 | default: | ||
| 672 | err("ibmcam_model2_320x240_parse_lines: Wrong mode."); | ||
| 673 | return scan_Out; | ||
| 674 | } | ||
| 675 | |||
| 676 | color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */ | ||
| 677 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
| 678 | |||
| 679 | len = scanLength * 2; /* See explanation above */ | ||
| 680 | assert(len <= sizeof(lineBuffer)); | ||
| 681 | |||
| 682 | /* Make sure there's enough data for the entire line */ | ||
| 683 | if (RingQueue_GetLength(&uvd->dp) < len) | ||
| 684 | return scan_Out; | ||
| 685 | |||
| 686 | /* Suck one line out of the ring queue */ | ||
| 687 | RingQueue_Dequeue(&uvd->dp, lineBuffer, len); | ||
| 688 | |||
| 689 | /* | ||
| 690 | * Make sure that our writing into output buffer | ||
| 691 | * will not exceed the buffer. Mind that we may write | ||
| 692 | * not into current output scanline but in several after | ||
| 693 | * it as well (if we enlarge image vertically.) | ||
| 694 | */ | ||
| 695 | if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request)) | ||
| 696 | return scan_NextFrame; | ||
| 697 | |||
| 698 | la = lineBuffer; | ||
| 699 | lb = lineBuffer + scanLength; | ||
| 700 | |||
| 701 | /* | ||
| 702 | * Now we are sure that entire line (representing all | ||
| 703 | * VIDEOSIZE_X(frame->request) | ||
| 704 | * pixels from the camera) is available in the scratch buffer. We | ||
| 705 | * start copying the line left-aligned to the V4L buffer (which | ||
| 706 | * might be larger - not smaller, hopefully). If the camera | ||
| 707 | * line is shorter then we should pad the V4L buffer with something | ||
| 708 | * (black in this case) to complete the line. | ||
| 709 | */ | ||
| 710 | f = frame->data + (v4l_linesize * frame->curline); | ||
| 711 | |||
| 712 | /* Fill the 2-line strip */ | ||
| 713 | for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { | ||
| 714 | int y, rv, gv, bv; /* RGB components */ | ||
| 715 | |||
| 716 | j = i & (~1); | ||
| 717 | |||
| 718 | /* Check for various visual debugging hints (colorized pixels) */ | ||
| 719 | if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) { | ||
| 720 | if (IBMCAM_T(uvd)->has_hdr == 1) { | ||
| 721 | bv = 0; /* Yellow marker */ | ||
| 722 | gv = 0xFF; | ||
| 723 | rv = 0xFF; | ||
| 724 | } else { | ||
| 725 | bv = 0xFF; /* Cyan marker */ | ||
| 726 | gv = 0xFF; | ||
| 727 | rv = 0; | ||
| 728 | } | ||
| 729 | IBMCAM_T(uvd)->has_hdr = 0; | ||
| 730 | goto make_pixel; | ||
| 731 | } | ||
| 732 | |||
| 733 | /* | ||
| 734 | * Check if we are still in range. We may be out of range if our | ||
| 735 | * V4L canvas is wider or taller than the camera "native" image. | ||
| 736 | * Then we quickly fill the remainder of the line with zeros to | ||
| 737 | * make black color and quit the horizontal scanning loop. | ||
| 738 | */ | ||
| 739 | if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { | ||
| 740 | const int j = i * V4L_BYTES_PER_PIXEL; | ||
| 741 | #if USES_IBMCAM_PUTPIXEL | ||
| 742 | /* Refresh 'f' because we don't use it much with PUTPIXEL */ | ||
| 743 | f = frame->data + (v4l_linesize * frame->curline) + j; | ||
| 744 | #endif | ||
| 745 | memset(f, 0, v4l_linesize - j); | ||
| 746 | break; | ||
| 747 | } | ||
| 748 | |||
| 749 | /* | ||
| 750 | * Here I use RA and RB components, one per physical pixel. | ||
| 751 | * This causes fine vertical grid on the picture but may improve | ||
| 752 | * horizontal resolution. If you prefer replicating, use this: | ||
| 753 | * rv = la[j + 0]; ... or ... rv = la[j + 1]; | ||
| 754 | * then the pixel will be replicated. | ||
| 755 | */ | ||
| 756 | rv = la[i]; | ||
| 757 | gv = lb[j + 1]; | ||
| 758 | bv = lb[j + 0]; | ||
| 759 | |||
| 760 | y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */ | ||
| 761 | |||
| 762 | if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */ | ||
| 763 | rv = gv = bv = y; | ||
| 764 | else if (color_corr != 128) { | ||
| 765 | |||
| 766 | /* Calculate difference between color and brightness */ | ||
| 767 | rv -= y; | ||
| 768 | gv -= y; | ||
| 769 | bv -= y; | ||
| 770 | |||
| 771 | /* Scale differences */ | ||
| 772 | rv = (rv * color_corr) / 128; | ||
| 773 | gv = (gv * color_corr) / 128; | ||
| 774 | bv = (bv * color_corr) / 128; | ||
| 775 | |||
| 776 | /* Reapply brightness */ | ||
| 777 | rv += y; | ||
| 778 | gv += y; | ||
| 779 | bv += y; | ||
| 780 | |||
| 781 | /* Watch for overflows */ | ||
| 782 | RESTRICT_TO_RANGE(rv, 0, 255); | ||
| 783 | RESTRICT_TO_RANGE(gv, 0, 255); | ||
| 784 | RESTRICT_TO_RANGE(bv, 0, 255); | ||
| 785 | } | ||
| 786 | |||
| 787 | make_pixel: | ||
| 788 | RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); | ||
| 789 | } | ||
| 790 | /* | ||
| 791 | * Account for number of bytes that we wrote into output V4L frame. | ||
| 792 | * We do it here, after we are done with the scanline, because we | ||
| 793 | * may fill more than one output scanline if we do vertical | ||
| 794 | * enlargement. | ||
| 795 | */ | ||
| 796 | frame->curline += 2; | ||
| 797 | *pcopylen += v4l_linesize * 2; | ||
| 798 | frame->deinterlace = Deinterlace_FillOddLines; | ||
| 799 | |||
| 800 | if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request))) | ||
| 801 | return scan_NextFrame; | ||
| 802 | else | ||
| 803 | return scan_Continue; | ||
| 804 | } | ||
| 805 | |||
| 806 | static enum ParseState ibmcam_model3_parse_lines( | ||
| 807 | struct uvd *uvd, | ||
| 808 | struct usbvideo_frame *frame, | ||
| 809 | long *pcopylen) | ||
| 810 | { | ||
| 811 | unsigned char *data; | ||
| 812 | const unsigned char *color; | ||
| 813 | unsigned int len; | ||
| 814 | int v4l_linesize; /* V4L line offset */ | ||
| 815 | const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */ | ||
| 816 | const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ | ||
| 817 | const int ccm = 128; /* Color correction median - see below */ | ||
| 818 | int i, u, v, rw, data_w=0, data_h=0, color_corr; | ||
| 819 | static unsigned char lineBuffer[640*3]; | ||
| 820 | |||
| 821 | color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ | ||
| 822 | RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); | ||
| 823 | |||
| 824 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
| 825 | |||
| 826 | /* The header tells us what sort of data is in this frame */ | ||
| 827 | switch (frame->header) { | ||
| 828 | /* | ||
| 829 | * Uncompressed modes (that are easy to decode). | ||
| 830 | */ | ||
| 831 | case 0x0308: | ||
| 832 | data_w = 640; | ||
| 833 | data_h = 480; | ||
| 834 | break; | ||
| 835 | case 0x0208: | ||
| 836 | data_w = 320; | ||
| 837 | data_h = 240; | ||
| 838 | break; | ||
| 839 | case 0x020A: | ||
| 840 | data_w = 160; | ||
| 841 | data_h = 120; | ||
| 842 | break; | ||
| 843 | /* | ||
| 844 | * Compressed modes (ViCE - that I don't know how to decode). | ||
| 845 | */ | ||
| 846 | case 0x0328: /* 640x480, best quality compression */ | ||
| 847 | case 0x0368: /* 640x480, best frame rate compression */ | ||
| 848 | case 0x0228: /* 320x240, best quality compression */ | ||
| 849 | case 0x0268: /* 320x240, best frame rate compression */ | ||
| 850 | case 0x02CA: /* 160x120, best quality compression */ | ||
| 851 | case 0x02EA: /* 160x120, best frame rate compression */ | ||
| 852 | /* Do nothing with this - not supported */ | ||
| 853 | err("Unsupported mode $%04lx", frame->header); | ||
| 854 | return scan_NextFrame; | ||
| 855 | default: | ||
| 856 | /* Catch unknown headers, may help in learning new headers */ | ||
| 857 | err("Strange frame->header=$%08lx", frame->header); | ||
| 858 | return scan_NextFrame; | ||
| 859 | } | ||
| 860 | |||
| 861 | /* | ||
| 862 | * Make sure that our writing into output buffer | ||
| 863 | * will not exceed the buffer. Note that we may write | ||
| 864 | * not into current output scanline but in several after | ||
| 865 | * it as well (if we enlarge image vertically.) | ||
| 866 | */ | ||
| 867 | if ((frame->curline + 1) >= data_h) { | ||
| 868 | if (uvd->debug >= 3) | ||
| 869 | info("Reached line %d. (frame is done)", frame->curline); | ||
| 870 | return scan_NextFrame; | ||
| 871 | } | ||
| 872 | |||
| 873 | /* Make sure there's enough data for the entire line */ | ||
| 874 | len = 3 * data_w; /* <y-data> <uv-data> */ | ||
| 875 | assert(len <= sizeof(lineBuffer)); | ||
| 876 | |||
| 877 | /* Make sure there's enough data for the entire line */ | ||
| 878 | if (RingQueue_GetLength(&uvd->dp) < len) | ||
| 879 | return scan_Out; | ||
| 880 | |||
| 881 | /* Suck one line out of the ring queue */ | ||
| 882 | RingQueue_Dequeue(&uvd->dp, lineBuffer, len); | ||
| 883 | |||
| 884 | data = lineBuffer; | ||
| 885 | color = data + data_w; /* Point to where color planes begin */ | ||
| 886 | |||
| 887 | /* Bottom-to-top scanning */ | ||
| 888 | rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1; | ||
| 889 | RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1); | ||
| 890 | |||
| 891 | for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { | ||
| 892 | int y, rv, gv, bv; /* RGB components */ | ||
| 893 | |||
| 894 | if (i < data_w) { | ||
| 895 | y = data[i]; /* Luminosity is the first line */ | ||
| 896 | |||
| 897 | /* Apply static color correction */ | ||
| 898 | u = color[i*2] + hue_corr; | ||
| 899 | v = color[i*2 + 1] + hue2_corr; | ||
| 900 | |||
| 901 | /* Apply color correction */ | ||
| 902 | if (color_corr != 0) { | ||
| 903 | /* Magnify up to 2 times, reduce down to zero saturation */ | ||
| 904 | u = 128 + ((ccm + color_corr) * (u - 128)) / ccm; | ||
| 905 | v = 128 + ((ccm + color_corr) * (v - 128)) / ccm; | ||
| 906 | } | ||
| 907 | } else | ||
| 908 | y = 0, u = v = 128; | ||
| 909 | |||
| 910 | YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); | ||
| 911 | RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */ | ||
| 912 | } | ||
| 913 | frame->deinterlace = Deinterlace_FillEvenLines; | ||
| 914 | |||
| 915 | /* | ||
| 916 | * Account for number of bytes that we wrote into output V4L frame. | ||
| 917 | * We do it here, after we are done with the scanline, because we | ||
| 918 | * may fill more than one output scanline if we do vertical | ||
| 919 | * enlargement. | ||
| 920 | */ | ||
| 921 | frame->curline += 2; | ||
| 922 | *pcopylen += 2 * v4l_linesize; | ||
| 923 | |||
| 924 | if (frame->curline >= VIDEOSIZE_Y(frame->request)) { | ||
| 925 | if (uvd->debug >= 3) { | ||
| 926 | info("All requested lines (%ld.) done.", | ||
| 927 | VIDEOSIZE_Y(frame->request)); | ||
| 928 | } | ||
| 929 | return scan_NextFrame; | ||
| 930 | } else | ||
| 931 | return scan_Continue; | ||
| 932 | } | ||
| 933 | |||
| 934 | /* | ||
| 935 | * ibmcam_model4_128x96_parse_lines() | ||
| 936 | * | ||
| 937 | * This decoder is for one strange data format that is produced by Model 4 | ||
| 938 | * camera only in 128x96 mode. This is RGB format and here is its description. | ||
| 939 | * First of all, this is non-interlaced stream, meaning that all scan lines | ||
| 940 | * are present in the datastream. There are 96 consecutive blocks of data | ||
| 941 | * that describe all 96 lines of the image. Each block is 5*128 bytes long | ||
| 942 | * and carries R, G, B components. The format of the block is shown in the | ||
| 943 | * code below. First 128*2 bytes are interleaved R and G components. Then | ||
| 944 | * we have a gap (junk data) 64 bytes long. Then follow B and something | ||
| 945 | * else, also interleaved (this makes another 128*2 bytes). After that | ||
| 946 | * probably another 64 bytes of junk follow. | ||
| 947 | * | ||
| 948 | * History: | ||
| 949 | * 10-Feb-2001 Created. | ||
| 950 | */ | ||
| 951 | static enum ParseState ibmcam_model4_128x96_parse_lines( | ||
| 952 | struct uvd *uvd, | ||
| 953 | struct usbvideo_frame *frame, | ||
| 954 | long *pcopylen) | ||
| 955 | { | ||
| 956 | const unsigned char *data_rv, *data_gv, *data_bv; | ||
| 957 | unsigned int len; | ||
| 958 | int i, v4l_linesize; /* V4L line offset */ | ||
| 959 | const int data_w=128, data_h=96; | ||
| 960 | static unsigned char lineBuffer[128*5]; | ||
| 961 | |||
| 962 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
| 963 | |||
| 964 | /* | ||
| 965 | * Make sure that our writing into output buffer | ||
| 966 | * will not exceed the buffer. Note that we may write | ||
| 967 | * not into current output scanline but in several after | ||
| 968 | * it as well (if we enlarge image vertically.) | ||
| 969 | */ | ||
| 970 | if ((frame->curline + 1) >= data_h) { | ||
| 971 | if (uvd->debug >= 3) | ||
| 972 | info("Reached line %d. (frame is done)", frame->curline); | ||
| 973 | return scan_NextFrame; | ||
| 974 | } | ||
| 975 | |||
| 976 | /* | ||
| 977 | * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________ | ||
| 978 | * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 ---> | ||
| 979 | */ | ||
| 980 | |||
| 981 | /* Make sure there's enough data for the entire line */ | ||
| 982 | len = 5 * data_w; | ||
| 983 | assert(len <= sizeof(lineBuffer)); | ||
| 984 | |||
| 985 | /* Make sure there's enough data for the entire line */ | ||
| 986 | if (RingQueue_GetLength(&uvd->dp) < len) | ||
| 987 | return scan_Out; | ||
| 988 | |||
| 989 | /* Suck one line out of the ring queue */ | ||
| 990 | RingQueue_Dequeue(&uvd->dp, lineBuffer, len); | ||
| 991 | |||
| 992 | data_rv = lineBuffer; | ||
| 993 | data_gv = lineBuffer + 1; | ||
| 994 | data_bv = lineBuffer + data_w*2 + data_w/2; | ||
| 995 | for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { | ||
| 996 | int rv, gv, bv; /* RGB components */ | ||
| 997 | if (i < data_w) { | ||
| 998 | const int j = i * 2; | ||
| 999 | gv = data_rv[j]; | ||
| 1000 | rv = data_gv[j]; | ||
| 1001 | bv = data_bv[j]; | ||
| 1002 | if (flags & FLAGS_MONOCHROME) { | ||
| 1003 | unsigned long y; | ||
| 1004 | y = rv + gv + bv; | ||
| 1005 | y /= 3; | ||
| 1006 | if (y > 0xFF) | ||
| 1007 | y = 0xFF; | ||
| 1008 | rv = gv = bv = (unsigned char) y; | ||
| 1009 | } | ||
| 1010 | } else { | ||
| 1011 | rv = gv = bv = 0; | ||
| 1012 | } | ||
| 1013 | RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); | ||
| 1014 | } | ||
| 1015 | frame->deinterlace = Deinterlace_None; | ||
| 1016 | frame->curline++; | ||
| 1017 | *pcopylen += v4l_linesize; | ||
| 1018 | |||
| 1019 | if (frame->curline >= VIDEOSIZE_Y(frame->request)) { | ||
| 1020 | if (uvd->debug >= 3) { | ||
| 1021 | info("All requested lines (%ld.) done.", | ||
| 1022 | VIDEOSIZE_Y(frame->request)); | ||
| 1023 | } | ||
| 1024 | return scan_NextFrame; | ||
| 1025 | } else | ||
| 1026 | return scan_Continue; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | /* | ||
| 1030 | * ibmcam_ProcessIsocData() | ||
| 1031 | * | ||
| 1032 | * Generic routine to parse the ring queue data. It employs either | ||
| 1033 | * ibmcam_find_header() or ibmcam_parse_lines() to do most | ||
| 1034 | * of work. | ||
| 1035 | * | ||
| 1036 | * History: | ||
| 1037 | * 1/21/00 Created. | ||
| 1038 | */ | ||
| 1039 | static void ibmcam_ProcessIsocData(struct uvd *uvd, | ||
| 1040 | struct usbvideo_frame *frame) | ||
| 1041 | { | ||
| 1042 | enum ParseState newstate; | ||
| 1043 | long copylen = 0; | ||
| 1044 | int mod = IBMCAM_T(uvd)->camera_model; | ||
| 1045 | |||
| 1046 | while (1) { | ||
| 1047 | newstate = scan_Out; | ||
| 1048 | if (RingQueue_GetLength(&uvd->dp) > 0) { | ||
| 1049 | if (frame->scanstate == ScanState_Scanning) { | ||
| 1050 | newstate = ibmcam_find_header(uvd); | ||
| 1051 | } else if (frame->scanstate == ScanState_Lines) { | ||
| 1052 | if ((mod == IBMCAM_MODEL_2) && | ||
| 1053 | ((uvd->videosize == VIDEOSIZE_352x288) || | ||
| 1054 | (uvd->videosize == VIDEOSIZE_320x240) || | ||
| 1055 | (uvd->videosize == VIDEOSIZE_352x240))) | ||
| 1056 | { | ||
| 1057 | newstate = ibmcam_model2_320x240_parse_lines( | ||
| 1058 | uvd, frame, ©len); | ||
| 1059 | } else if (mod == IBMCAM_MODEL_4) { | ||
| 1060 | /* | ||
| 1061 | * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB) | ||
| 1062 | * for 320x240 and above; 160x120 and 176x144 uses Model 1 | ||
| 1063 | * decoder (YUV), and 128x96 mode uses ??? | ||
| 1064 | */ | ||
| 1065 | if ((uvd->videosize == VIDEOSIZE_352x288) || | ||
| 1066 | (uvd->videosize == VIDEOSIZE_320x240) || | ||
| 1067 | (uvd->videosize == VIDEOSIZE_352x240)) | ||
| 1068 | { | ||
| 1069 | newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, ©len); | ||
| 1070 | } else if (uvd->videosize == VIDEOSIZE_128x96) { | ||
| 1071 | newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, ©len); | ||
| 1072 | } else { | ||
| 1073 | newstate = ibmcam_parse_lines(uvd, frame, ©len); | ||
| 1074 | } | ||
| 1075 | } else if (mod == IBMCAM_MODEL_3) { | ||
| 1076 | newstate = ibmcam_model3_parse_lines(uvd, frame, ©len); | ||
| 1077 | } else { | ||
| 1078 | newstate = ibmcam_parse_lines(uvd, frame, ©len); | ||
| 1079 | } | ||
| 1080 | } | ||
| 1081 | } | ||
| 1082 | if (newstate == scan_Continue) | ||
| 1083 | continue; | ||
| 1084 | else if ((newstate == scan_NextFrame) || (newstate == scan_Out)) | ||
| 1085 | break; | ||
| 1086 | else | ||
| 1087 | return; /* scan_EndParse */ | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | if (newstate == scan_NextFrame) { | ||
| 1091 | frame->frameState = FrameState_Done; | ||
| 1092 | uvd->curframe = -1; | ||
| 1093 | uvd->stats.frame_num++; | ||
| 1094 | if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) { | ||
| 1095 | /* Need software contrast adjustment for those cameras */ | ||
| 1096 | frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST; | ||
| 1097 | } | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | /* Update the frame's uncompressed length. */ | ||
| 1101 | frame->seqRead_Length += copylen; | ||
| 1102 | |||
| 1103 | #if 0 | ||
| 1104 | { | ||
| 1105 | static unsigned char j=0; | ||
| 1106 | memset(frame->data, j++, uvd->max_frame_size); | ||
| 1107 | frame->frameState = FrameState_Ready; | ||
| 1108 | } | ||
| 1109 | #endif | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | /* | ||
| 1113 | * ibmcam_veio() | ||
| 1114 | * | ||
| 1115 | * History: | ||
| 1116 | * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. | ||
| 1117 | */ | ||
| 1118 | static int ibmcam_veio( | ||
| 1119 | struct uvd *uvd, | ||
| 1120 | unsigned char req, | ||
| 1121 | unsigned short value, | ||
| 1122 | unsigned short index) | ||
| 1123 | { | ||
| 1124 | static const char proc[] = "ibmcam_veio"; | ||
| 1125 | unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; | ||
| 1126 | int i; | ||
| 1127 | |||
| 1128 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
| 1129 | return 0; | ||
| 1130 | |||
| 1131 | if (req == 1) { | ||
| 1132 | i = usb_control_msg( | ||
| 1133 | uvd->dev, | ||
| 1134 | usb_rcvctrlpipe(uvd->dev, 0), | ||
| 1135 | req, | ||
| 1136 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, | ||
| 1137 | value, | ||
| 1138 | index, | ||
| 1139 | cp, | ||
| 1140 | sizeof(cp), | ||
| 1141 | 1000); | ||
| 1142 | #if 0 | ||
| 1143 | info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " | ||
| 1144 | "(req=$%02x val=$%04x ind=$%04x)", | ||
| 1145 | cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], | ||
| 1146 | req, value, index); | ||
| 1147 | #endif | ||
| 1148 | } else { | ||
| 1149 | i = usb_control_msg( | ||
| 1150 | uvd->dev, | ||
| 1151 | usb_sndctrlpipe(uvd->dev, 0), | ||
| 1152 | req, | ||
| 1153 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, | ||
| 1154 | value, | ||
| 1155 | index, | ||
| 1156 | NULL, | ||
| 1157 | 0, | ||
| 1158 | 1000); | ||
| 1159 | } | ||
| 1160 | if (i < 0) { | ||
| 1161 | err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", | ||
| 1162 | proc, i); | ||
| 1163 | uvd->last_error = i; | ||
| 1164 | } | ||
| 1165 | return i; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | /* | ||
| 1169 | * ibmcam_calculate_fps() | ||
| 1170 | * | ||
| 1171 | * This procedure roughly calculates the real frame rate based | ||
| 1172 | * on FPS code (framerate=NNN option). Actual FPS differs | ||
| 1173 | * slightly depending on lighting conditions, so that actual frame | ||
| 1174 | * rate is determined by the camera. Since I don't know how to ask | ||
| 1175 | * the camera what FPS is now I have to use the FPS code instead. | ||
| 1176 | * | ||
| 1177 | * The FPS code is in range [0..6], 0 is slowest, 6 is fastest. | ||
| 1178 | * Corresponding real FPS should be in range [3..30] frames per second. | ||
| 1179 | * The conversion formula is obvious: | ||
| 1180 | * | ||
| 1181 | * real_fps = 3 + (fps_code * 4.5) | ||
| 1182 | * | ||
| 1183 | * History: | ||
| 1184 | * 1/18/00 Created. | ||
| 1185 | */ | ||
| 1186 | static int ibmcam_calculate_fps(struct uvd *uvd) | ||
| 1187 | { | ||
| 1188 | return 3 + framerate*4 + framerate/2; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | /* | ||
| 1192 | * ibmcam_send_FF_04_02() | ||
| 1193 | * | ||
| 1194 | * This procedure sends magic 3-command prefix to the camera. | ||
| 1195 | * The purpose of this prefix is not known. | ||
| 1196 | * | ||
| 1197 | * History: | ||
| 1198 | * 1/2/00 Created. | ||
| 1199 | */ | ||
| 1200 | static void ibmcam_send_FF_04_02(struct uvd *uvd) | ||
| 1201 | { | ||
| 1202 | ibmcam_veio(uvd, 0, 0x00FF, 0x0127); | ||
| 1203 | ibmcam_veio(uvd, 0, 0x0004, 0x0124); | ||
| 1204 | ibmcam_veio(uvd, 0, 0x0002, 0x0124); | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | static void ibmcam_send_00_04_06(struct uvd *uvd) | ||
| 1208 | { | ||
| 1209 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 1210 | ibmcam_veio(uvd, 0, 0x0004, 0x0124); | ||
| 1211 | ibmcam_veio(uvd, 0, 0x0006, 0x0124); | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x) | ||
| 1215 | { | ||
| 1216 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
| 1217 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x) | ||
| 1221 | { | ||
| 1222 | ibmcam_send_x_00(uvd, x); | ||
| 1223 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x) | ||
| 1227 | { | ||
| 1228 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
| 1229 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
| 1230 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
| 1231 | ibmcam_veio(uvd, 0, 0x0002, 0x0124); | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x) | ||
| 1235 | { | ||
| 1236 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
| 1237 | ibmcam_veio(uvd, 0, 0x0001, 0x0124); | ||
| 1238 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
| 1239 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x) | ||
| 1243 | { | ||
| 1244 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
| 1245 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
| 1246 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
| 1247 | ibmcam_veio(uvd, 0, 0x0002, 0x0124); | ||
| 1248 | ibmcam_veio(uvd, 0, 0x0001, 0x0124); | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x) | ||
| 1252 | { | ||
| 1253 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
| 1254 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
| 1255 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
| 1256 | ibmcam_veio(uvd, 0, 0x0002, 0x0124); | ||
| 1257 | ibmcam_veio(uvd, 0, 0x0008, 0x0124); | ||
| 1258 | ibmcam_veio(uvd, 0, 0x0001, 0x0124); | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val) | ||
| 1262 | { | ||
| 1263 | ibmcam_send_x_01_00_05(uvd, unknown_88); | ||
| 1264 | ibmcam_send_x_00_05(uvd, fkey); | ||
| 1265 | ibmcam_send_x_00_05_02_08_01(uvd, val); | ||
| 1266 | ibmcam_send_x_00_05(uvd, unknown_88); | ||
| 1267 | ibmcam_send_x_00_05_02_01(uvd, fkey); | ||
| 1268 | ibmcam_send_x_00_05(uvd, unknown_89); | ||
| 1269 | ibmcam_send_x_00(uvd, fkey); | ||
| 1270 | ibmcam_send_00_04_06(uvd); | ||
| 1271 | ibmcam_veio(uvd, 1, 0x0000, 0x0126); | ||
| 1272 | ibmcam_send_FF_04_02(uvd); | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val) | ||
| 1276 | { | ||
| 1277 | ibmcam_send_x_01_00_05 (uvd, unknown_88); | ||
| 1278 | ibmcam_send_x_00_05 (uvd, fkey); | ||
| 1279 | ibmcam_send_x_00_05_02 (uvd, val); | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | static void ibmcam_model2_Packet2(struct uvd *uvd) | ||
| 1283 | { | ||
| 1284 | ibmcam_veio(uvd, 0, 0x00ff, 0x012d); | ||
| 1285 | ibmcam_veio(uvd, 0, 0xfea3, 0x0124); | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2) | ||
| 1289 | { | ||
| 1290 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 1291 | ibmcam_veio(uvd, 0, 0x00ff, 0x012e); | ||
| 1292 | ibmcam_veio(uvd, 0, v1, 0x012f); | ||
| 1293 | ibmcam_veio(uvd, 0, 0x00ff, 0x0130); | ||
| 1294 | ibmcam_veio(uvd, 0, 0xc719, 0x0124); | ||
| 1295 | ibmcam_veio(uvd, 0, v2, 0x0127); | ||
| 1296 | |||
| 1297 | ibmcam_model2_Packet2(uvd); | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | /* | ||
| 1301 | * ibmcam_model3_Packet1() | ||
| 1302 | * | ||
| 1303 | * 00_0078_012d | ||
| 1304 | * 00_0097_012f | ||
| 1305 | * 00_d141_0124 | ||
| 1306 | * 00_0096_0127 | ||
| 1307 | * 00_fea8_0124 | ||
| 1308 | */ | ||
| 1309 | static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2) | ||
| 1310 | { | ||
| 1311 | ibmcam_veio(uvd, 0, 0x0078, 0x012d); | ||
| 1312 | ibmcam_veio(uvd, 0, v1, 0x012f); | ||
| 1313 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 1314 | ibmcam_veio(uvd, 0, v2, 0x0127); | ||
| 1315 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i) | ||
| 1319 | { | ||
| 1320 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 1321 | ibmcam_veio(uvd, 0, 0x0026, 0x012f); | ||
| 1322 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 1323 | ibmcam_veio(uvd, 0, i, 0x0127); | ||
| 1324 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 1325 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 1326 | ibmcam_veio(uvd, 0, 0x0038, 0x012d); | ||
| 1327 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
| 1328 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 1329 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 1330 | } | ||
| 1331 | |||
| 1332 | /* | ||
| 1333 | * ibmcam_adjust_contrast() | ||
| 1334 | * | ||
| 1335 | * The contrast value changes from 0 (high contrast) to 15 (low contrast). | ||
| 1336 | * This is in reverse to usual order of things (such as TV controls), so | ||
| 1337 | * we reverse it again here. | ||
| 1338 | * | ||
| 1339 | * TODO: we probably don't need to send the setup 5 times... | ||
| 1340 | * | ||
| 1341 | * History: | ||
| 1342 | * 1/2/00 Created. | ||
| 1343 | */ | ||
| 1344 | static void ibmcam_adjust_contrast(struct uvd *uvd) | ||
| 1345 | { | ||
| 1346 | unsigned char a_contrast = uvd->vpic.contrast >> 12; | ||
| 1347 | unsigned char new_contrast; | ||
| 1348 | |||
| 1349 | if (a_contrast >= 16) | ||
| 1350 | a_contrast = 15; | ||
| 1351 | new_contrast = 15 - a_contrast; | ||
| 1352 | if (new_contrast == uvd->vpic_old.contrast) | ||
| 1353 | return; | ||
| 1354 | uvd->vpic_old.contrast = new_contrast; | ||
| 1355 | switch (IBMCAM_T(uvd)->camera_model) { | ||
| 1356 | case IBMCAM_MODEL_1: | ||
| 1357 | { | ||
| 1358 | const int ntries = 5; | ||
| 1359 | int i; | ||
| 1360 | for (i=0; i < ntries; i++) { | ||
| 1361 | ibmcam_Packet_Format1(uvd, contrast_14, new_contrast); | ||
| 1362 | ibmcam_send_FF_04_02(uvd); | ||
| 1363 | } | ||
| 1364 | break; | ||
| 1365 | } | ||
| 1366 | case IBMCAM_MODEL_2: | ||
| 1367 | case IBMCAM_MODEL_4: | ||
| 1368 | /* Models 2, 4 do not have this control; implemented in software. */ | ||
| 1369 | break; | ||
| 1370 | case IBMCAM_MODEL_3: | ||
| 1371 | { /* Preset hardware values */ | ||
| 1372 | static const struct { | ||
| 1373 | unsigned short cv1; | ||
| 1374 | unsigned short cv2; | ||
| 1375 | unsigned short cv3; | ||
| 1376 | } cv[7] = { | ||
| 1377 | { 0x05, 0x05, 0x0f }, /* Minimum */ | ||
| 1378 | { 0x04, 0x04, 0x16 }, | ||
| 1379 | { 0x02, 0x03, 0x16 }, | ||
| 1380 | { 0x02, 0x08, 0x16 }, | ||
| 1381 | { 0x01, 0x0c, 0x16 }, | ||
| 1382 | { 0x01, 0x0e, 0x16 }, | ||
| 1383 | { 0x01, 0x10, 0x16 } /* Maximum */ | ||
| 1384 | }; | ||
| 1385 | int i = a_contrast / 2; | ||
| 1386 | RESTRICT_TO_RANGE(i, 0, 6); | ||
| 1387 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ | ||
| 1388 | ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1); | ||
| 1389 | ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2); | ||
| 1390 | ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3); | ||
| 1391 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
| 1392 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ | ||
| 1393 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
| 1394 | break; | ||
| 1395 | } | ||
| 1396 | default: | ||
| 1397 | break; | ||
| 1398 | } | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | /* | ||
| 1402 | * ibmcam_change_lighting_conditions() | ||
| 1403 | * | ||
| 1404 | * Camera model 1: | ||
| 1405 | * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low. | ||
| 1406 | * | ||
| 1407 | * Camera model 2: | ||
| 1408 | * We have 16 levels of lighting, 0 for bright light and up to 15 for | ||
| 1409 | * low light. But values above 5 or so are useless because camera is | ||
| 1410 | * not really capable to produce anything worth viewing at such light. | ||
| 1411 | * This setting may be altered only in certain camera state. | ||
| 1412 | * | ||
| 1413 | * Low lighting forces slower FPS. Lighting is set as a module parameter. | ||
| 1414 | * | ||
| 1415 | * History: | ||
| 1416 | * 1/5/00 Created. | ||
| 1417 | * 2/20/00 Added support for Model 2 cameras. | ||
| 1418 | */ | ||
| 1419 | static void ibmcam_change_lighting_conditions(struct uvd *uvd) | ||
| 1420 | { | ||
| 1421 | static const char proc[] = "ibmcam_change_lighting_conditions"; | ||
| 1422 | |||
| 1423 | if (debug > 0) | ||
| 1424 | info("%s: Set lighting to %hu.", proc, lighting); | ||
| 1425 | |||
| 1426 | switch (IBMCAM_T(uvd)->camera_model) { | ||
| 1427 | case IBMCAM_MODEL_1: | ||
| 1428 | { | ||
| 1429 | const int ntries = 5; | ||
| 1430 | int i; | ||
| 1431 | for (i=0; i < ntries; i++) | ||
| 1432 | ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting); | ||
| 1433 | break; | ||
| 1434 | } | ||
| 1435 | case IBMCAM_MODEL_2: | ||
| 1436 | #if 0 | ||
| 1437 | /* | ||
| 1438 | * This command apparently requires camera to be stopped. My | ||
| 1439 | * experiments showed that it -is- possible to alter the lighting | ||
| 1440 | * conditions setting "on the fly", but why bother? This setting does | ||
| 1441 | * not work reliably in all cases, so I decided simply to leave the | ||
| 1442 | * setting where Xirlink put it - in the camera setup phase. This code | ||
| 1443 | * is commented out because it does not work at -any- moment, so its | ||
| 1444 | * presence makes no sense. You may use it for experiments. | ||
| 1445 | */ | ||
| 1446 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop camera */ | ||
| 1447 | ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting); | ||
| 1448 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Start camera */ | ||
| 1449 | #endif | ||
| 1450 | break; | ||
| 1451 | case IBMCAM_MODEL_3: | ||
| 1452 | case IBMCAM_MODEL_4: | ||
| 1453 | default: | ||
| 1454 | break; | ||
| 1455 | } | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | /* | ||
| 1459 | * ibmcam_set_sharpness() | ||
| 1460 | * | ||
| 1461 | * Cameras model 1 have internal smoothing feature. It is controlled by value in | ||
| 1462 | * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess). | ||
| 1463 | * Recommended value is 4. Cameras model 2 do not have this feature at all. | ||
| 1464 | */ | ||
| 1465 | static void ibmcam_set_sharpness(struct uvd *uvd) | ||
| 1466 | { | ||
| 1467 | static const char proc[] = "ibmcam_set_sharpness"; | ||
| 1468 | |||
| 1469 | switch (IBMCAM_T(uvd)->camera_model) { | ||
| 1470 | case IBMCAM_MODEL_1: | ||
| 1471 | { | ||
| 1472 | static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a }; | ||
| 1473 | unsigned short i, sv; | ||
| 1474 | |||
| 1475 | RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); | ||
| 1476 | if (debug > 0) | ||
| 1477 | info("%s: Set sharpness to %hu.", proc, sharpness); | ||
| 1478 | |||
| 1479 | sv = sa[sharpness - SHARPNESS_MIN]; | ||
| 1480 | for (i=0; i < 2; i++) { | ||
| 1481 | ibmcam_send_x_01_00_05 (uvd, unknown_88); | ||
| 1482 | ibmcam_send_x_00_05 (uvd, sharp_13); | ||
| 1483 | ibmcam_send_x_00_05_02 (uvd, sv); | ||
| 1484 | } | ||
| 1485 | break; | ||
| 1486 | } | ||
| 1487 | case IBMCAM_MODEL_2: | ||
| 1488 | case IBMCAM_MODEL_4: | ||
| 1489 | /* Models 2, 4 do not have this control */ | ||
| 1490 | break; | ||
| 1491 | case IBMCAM_MODEL_3: | ||
| 1492 | { /* | ||
| 1493 | * "Use a table of magic numbers. | ||
| 1494 | * This setting doesn't really change much. | ||
| 1495 | * But that's how Windows does it." | ||
| 1496 | */ | ||
| 1497 | static const struct { | ||
| 1498 | unsigned short sv1; | ||
| 1499 | unsigned short sv2; | ||
| 1500 | unsigned short sv3; | ||
| 1501 | unsigned short sv4; | ||
| 1502 | } sv[7] = { | ||
| 1503 | { 0x00, 0x00, 0x05, 0x14 }, /* Smoothest */ | ||
| 1504 | { 0x01, 0x04, 0x05, 0x14 }, | ||
| 1505 | { 0x02, 0x04, 0x05, 0x14 }, | ||
| 1506 | { 0x03, 0x04, 0x05, 0x14 }, | ||
| 1507 | { 0x03, 0x05, 0x05, 0x14 }, | ||
| 1508 | { 0x03, 0x06, 0x05, 0x14 }, | ||
| 1509 | { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */ | ||
| 1510 | }; | ||
| 1511 | RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); | ||
| 1512 | RESTRICT_TO_RANGE(sharpness, 0, 6); | ||
| 1513 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ | ||
| 1514 | ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1); | ||
| 1515 | ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2); | ||
| 1516 | ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3); | ||
| 1517 | ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4); | ||
| 1518 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
| 1519 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ | ||
| 1520 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
| 1521 | ibmcam_veio(uvd, 0, 0x0001, 0x0113); | ||
| 1522 | break; | ||
| 1523 | } | ||
| 1524 | default: | ||
| 1525 | break; | ||
| 1526 | } | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | /* | ||
| 1530 | * ibmcam_set_brightness() | ||
| 1531 | * | ||
| 1532 | * This procedure changes brightness of the picture. | ||
| 1533 | */ | ||
| 1534 | static void ibmcam_set_brightness(struct uvd *uvd) | ||
| 1535 | { | ||
| 1536 | static const char proc[] = "ibmcam_set_brightness"; | ||
| 1537 | static const unsigned short n = 1; | ||
| 1538 | |||
| 1539 | if (debug > 0) | ||
| 1540 | info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness); | ||
| 1541 | |||
| 1542 | switch (IBMCAM_T(uvd)->camera_model) { | ||
| 1543 | case IBMCAM_MODEL_1: | ||
| 1544 | { | ||
| 1545 | unsigned short i, j, bv[3]; | ||
| 1546 | bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10; | ||
| 1547 | if (bv[0] == (uvd->vpic_old.brightness >> 10)) | ||
| 1548 | return; | ||
| 1549 | uvd->vpic_old.brightness = bv[0]; | ||
| 1550 | for (j=0; j < 3; j++) | ||
| 1551 | for (i=0; i < n; i++) | ||
| 1552 | ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]); | ||
| 1553 | break; | ||
| 1554 | } | ||
| 1555 | case IBMCAM_MODEL_2: | ||
| 1556 | { | ||
| 1557 | unsigned short i, j; | ||
| 1558 | i = uvd->vpic.brightness >> 12; /* 0 .. 15 */ | ||
| 1559 | j = 0x60 + i * ((0xee - 0x60) / 16); /* 0x60 .. 0xee or so */ | ||
| 1560 | if (uvd->vpic_old.brightness == j) | ||
| 1561 | break; | ||
| 1562 | uvd->vpic_old.brightness = j; | ||
| 1563 | ibmcam_model2_Packet1(uvd, mod2_brightness, j); | ||
| 1564 | break; | ||
| 1565 | } | ||
| 1566 | case IBMCAM_MODEL_3: | ||
| 1567 | { | ||
| 1568 | /* Model 3: Brightness range 'i' in [0x0C..0x3F] */ | ||
| 1569 | unsigned short i = | ||
| 1570 | 0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1))); | ||
| 1571 | RESTRICT_TO_RANGE(i, 0x0C, 0x3F); | ||
| 1572 | if (uvd->vpic_old.brightness == i) | ||
| 1573 | break; | ||
| 1574 | uvd->vpic_old.brightness = i; | ||
| 1575 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ | ||
| 1576 | ibmcam_model3_Packet1(uvd, 0x0036, i); | ||
| 1577 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
| 1578 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ | ||
| 1579 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
| 1580 | ibmcam_veio(uvd, 0, 0x0001, 0x0113); | ||
| 1581 | break; | ||
| 1582 | } | ||
| 1583 | case IBMCAM_MODEL_4: | ||
| 1584 | { | ||
| 1585 | /* Model 4: Brightness range 'i' in [0x04..0xb4] */ | ||
| 1586 | unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1))); | ||
| 1587 | RESTRICT_TO_RANGE(i, 0x04, 0xb4); | ||
| 1588 | if (uvd->vpic_old.brightness == i) | ||
| 1589 | break; | ||
| 1590 | uvd->vpic_old.brightness = i; | ||
| 1591 | ibmcam_model4_BrightnessPacket(uvd, i); | ||
| 1592 | break; | ||
| 1593 | } | ||
| 1594 | default: | ||
| 1595 | break; | ||
| 1596 | } | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | static void ibmcam_set_hue(struct uvd *uvd) | ||
| 1600 | { | ||
| 1601 | switch (IBMCAM_T(uvd)->camera_model) { | ||
| 1602 | case IBMCAM_MODEL_2: | ||
| 1603 | { | ||
| 1604 | unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */ | ||
| 1605 | if (uvd->vpic_old.hue == hue) | ||
| 1606 | return; | ||
| 1607 | uvd->vpic_old.hue = hue; | ||
| 1608 | ibmcam_model2_Packet1(uvd, mod2_hue, hue); | ||
| 1609 | /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */ | ||
| 1610 | break; | ||
| 1611 | } | ||
| 1612 | case IBMCAM_MODEL_3: | ||
| 1613 | { | ||
| 1614 | #if 0 /* This seems not to work. No problem, will fix programmatically */ | ||
| 1615 | unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1))); | ||
| 1616 | RESTRICT_TO_RANGE(hue, 0x05, 0x37); | ||
| 1617 | if (uvd->vpic_old.hue == hue) | ||
| 1618 | return; | ||
| 1619 | uvd->vpic_old.hue = hue; | ||
| 1620 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ | ||
| 1621 | ibmcam_model3_Packet1(uvd, 0x007e, hue); | ||
| 1622 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
| 1623 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ | ||
| 1624 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
| 1625 | ibmcam_veio(uvd, 0, 0x0001, 0x0113); | ||
| 1626 | #endif | ||
| 1627 | break; | ||
| 1628 | } | ||
| 1629 | case IBMCAM_MODEL_4: | ||
| 1630 | { | ||
| 1631 | unsigned short r_gain, g_gain, b_gain, hue; | ||
| 1632 | |||
| 1633 | /* | ||
| 1634 | * I am not sure r/g/b_gain variables exactly control gain | ||
| 1635 | * of those channels. Most likely they subtly change some | ||
| 1636 | * very internal image processing settings in the camera. | ||
| 1637 | * In any case, here is what they do, and feel free to tweak: | ||
| 1638 | * | ||
| 1639 | * r_gain: seriously affects red gain | ||
| 1640 | * g_gain: seriously affects green gain | ||
| 1641 | * b_gain: seriously affects blue gain | ||
| 1642 | * hue: changes average color from violet (0) to red (0xFF) | ||
| 1643 | * | ||
| 1644 | * These settings are preset for a decent white balance in | ||
| 1645 | * 320x240, 352x288 modes. Low-res modes exhibit higher contrast | ||
| 1646 | * and therefore may need different values here. | ||
| 1647 | */ | ||
| 1648 | hue = 20 + (uvd->vpic.hue >> 9); | ||
| 1649 | switch (uvd->videosize) { | ||
| 1650 | case VIDEOSIZE_128x96: | ||
| 1651 | r_gain = 90; | ||
| 1652 | g_gain = 166; | ||
| 1653 | b_gain = 175; | ||
| 1654 | break; | ||
| 1655 | case VIDEOSIZE_160x120: | ||
| 1656 | r_gain = 70; | ||
| 1657 | g_gain = 166; | ||
| 1658 | b_gain = 185; | ||
| 1659 | break; | ||
| 1660 | case VIDEOSIZE_176x144: | ||
| 1661 | r_gain = 160; | ||
| 1662 | g_gain = 175; | ||
| 1663 | b_gain = 185; | ||
| 1664 | break; | ||
| 1665 | default: | ||
| 1666 | r_gain = 120; | ||
| 1667 | g_gain = 166; | ||
| 1668 | b_gain = 175; | ||
| 1669 | break; | ||
| 1670 | } | ||
| 1671 | RESTRICT_TO_RANGE(hue, 1, 0x7f); | ||
| 1672 | |||
| 1673 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 1674 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
| 1675 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 1676 | ibmcam_veio(uvd, 0, g_gain, 0x0127); /* Green gain */ | ||
| 1677 | ibmcam_veio(uvd, 0, r_gain, 0x012e); /* Red gain */ | ||
| 1678 | ibmcam_veio(uvd, 0, b_gain, 0x0130); /* Blue gain */ | ||
| 1679 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 1680 | ibmcam_veio(uvd, 0, hue, 0x012d); /* Hue */ | ||
| 1681 | ibmcam_veio(uvd, 0, 0xf545, 0x0124); | ||
| 1682 | break; | ||
| 1683 | } | ||
| 1684 | default: | ||
| 1685 | break; | ||
| 1686 | } | ||
| 1687 | } | ||
| 1688 | |||
| 1689 | /* | ||
| 1690 | * ibmcam_adjust_picture() | ||
| 1691 | * | ||
| 1692 | * This procedure gets called from V4L interface to update picture settings. | ||
| 1693 | * Here we change brightness and contrast. | ||
| 1694 | */ | ||
| 1695 | static void ibmcam_adjust_picture(struct uvd *uvd) | ||
| 1696 | { | ||
| 1697 | ibmcam_adjust_contrast(uvd); | ||
| 1698 | ibmcam_set_brightness(uvd); | ||
| 1699 | ibmcam_set_hue(uvd); | ||
| 1700 | } | ||
| 1701 | |||
| 1702 | static int ibmcam_model1_setup(struct uvd *uvd) | ||
| 1703 | { | ||
| 1704 | const int ntries = 5; | ||
| 1705 | int i; | ||
| 1706 | |||
| 1707 | ibmcam_veio(uvd, 1, 0x00, 0x0128); | ||
| 1708 | ibmcam_veio(uvd, 1, 0x00, 0x0100); | ||
| 1709 | ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ | ||
| 1710 | ibmcam_veio(uvd, 1, 0x00, 0x0100); | ||
| 1711 | ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */ | ||
| 1712 | ibmcam_veio(uvd, 1, 0x00, 0x0100); | ||
| 1713 | ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ | ||
| 1714 | ibmcam_veio(uvd, 0, 0x01, 0x0108); | ||
| 1715 | |||
| 1716 | ibmcam_veio(uvd, 0, 0x03, 0x0112); | ||
| 1717 | ibmcam_veio(uvd, 1, 0x00, 0x0115); | ||
| 1718 | ibmcam_veio(uvd, 0, 0x06, 0x0115); | ||
| 1719 | ibmcam_veio(uvd, 1, 0x00, 0x0116); | ||
| 1720 | ibmcam_veio(uvd, 0, 0x44, 0x0116); | ||
| 1721 | ibmcam_veio(uvd, 1, 0x00, 0x0116); | ||
| 1722 | ibmcam_veio(uvd, 0, 0x40, 0x0116); | ||
| 1723 | ibmcam_veio(uvd, 1, 0x00, 0x0115); | ||
| 1724 | ibmcam_veio(uvd, 0, 0x0e, 0x0115); | ||
| 1725 | ibmcam_veio(uvd, 0, 0x19, 0x012c); | ||
| 1726 | |||
| 1727 | ibmcam_Packet_Format1(uvd, 0x00, 0x1e); | ||
| 1728 | ibmcam_Packet_Format1(uvd, 0x39, 0x0d); | ||
| 1729 | ibmcam_Packet_Format1(uvd, 0x39, 0x09); | ||
| 1730 | ibmcam_Packet_Format1(uvd, 0x3b, 0x00); | ||
| 1731 | ibmcam_Packet_Format1(uvd, 0x28, 0x22); | ||
| 1732 | ibmcam_Packet_Format1(uvd, light_27, 0); | ||
| 1733 | ibmcam_Packet_Format1(uvd, 0x2b, 0x1f); | ||
| 1734 | ibmcam_Packet_Format1(uvd, 0x39, 0x08); | ||
| 1735 | |||
| 1736 | for (i=0; i < ntries; i++) | ||
| 1737 | ibmcam_Packet_Format1(uvd, 0x2c, 0x00); | ||
| 1738 | |||
| 1739 | for (i=0; i < ntries; i++) | ||
| 1740 | ibmcam_Packet_Format1(uvd, 0x30, 0x14); | ||
| 1741 | |||
| 1742 | ibmcam_PacketFormat2(uvd, 0x39, 0x02); | ||
| 1743 | ibmcam_PacketFormat2(uvd, 0x01, 0xe1); | ||
| 1744 | ibmcam_PacketFormat2(uvd, 0x02, 0xcd); | ||
| 1745 | ibmcam_PacketFormat2(uvd, 0x03, 0xcd); | ||
| 1746 | ibmcam_PacketFormat2(uvd, 0x04, 0xfa); | ||
| 1747 | ibmcam_PacketFormat2(uvd, 0x3f, 0xff); | ||
| 1748 | ibmcam_PacketFormat2(uvd, 0x39, 0x00); | ||
| 1749 | |||
| 1750 | ibmcam_PacketFormat2(uvd, 0x39, 0x02); | ||
| 1751 | ibmcam_PacketFormat2(uvd, 0x0a, 0x37); | ||
| 1752 | ibmcam_PacketFormat2(uvd, 0x0b, 0xb8); | ||
| 1753 | ibmcam_PacketFormat2(uvd, 0x0c, 0xf3); | ||
| 1754 | ibmcam_PacketFormat2(uvd, 0x0d, 0xe3); | ||
| 1755 | ibmcam_PacketFormat2(uvd, 0x0e, 0x0d); | ||
| 1756 | ibmcam_PacketFormat2(uvd, 0x0f, 0xf2); | ||
| 1757 | ibmcam_PacketFormat2(uvd, 0x10, 0xd5); | ||
| 1758 | ibmcam_PacketFormat2(uvd, 0x11, 0xba); | ||
| 1759 | ibmcam_PacketFormat2(uvd, 0x12, 0x53); | ||
| 1760 | ibmcam_PacketFormat2(uvd, 0x3f, 0xff); | ||
| 1761 | ibmcam_PacketFormat2(uvd, 0x39, 0x00); | ||
| 1762 | |||
| 1763 | ibmcam_PacketFormat2(uvd, 0x39, 0x02); | ||
| 1764 | ibmcam_PacketFormat2(uvd, 0x16, 0x00); | ||
| 1765 | ibmcam_PacketFormat2(uvd, 0x17, 0x28); | ||
| 1766 | ibmcam_PacketFormat2(uvd, 0x18, 0x7d); | ||
| 1767 | ibmcam_PacketFormat2(uvd, 0x19, 0xbe); | ||
| 1768 | ibmcam_PacketFormat2(uvd, 0x3f, 0xff); | ||
| 1769 | ibmcam_PacketFormat2(uvd, 0x39, 0x00); | ||
| 1770 | |||
| 1771 | for (i=0; i < ntries; i++) | ||
| 1772 | ibmcam_Packet_Format1(uvd, 0x00, 0x18); | ||
| 1773 | for (i=0; i < ntries; i++) | ||
| 1774 | ibmcam_Packet_Format1(uvd, 0x13, 0x18); | ||
| 1775 | for (i=0; i < ntries; i++) | ||
| 1776 | ibmcam_Packet_Format1(uvd, 0x14, 0x06); | ||
| 1777 | |||
| 1778 | /* This is default brightness */ | ||
| 1779 | for (i=0; i < ntries; i++) | ||
| 1780 | ibmcam_Packet_Format1(uvd, 0x31, 0x37); | ||
| 1781 | for (i=0; i < ntries; i++) | ||
| 1782 | ibmcam_Packet_Format1(uvd, 0x32, 0x46); | ||
| 1783 | for (i=0; i < ntries; i++) | ||
| 1784 | ibmcam_Packet_Format1(uvd, 0x33, 0x55); | ||
| 1785 | |||
| 1786 | ibmcam_Packet_Format1(uvd, 0x2e, 0x04); | ||
| 1787 | for (i=0; i < ntries; i++) | ||
| 1788 | ibmcam_Packet_Format1(uvd, 0x2d, 0x04); | ||
| 1789 | for (i=0; i < ntries; i++) | ||
| 1790 | ibmcam_Packet_Format1(uvd, 0x29, 0x80); | ||
| 1791 | ibmcam_Packet_Format1(uvd, 0x2c, 0x01); | ||
| 1792 | ibmcam_Packet_Format1(uvd, 0x30, 0x17); | ||
| 1793 | ibmcam_Packet_Format1(uvd, 0x39, 0x08); | ||
| 1794 | for (i=0; i < ntries; i++) | ||
| 1795 | ibmcam_Packet_Format1(uvd, 0x34, 0x00); | ||
| 1796 | |||
| 1797 | ibmcam_veio(uvd, 0, 0x00, 0x0101); | ||
| 1798 | ibmcam_veio(uvd, 0, 0x00, 0x010a); | ||
| 1799 | |||
| 1800 | switch (uvd->videosize) { | ||
| 1801 | case VIDEOSIZE_128x96: | ||
| 1802 | ibmcam_veio(uvd, 0, 0x80, 0x0103); | ||
| 1803 | ibmcam_veio(uvd, 0, 0x60, 0x0105); | ||
| 1804 | ibmcam_veio(uvd, 0, 0x0c, 0x010b); | ||
| 1805 | ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ | ||
| 1806 | ibmcam_veio(uvd, 0, 0x0b, 0x011d); | ||
| 1807 | ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ | ||
| 1808 | ibmcam_veio(uvd, 0, 0x00, 0x0129); | ||
| 1809 | break; | ||
| 1810 | case VIDEOSIZE_176x144: | ||
| 1811 | ibmcam_veio(uvd, 0, 0xb0, 0x0103); | ||
| 1812 | ibmcam_veio(uvd, 0, 0x8f, 0x0105); | ||
| 1813 | ibmcam_veio(uvd, 0, 0x06, 0x010b); | ||
| 1814 | ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ | ||
| 1815 | ibmcam_veio(uvd, 0, 0x0d, 0x011d); | ||
| 1816 | ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ | ||
| 1817 | ibmcam_veio(uvd, 0, 0x03, 0x0129); | ||
| 1818 | break; | ||
| 1819 | case VIDEOSIZE_352x288: | ||
| 1820 | ibmcam_veio(uvd, 0, 0xb0, 0x0103); | ||
| 1821 | ibmcam_veio(uvd, 0, 0x90, 0x0105); | ||
| 1822 | ibmcam_veio(uvd, 0, 0x02, 0x010b); | ||
| 1823 | ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ | ||
| 1824 | ibmcam_veio(uvd, 0, 0x05, 0x011d); | ||
| 1825 | ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ | ||
| 1826 | ibmcam_veio(uvd, 0, 0x00, 0x0129); | ||
| 1827 | break; | ||
| 1828 | } | ||
| 1829 | |||
| 1830 | ibmcam_veio(uvd, 0, 0xff, 0x012b); | ||
| 1831 | |||
| 1832 | /* This is another brightness - don't know why */ | ||
| 1833 | for (i=0; i < ntries; i++) | ||
| 1834 | ibmcam_Packet_Format1(uvd, 0x31, 0xc3); | ||
| 1835 | for (i=0; i < ntries; i++) | ||
| 1836 | ibmcam_Packet_Format1(uvd, 0x32, 0xd2); | ||
| 1837 | for (i=0; i < ntries; i++) | ||
| 1838 | ibmcam_Packet_Format1(uvd, 0x33, 0xe1); | ||
| 1839 | |||
| 1840 | /* Default contrast */ | ||
| 1841 | for (i=0; i < ntries; i++) | ||
| 1842 | ibmcam_Packet_Format1(uvd, contrast_14, 0x0a); | ||
| 1843 | |||
| 1844 | /* Default sharpness */ | ||
| 1845 | for (i=0; i < 2; i++) | ||
| 1846 | ibmcam_PacketFormat2(uvd, sharp_13, 0x1a); /* Level 4 FIXME */ | ||
| 1847 | |||
| 1848 | /* Default lighting conditions */ | ||
| 1849 | ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */ | ||
| 1850 | |||
| 1851 | /* Assorted init */ | ||
| 1852 | |||
| 1853 | switch (uvd->videosize) { | ||
| 1854 | case VIDEOSIZE_128x96: | ||
| 1855 | ibmcam_Packet_Format1(uvd, 0x2b, 0x1e); | ||
| 1856 | ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ | ||
| 1857 | ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ | ||
| 1858 | ibmcam_veio(uvd, 0, 0x36, 0x0102); | ||
| 1859 | ibmcam_veio(uvd, 0, 0x1a, 0x0104); | ||
| 1860 | ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ | ||
| 1861 | ibmcam_veio(uvd, 0, 0x2b, 0x011c); | ||
| 1862 | ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ | ||
| 1863 | #if 0 | ||
| 1864 | ibmcam_veio(uvd, 0, 0x00, 0x0106); | ||
| 1865 | ibmcam_veio(uvd, 0, 0x38, 0x0107); | ||
| 1866 | #else | ||
| 1867 | ibmcam_veio(uvd, 0, 0x02, 0x0106); | ||
| 1868 | ibmcam_veio(uvd, 0, 0x2a, 0x0107); | ||
| 1869 | #endif | ||
| 1870 | break; | ||
| 1871 | case VIDEOSIZE_176x144: | ||
| 1872 | ibmcam_Packet_Format1(uvd, 0x2b, 0x1e); | ||
| 1873 | ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ | ||
| 1874 | ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ | ||
| 1875 | ibmcam_veio(uvd, 0, 0x04, 0x0102); | ||
| 1876 | ibmcam_veio(uvd, 0, 0x02, 0x0104); | ||
| 1877 | ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ | ||
| 1878 | ibmcam_veio(uvd, 0, 0x2b, 0x011c); | ||
| 1879 | ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ | ||
| 1880 | ibmcam_veio(uvd, 0, 0x01, 0x0106); | ||
| 1881 | ibmcam_veio(uvd, 0, 0xca, 0x0107); | ||
| 1882 | break; | ||
| 1883 | case VIDEOSIZE_352x288: | ||
| 1884 | ibmcam_Packet_Format1(uvd, 0x2b, 0x1f); | ||
| 1885 | ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ | ||
| 1886 | ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ | ||
| 1887 | ibmcam_veio(uvd, 0, 0x08, 0x0102); | ||
| 1888 | ibmcam_veio(uvd, 0, 0x01, 0x0104); | ||
| 1889 | ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ | ||
| 1890 | ibmcam_veio(uvd, 0, 0x2f, 0x011c); | ||
| 1891 | ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ | ||
| 1892 | ibmcam_veio(uvd, 0, 0x03, 0x0106); | ||
| 1893 | ibmcam_veio(uvd, 0, 0xf6, 0x0107); | ||
| 1894 | break; | ||
| 1895 | } | ||
| 1896 | return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT); | ||
| 1897 | } | ||
| 1898 | |||
| 1899 | static int ibmcam_model2_setup(struct uvd *uvd) | ||
| 1900 | { | ||
| 1901 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */ | ||
| 1902 | ibmcam_veio(uvd, 1, 0x0000, 0x0116); | ||
| 1903 | ibmcam_veio(uvd, 0, 0x0060, 0x0116); | ||
| 1904 | ibmcam_veio(uvd, 0, 0x0002, 0x0112); | ||
| 1905 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
| 1906 | ibmcam_veio(uvd, 0, 0x0008, 0x012b); | ||
| 1907 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
| 1908 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
| 1909 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
| 1910 | switch (uvd->videosize) { | ||
| 1911 | case VIDEOSIZE_176x144: | ||
| 1912 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ | ||
| 1913 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ | ||
| 1914 | ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ | ||
| 1915 | ibmcam_veio(uvd, 0, 0x00b9, 0x010a); /* Unique to this mode */ | ||
| 1916 | ibmcam_veio(uvd, 0, 0x0038, 0x0119); /* Unique to this mode */ | ||
| 1917 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ | ||
| 1918 | ibmcam_veio(uvd, 0, 0x0090, 0x0107); /* Unique to every mode*/ | ||
| 1919 | break; | ||
| 1920 | case VIDEOSIZE_320x240: | ||
| 1921 | ibmcam_veio(uvd, 0, 0x0028, 0x0103); /* Unique to this mode */ | ||
| 1922 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ | ||
| 1923 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ | ||
| 1924 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ | ||
| 1925 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ | ||
| 1926 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ | ||
| 1927 | ibmcam_veio(uvd, 0, 0x0098, 0x0107); /* Unique to every mode*/ | ||
| 1928 | break; | ||
| 1929 | case VIDEOSIZE_352x240: | ||
| 1930 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ | ||
| 1931 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ | ||
| 1932 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ | ||
| 1933 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ | ||
| 1934 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ | ||
| 1935 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ | ||
| 1936 | ibmcam_veio(uvd, 0, 0x00da, 0x0107); /* Unique to every mode*/ | ||
| 1937 | break; | ||
| 1938 | case VIDEOSIZE_352x288: | ||
| 1939 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ | ||
| 1940 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ | ||
| 1941 | ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ | ||
| 1942 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ | ||
| 1943 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ | ||
| 1944 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ | ||
| 1945 | ibmcam_veio(uvd, 0, 0x00fe, 0x0107); /* Unique to every mode*/ | ||
| 1946 | break; | ||
| 1947 | } | ||
| 1948 | return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT); | ||
| 1949 | } | ||
| 1950 | |||
| 1951 | /* | ||
| 1952 | * ibmcam_model1_setup_after_video_if() | ||
| 1953 | * | ||
| 1954 | * This code adds finishing touches to the video data interface. | ||
| 1955 | * Here we configure the frame rate and turn on the LED. | ||
| 1956 | */ | ||
| 1957 | static void ibmcam_model1_setup_after_video_if(struct uvd *uvd) | ||
| 1958 | { | ||
| 1959 | unsigned short internal_frame_rate; | ||
| 1960 | |||
| 1961 | RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX); | ||
| 1962 | internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */ | ||
| 1963 | ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ | ||
| 1964 | ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111); | ||
| 1965 | ibmcam_veio(uvd, 0, 0x01, 0x0114); | ||
| 1966 | ibmcam_veio(uvd, 0, 0xc0, 0x010c); | ||
| 1967 | } | ||
| 1968 | |||
| 1969 | static void ibmcam_model2_setup_after_video_if(struct uvd *uvd) | ||
| 1970 | { | ||
| 1971 | unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb; | ||
| 1972 | |||
| 1973 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */ | ||
| 1974 | |||
| 1975 | switch (uvd->videosize) { | ||
| 1976 | case VIDEOSIZE_176x144: | ||
| 1977 | ibmcam_veio(uvd, 0, 0x0050, 0x0111); | ||
| 1978 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
| 1979 | break; | ||
| 1980 | case VIDEOSIZE_320x240: | ||
| 1981 | case VIDEOSIZE_352x240: | ||
| 1982 | case VIDEOSIZE_352x288: | ||
| 1983 | ibmcam_veio(uvd, 0, 0x0040, 0x0111); | ||
| 1984 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
| 1985 | break; | ||
| 1986 | } | ||
| 1987 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
| 1988 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
| 1989 | |||
| 1990 | /* | ||
| 1991 | * Hardware settings, may affect CMOS sensor; not user controls! | ||
| 1992 | * ------------------------------------------------------------- | ||
| 1993 | * 0x0004: no effect | ||
| 1994 | * 0x0006: hardware effect | ||
| 1995 | * 0x0008: no effect | ||
| 1996 | * 0x000a: stops video stream, probably important h/w setting | ||
| 1997 | * 0x000c: changes color in hardware manner (not user setting) | ||
| 1998 | * 0x0012: changes number of colors (does not affect speed) | ||
| 1999 | * 0x002a: no effect | ||
| 2000 | * 0x002c: hardware setting (related to scan lines) | ||
| 2001 | * 0x002e: stops video stream, probably important h/w setting | ||
| 2002 | */ | ||
| 2003 | ibmcam_model2_Packet1(uvd, 0x000a, 0x005c); | ||
| 2004 | ibmcam_model2_Packet1(uvd, 0x0004, 0x0000); | ||
| 2005 | ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb); | ||
| 2006 | ibmcam_model2_Packet1(uvd, 0x0008, 0x0000); | ||
| 2007 | ibmcam_model2_Packet1(uvd, 0x000c, 0x0009); | ||
| 2008 | ibmcam_model2_Packet1(uvd, 0x0012, 0x000a); | ||
| 2009 | ibmcam_model2_Packet1(uvd, 0x002a, 0x0000); | ||
| 2010 | ibmcam_model2_Packet1(uvd, 0x002c, 0x0000); | ||
| 2011 | ibmcam_model2_Packet1(uvd, 0x002e, 0x0008); | ||
| 2012 | |||
| 2013 | /* | ||
| 2014 | * Function 0x0030 pops up all over the place. Apparently | ||
| 2015 | * it is a hardware control register, with every bit assigned to | ||
| 2016 | * do something. | ||
| 2017 | */ | ||
| 2018 | ibmcam_model2_Packet1(uvd, 0x0030, 0x0000); | ||
| 2019 | |||
| 2020 | /* | ||
| 2021 | * Magic control of CMOS sensor. Only lower values like | ||
| 2022 | * 0-3 work, and picture shifts left or right. Don't change. | ||
| 2023 | */ | ||
| 2024 | switch (uvd->videosize) { | ||
| 2025 | case VIDEOSIZE_176x144: | ||
| 2026 | ibmcam_model2_Packet1(uvd, 0x0014, 0x0002); | ||
| 2027 | ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */ | ||
| 2028 | ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */ | ||
| 2029 | break; | ||
| 2030 | case VIDEOSIZE_320x240: | ||
| 2031 | ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); | ||
| 2032 | ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */ | ||
| 2033 | ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */ | ||
| 2034 | break; | ||
| 2035 | case VIDEOSIZE_352x240: | ||
| 2036 | /* This mode doesn't work as Windows programs it; changed to work */ | ||
| 2037 | ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */ | ||
| 2038 | ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */ | ||
| 2039 | ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */ | ||
| 2040 | break; | ||
| 2041 | case VIDEOSIZE_352x288: | ||
| 2042 | ibmcam_model2_Packet1(uvd, 0x0014, 0x0003); | ||
| 2043 | ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */ | ||
| 2044 | ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */ | ||
| 2045 | break; | ||
| 2046 | } | ||
| 2047 | |||
| 2048 | ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a); | ||
| 2049 | |||
| 2050 | /* | ||
| 2051 | * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest). | ||
| 2052 | * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the | ||
| 2053 | * slowest setting. However for all practical reasons high settings make no | ||
| 2054 | * sense because USB is not fast enough to support high FPS. Be aware that | ||
| 2055 | * the picture datastream will be severely disrupted if you ask for | ||
| 2056 | * frame rate faster than allowed for the video size - see below: | ||
| 2057 | * | ||
| 2058 | * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz): | ||
| 2059 | * ----------------------------------------------------------------- | ||
| 2060 | * 176x144: [6..31] | ||
| 2061 | * 320x240: [8..31] | ||
| 2062 | * 352x240: [10..31] | ||
| 2063 | * 352x288: [16..31] I have to raise lower threshold for stability... | ||
| 2064 | * | ||
| 2065 | * As usual, slower FPS provides better sensitivity. | ||
| 2066 | */ | ||
| 2067 | { | ||
| 2068 | short hw_fps=31, i_framerate; | ||
| 2069 | |||
| 2070 | RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX); | ||
| 2071 | i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN; | ||
| 2072 | switch (uvd->videosize) { | ||
| 2073 | case VIDEOSIZE_176x144: | ||
| 2074 | hw_fps = 6 + i_framerate*4; | ||
| 2075 | break; | ||
| 2076 | case VIDEOSIZE_320x240: | ||
| 2077 | hw_fps = 8 + i_framerate*3; | ||
| 2078 | break; | ||
| 2079 | case VIDEOSIZE_352x240: | ||
| 2080 | hw_fps = 10 + i_framerate*2; | ||
| 2081 | break; | ||
| 2082 | case VIDEOSIZE_352x288: | ||
| 2083 | hw_fps = 28 + i_framerate/2; | ||
| 2084 | break; | ||
| 2085 | } | ||
| 2086 | if (uvd->debug > 0) | ||
| 2087 | info("Framerate (hardware): %hd.", hw_fps); | ||
| 2088 | RESTRICT_TO_RANGE(hw_fps, 0, 31); | ||
| 2089 | ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps); | ||
| 2090 | } | ||
| 2091 | |||
| 2092 | /* | ||
| 2093 | * This setting does not visibly affect pictures; left it here | ||
| 2094 | * because it was present in Windows USB data stream. This function | ||
| 2095 | * does not allow arbitrary values and apparently is a bit mask, to | ||
| 2096 | * be activated only at appropriate time. Don't change it randomly! | ||
| 2097 | */ | ||
| 2098 | switch (uvd->videosize) { | ||
| 2099 | case VIDEOSIZE_176x144: | ||
| 2100 | ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2); | ||
| 2101 | break; | ||
| 2102 | case VIDEOSIZE_320x240: | ||
| 2103 | ibmcam_model2_Packet1(uvd, 0x0026, 0x0044); | ||
| 2104 | break; | ||
| 2105 | case VIDEOSIZE_352x240: | ||
| 2106 | ibmcam_model2_Packet1(uvd, 0x0026, 0x0046); | ||
| 2107 | break; | ||
| 2108 | case VIDEOSIZE_352x288: | ||
| 2109 | ibmcam_model2_Packet1(uvd, 0x0026, 0x0048); | ||
| 2110 | break; | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting); | ||
| 2114 | |||
| 2115 | if (init_model2_rg2 >= 0) { | ||
| 2116 | RESTRICT_TO_RANGE(init_model2_rg2, 0, 255); | ||
| 2117 | setup_model2_rg2 = init_model2_rg2; | ||
| 2118 | } else | ||
| 2119 | setup_model2_rg2 = 0x002f; | ||
| 2120 | |||
| 2121 | if (init_model2_sat >= 0) { | ||
| 2122 | RESTRICT_TO_RANGE(init_model2_sat, 0, 255); | ||
| 2123 | setup_model2_sat = init_model2_sat; | ||
| 2124 | } else | ||
| 2125 | setup_model2_sat = 0x0034; | ||
| 2126 | |||
| 2127 | if (init_model2_yb >= 0) { | ||
| 2128 | RESTRICT_TO_RANGE(init_model2_yb, 0, 255); | ||
| 2129 | setup_model2_yb = init_model2_yb; | ||
| 2130 | } else | ||
| 2131 | setup_model2_yb = 0x00a0; | ||
| 2132 | |||
| 2133 | ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2); | ||
| 2134 | ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat); | ||
| 2135 | ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb); | ||
| 2136 | ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */; | ||
| 2137 | |||
| 2138 | /* Hardware control command */ | ||
| 2139 | ibmcam_model2_Packet1(uvd, 0x0030, 0x0004); | ||
| 2140 | |||
| 2141 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go camera, go! */ | ||
| 2142 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
| 2143 | } | ||
| 2144 | |||
| 2145 | static void ibmcam_model4_setup_after_video_if(struct uvd *uvd) | ||
| 2146 | { | ||
| 2147 | switch (uvd->videosize) { | ||
| 2148 | case VIDEOSIZE_128x96: | ||
| 2149 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
| 2150 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
| 2151 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
| 2152 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
| 2153 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
| 2154 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
| 2155 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
| 2156 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
| 2157 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2158 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2159 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2160 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2161 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2162 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2163 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
| 2164 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2165 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
| 2166 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2167 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2168 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
| 2169 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2170 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2171 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
| 2172 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
| 2173 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2174 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2175 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2176 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
| 2177 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
| 2178 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2179 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2180 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
| 2181 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2182 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
| 2183 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2184 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2185 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
| 2186 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
| 2187 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2188 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2189 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2190 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
| 2191 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2192 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2193 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2194 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); | ||
| 2195 | ibmcam_veio(uvd, 0, 0x00d2, 0x0107); | ||
| 2196 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
| 2197 | ibmcam_veio(uvd, 0, 0x005e, 0x0107); | ||
| 2198 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
| 2199 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
| 2200 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); | ||
| 2201 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
| 2202 | ibmcam_veio(uvd, 0, 0x0028, 0x0103); | ||
| 2203 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
| 2204 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); | ||
| 2205 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2206 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
| 2207 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2208 | ibmcam_veio(uvd, 0, 0x000a, 0x0127); | ||
| 2209 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2210 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2211 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
| 2212 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
| 2213 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2214 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
| 2215 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
| 2216 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
| 2217 | ibmcam_veio(uvd, 0, 0x005a, 0x012d); | ||
| 2218 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
| 2219 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
| 2220 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
| 2221 | ibmcam_veio(uvd, 0, 0x0043, 0x0130); | ||
| 2222 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2223 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2224 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2225 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
| 2226 | ibmcam_veio(uvd, 0, 0x00eb, 0x012e); | ||
| 2227 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2228 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2229 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
| 2230 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2231 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2232 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2233 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2234 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
| 2235 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
| 2236 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2237 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2238 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2239 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
| 2240 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2241 | ibmcam_veio(uvd, 0, 0x0017, 0x0127); | ||
| 2242 | ibmcam_veio(uvd, 0, 0x0013, 0x012e); | ||
| 2243 | ibmcam_veio(uvd, 0, 0x0031, 0x0130); | ||
| 2244 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2245 | ibmcam_veio(uvd, 0, 0x0017, 0x012d); | ||
| 2246 | ibmcam_veio(uvd, 0, 0x0078, 0x012f); | ||
| 2247 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2248 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2249 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2250 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2251 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2252 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2253 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
| 2254 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2255 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
| 2256 | break; | ||
| 2257 | case VIDEOSIZE_160x120: | ||
| 2258 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
| 2259 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
| 2260 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
| 2261 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
| 2262 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
| 2263 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
| 2264 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
| 2265 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
| 2266 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2267 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2268 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2269 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2270 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2271 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2272 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
| 2273 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2274 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
| 2275 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2276 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2277 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
| 2278 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2279 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2280 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
| 2281 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
| 2282 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2283 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2284 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2285 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
| 2286 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
| 2287 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2288 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2289 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
| 2290 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2291 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
| 2292 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2293 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2294 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
| 2295 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
| 2296 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2297 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2298 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2299 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
| 2300 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2301 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2302 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2303 | ibmcam_veio(uvd, 0, 0x0038, 0x0119); | ||
| 2304 | ibmcam_veio(uvd, 0, 0x00d8, 0x0107); | ||
| 2305 | ibmcam_veio(uvd, 0, 0x0002, 0x0106); | ||
| 2306 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
| 2307 | ibmcam_veio(uvd, 0, 0x00b9, 0x010a); | ||
| 2308 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
| 2309 | ibmcam_veio(uvd, 0, 0x0028, 0x0103); | ||
| 2310 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
| 2311 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); | ||
| 2312 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2313 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
| 2314 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2315 | ibmcam_veio(uvd, 0, 0x000b, 0x0127); | ||
| 2316 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2317 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2318 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
| 2319 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
| 2320 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2321 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
| 2322 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
| 2323 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
| 2324 | ibmcam_veio(uvd, 0, 0x005a, 0x012d); | ||
| 2325 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
| 2326 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
| 2327 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
| 2328 | ibmcam_veio(uvd, 0, 0x0043, 0x0130); | ||
| 2329 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2330 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2331 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2332 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
| 2333 | ibmcam_veio(uvd, 0, 0x00c7, 0x012e); | ||
| 2334 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2335 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2336 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
| 2337 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2338 | ibmcam_veio(uvd, 0, 0x0025, 0x0127); | ||
| 2339 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2340 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2341 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
| 2342 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
| 2343 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2344 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2345 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2346 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
| 2347 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2348 | ibmcam_veio(uvd, 0, 0x0048, 0x0127); | ||
| 2349 | ibmcam_veio(uvd, 0, 0x0035, 0x012e); | ||
| 2350 | ibmcam_veio(uvd, 0, 0x00d0, 0x0130); | ||
| 2351 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2352 | ibmcam_veio(uvd, 0, 0x0048, 0x012d); | ||
| 2353 | ibmcam_veio(uvd, 0, 0x0090, 0x012f); | ||
| 2354 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2355 | ibmcam_veio(uvd, 0, 0x0001, 0x0127); | ||
| 2356 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2357 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2358 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2359 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2360 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
| 2361 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2362 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
| 2363 | break; | ||
| 2364 | case VIDEOSIZE_176x144: | ||
| 2365 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
| 2366 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
| 2367 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
| 2368 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
| 2369 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
| 2370 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
| 2371 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
| 2372 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
| 2373 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2374 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2375 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2376 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2377 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2378 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2379 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
| 2380 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2381 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
| 2382 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2383 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2384 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
| 2385 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2386 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2387 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
| 2388 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
| 2389 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2390 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2391 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2392 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
| 2393 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
| 2394 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2395 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2396 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
| 2397 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2398 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
| 2399 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2400 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2401 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
| 2402 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
| 2403 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2404 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2405 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2406 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
| 2407 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2408 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2409 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2410 | ibmcam_veio(uvd, 0, 0x0038, 0x0119); | ||
| 2411 | ibmcam_veio(uvd, 0, 0x00d6, 0x0107); | ||
| 2412 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
| 2413 | ibmcam_veio(uvd, 0, 0x0018, 0x0107); | ||
| 2414 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
| 2415 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
| 2416 | ibmcam_veio(uvd, 0, 0x00b9, 0x010a); | ||
| 2417 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
| 2418 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); | ||
| 2419 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
| 2420 | ibmcam_veio(uvd, 0, 0x0024, 0x0105); | ||
| 2421 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2422 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
| 2423 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2424 | ibmcam_veio(uvd, 0, 0x0007, 0x0127); | ||
| 2425 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2426 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2427 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
| 2428 | ibmcam_veio(uvd, 0, 0x0001, 0x012f); | ||
| 2429 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2430 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
| 2431 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
| 2432 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
| 2433 | ibmcam_veio(uvd, 0, 0x005e, 0x012d); | ||
| 2434 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
| 2435 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
| 2436 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
| 2437 | ibmcam_veio(uvd, 0, 0x0049, 0x0130); | ||
| 2438 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2439 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2440 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2441 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
| 2442 | ibmcam_veio(uvd, 0, 0x00c7, 0x012e); | ||
| 2443 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2444 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2445 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
| 2446 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2447 | ibmcam_veio(uvd, 0, 0x0028, 0x0127); | ||
| 2448 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2449 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2450 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
| 2451 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
| 2452 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2453 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2454 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2455 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
| 2456 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2457 | ibmcam_veio(uvd, 0, 0x0010, 0x0127); | ||
| 2458 | ibmcam_veio(uvd, 0, 0x0013, 0x012e); | ||
| 2459 | ibmcam_veio(uvd, 0, 0x002a, 0x0130); | ||
| 2460 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2461 | ibmcam_veio(uvd, 0, 0x0010, 0x012d); | ||
| 2462 | ibmcam_veio(uvd, 0, 0x006d, 0x012f); | ||
| 2463 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2464 | ibmcam_veio(uvd, 0, 0x0001, 0x0127); | ||
| 2465 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2466 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2467 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2468 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2469 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
| 2470 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2471 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
| 2472 | break; | ||
| 2473 | case VIDEOSIZE_320x240: | ||
| 2474 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
| 2475 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
| 2476 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
| 2477 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
| 2478 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
| 2479 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
| 2480 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
| 2481 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
| 2482 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2483 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2484 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2485 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2486 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2487 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2488 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
| 2489 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2490 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
| 2491 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2492 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2493 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
| 2494 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2495 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2496 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
| 2497 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
| 2498 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2499 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2500 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2501 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
| 2502 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
| 2503 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2504 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2505 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
| 2506 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2507 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
| 2508 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2509 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2510 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
| 2511 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
| 2512 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2513 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2514 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2515 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
| 2516 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2517 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2518 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2519 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); | ||
| 2520 | ibmcam_veio(uvd, 0, 0x00d2, 0x0107); | ||
| 2521 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
| 2522 | ibmcam_veio(uvd, 0, 0x005e, 0x0107); | ||
| 2523 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
| 2524 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
| 2525 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); | ||
| 2526 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
| 2527 | ibmcam_veio(uvd, 0, 0x0028, 0x0103); | ||
| 2528 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
| 2529 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); | ||
| 2530 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2531 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
| 2532 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2533 | ibmcam_veio(uvd, 0, 0x000a, 0x0127); | ||
| 2534 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2535 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2536 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
| 2537 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
| 2538 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2539 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
| 2540 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
| 2541 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
| 2542 | ibmcam_veio(uvd, 0, 0x005a, 0x012d); | ||
| 2543 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
| 2544 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
| 2545 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
| 2546 | ibmcam_veio(uvd, 0, 0x0043, 0x0130); | ||
| 2547 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2548 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2549 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2550 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
| 2551 | ibmcam_veio(uvd, 0, 0x00eb, 0x012e); | ||
| 2552 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2553 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2554 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
| 2555 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2556 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2557 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2558 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2559 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
| 2560 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
| 2561 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2562 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2563 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2564 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
| 2565 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2566 | ibmcam_veio(uvd, 0, 0x0017, 0x0127); | ||
| 2567 | ibmcam_veio(uvd, 0, 0x0013, 0x012e); | ||
| 2568 | ibmcam_veio(uvd, 0, 0x0031, 0x0130); | ||
| 2569 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2570 | ibmcam_veio(uvd, 0, 0x0017, 0x012d); | ||
| 2571 | ibmcam_veio(uvd, 0, 0x0078, 0x012f); | ||
| 2572 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2573 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2574 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2575 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2576 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2577 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2578 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
| 2579 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2580 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
| 2581 | break; | ||
| 2582 | case VIDEOSIZE_352x288: | ||
| 2583 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
| 2584 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
| 2585 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
| 2586 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
| 2587 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
| 2588 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
| 2589 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
| 2590 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
| 2591 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2592 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2593 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2594 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2595 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2596 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2597 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
| 2598 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2599 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
| 2600 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2601 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2602 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
| 2603 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2604 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2605 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
| 2606 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
| 2607 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2608 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2609 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2610 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
| 2611 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
| 2612 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2613 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2614 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
| 2615 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2616 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
| 2617 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2618 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2619 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
| 2620 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
| 2621 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2622 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2623 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2624 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
| 2625 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2626 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2627 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2628 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); | ||
| 2629 | ibmcam_veio(uvd, 0, 0x00f2, 0x0107); | ||
| 2630 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
| 2631 | ibmcam_veio(uvd, 0, 0x008c, 0x0107); | ||
| 2632 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
| 2633 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
| 2634 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); | ||
| 2635 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
| 2636 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); | ||
| 2637 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
| 2638 | ibmcam_veio(uvd, 0, 0x0024, 0x0105); | ||
| 2639 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2640 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
| 2641 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2642 | ibmcam_veio(uvd, 0, 0x0006, 0x0127); | ||
| 2643 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2644 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2645 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
| 2646 | ibmcam_veio(uvd, 0, 0x0002, 0x012f); | ||
| 2647 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2648 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
| 2649 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
| 2650 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
| 2651 | ibmcam_veio(uvd, 0, 0x005e, 0x012d); | ||
| 2652 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
| 2653 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
| 2654 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
| 2655 | ibmcam_veio(uvd, 0, 0x0049, 0x0130); | ||
| 2656 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2657 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
| 2658 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
| 2659 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
| 2660 | ibmcam_veio(uvd, 0, 0x00cf, 0x012e); | ||
| 2661 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
| 2662 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2663 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
| 2664 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2665 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2666 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
| 2667 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
| 2668 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
| 2669 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
| 2670 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2671 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
| 2672 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2673 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
| 2674 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2675 | ibmcam_veio(uvd, 0, 0x0010, 0x0127); | ||
| 2676 | ibmcam_veio(uvd, 0, 0x0013, 0x012e); | ||
| 2677 | ibmcam_veio(uvd, 0, 0x0025, 0x0130); | ||
| 2678 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
| 2679 | ibmcam_veio(uvd, 0, 0x0010, 0x012d); | ||
| 2680 | ibmcam_veio(uvd, 0, 0x0048, 0x012f); | ||
| 2681 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
| 2682 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
| 2683 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2684 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
| 2685 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
| 2686 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
| 2687 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
| 2688 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
| 2689 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
| 2690 | break; | ||
| 2691 | } | ||
| 2692 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
| 2693 | } | ||
| 2694 | |||
| 2695 | static void ibmcam_model3_setup_after_video_if(struct uvd *uvd) | ||
| 2696 | { | ||
| 2697 | int i; | ||
| 2698 | /* | ||
| 2699 | * 01.01.08 - Added for RCA video in support -LO | ||
| 2700 | * This struct is used to init the Model3 cam to use the RCA video in port | ||
| 2701 | * instead of the CCD sensor. | ||
| 2702 | */ | ||
| 2703 | static const struct struct_initData initData[] = { | ||
| 2704 | {0, 0x0000, 0x010c}, | ||
| 2705 | {0, 0x0006, 0x012c}, | ||
| 2706 | {0, 0x0078, 0x012d}, | ||
| 2707 | {0, 0x0046, 0x012f}, | ||
| 2708 | {0, 0xd141, 0x0124}, | ||
| 2709 | {0, 0x0000, 0x0127}, | ||
| 2710 | {0, 0xfea8, 0x0124}, | ||
| 2711 | {1, 0x0000, 0x0116}, | ||
| 2712 | {0, 0x0064, 0x0116}, | ||
| 2713 | {1, 0x0000, 0x0115}, | ||
| 2714 | {0, 0x0003, 0x0115}, | ||
| 2715 | {0, 0x0008, 0x0123}, | ||
| 2716 | {0, 0x0000, 0x0117}, | ||
| 2717 | {0, 0x0000, 0x0112}, | ||
| 2718 | {0, 0x0080, 0x0100}, | ||
| 2719 | {0, 0x0000, 0x0100}, | ||
| 2720 | {1, 0x0000, 0x0116}, | ||
| 2721 | {0, 0x0060, 0x0116}, | ||
| 2722 | {0, 0x0002, 0x0112}, | ||
| 2723 | {0, 0x0000, 0x0123}, | ||
| 2724 | {0, 0x0001, 0x0117}, | ||
| 2725 | {0, 0x0040, 0x0108}, | ||
| 2726 | {0, 0x0019, 0x012c}, | ||
| 2727 | {0, 0x0040, 0x0116}, | ||
| 2728 | {0, 0x000a, 0x0115}, | ||
| 2729 | {0, 0x000b, 0x0115}, | ||
| 2730 | {0, 0x0078, 0x012d}, | ||
| 2731 | {0, 0x0046, 0x012f}, | ||
| 2732 | {0, 0xd141, 0x0124}, | ||
| 2733 | {0, 0x0000, 0x0127}, | ||
| 2734 | {0, 0xfea8, 0x0124}, | ||
| 2735 | {0, 0x0064, 0x0116}, | ||
| 2736 | {0, 0x0000, 0x0115}, | ||
| 2737 | {0, 0x0001, 0x0115}, | ||
| 2738 | {0, 0xffff, 0x0124}, | ||
| 2739 | {0, 0xfff9, 0x0124}, | ||
| 2740 | {0, 0x0086, 0x0127}, | ||
| 2741 | {0, 0xfff8, 0x0124}, | ||
| 2742 | {0, 0xfffd, 0x0124}, | ||
| 2743 | {0, 0x00aa, 0x0127}, | ||
| 2744 | {0, 0xfff8, 0x0124}, | ||
| 2745 | {0, 0xfffd, 0x0124}, | ||
| 2746 | {0, 0x0000, 0x0127}, | ||
| 2747 | {0, 0xfff8, 0x0124}, | ||
| 2748 | {0, 0xfffd, 0x0124}, | ||
| 2749 | {0, 0xfffa, 0x0124}, | ||
| 2750 | {0, 0xffff, 0x0124}, | ||
| 2751 | {0, 0xfff9, 0x0124}, | ||
| 2752 | {0, 0x0086, 0x0127}, | ||
| 2753 | {0, 0xfff8, 0x0124}, | ||
| 2754 | {0, 0xfffd, 0x0124}, | ||
| 2755 | {0, 0x00f2, 0x0127}, | ||
| 2756 | {0, 0xfff8, 0x0124}, | ||
| 2757 | {0, 0xfffd, 0x0124}, | ||
| 2758 | {0, 0x000f, 0x0127}, | ||
| 2759 | {0, 0xfff8, 0x0124}, | ||
| 2760 | {0, 0xfffd, 0x0124}, | ||
| 2761 | {0, 0xfffa, 0x0124}, | ||
| 2762 | {0, 0xffff, 0x0124}, | ||
| 2763 | {0, 0xfff9, 0x0124}, | ||
| 2764 | {0, 0x0086, 0x0127}, | ||
| 2765 | {0, 0xfff8, 0x0124}, | ||
| 2766 | {0, 0xfffd, 0x0124}, | ||
| 2767 | {0, 0x00f8, 0x0127}, | ||
| 2768 | {0, 0xfff8, 0x0124}, | ||
| 2769 | {0, 0xfffd, 0x0124}, | ||
| 2770 | {0, 0x00fc, 0x0127}, | ||
| 2771 | {0, 0xfff8, 0x0124}, | ||
| 2772 | {0, 0xfffd, 0x0124}, | ||
| 2773 | {0, 0xfffa, 0x0124}, | ||
| 2774 | {0, 0xffff, 0x0124}, | ||
| 2775 | {0, 0xfff9, 0x0124}, | ||
| 2776 | {0, 0x0086, 0x0127}, | ||
| 2777 | {0, 0xfff8, 0x0124}, | ||
| 2778 | {0, 0xfffd, 0x0124}, | ||
| 2779 | {0, 0x00f9, 0x0127}, | ||
| 2780 | {0, 0xfff8, 0x0124}, | ||
| 2781 | {0, 0xfffd, 0x0124}, | ||
| 2782 | {0, 0x003c, 0x0127}, | ||
| 2783 | {0, 0xfff8, 0x0124}, | ||
| 2784 | {0, 0xfffd, 0x0124}, | ||
| 2785 | {0, 0xfffa, 0x0124}, | ||
| 2786 | {0, 0xffff, 0x0124}, | ||
| 2787 | {0, 0xfff9, 0x0124}, | ||
| 2788 | {0, 0x0086, 0x0127}, | ||
| 2789 | {0, 0xfff8, 0x0124}, | ||
| 2790 | {0, 0xfffd, 0x0124}, | ||
| 2791 | {0, 0x0027, 0x0127}, | ||
| 2792 | {0, 0xfff8, 0x0124}, | ||
| 2793 | {0, 0xfffd, 0x0124}, | ||
| 2794 | {0, 0x0019, 0x0127}, | ||
| 2795 | {0, 0xfff8, 0x0124}, | ||
| 2796 | {0, 0xfffd, 0x0124}, | ||
| 2797 | {0, 0xfffa, 0x0124}, | ||
| 2798 | {0, 0xfff9, 0x0124}, | ||
| 2799 | {0, 0x0086, 0x0127}, | ||
| 2800 | {0, 0xfff8, 0x0124}, | ||
| 2801 | {0, 0xfffd, 0x0124}, | ||
| 2802 | {0, 0x0037, 0x0127}, | ||
| 2803 | {0, 0xfff8, 0x0124}, | ||
| 2804 | {0, 0xfffd, 0x0124}, | ||
| 2805 | {0, 0x0000, 0x0127}, | ||
| 2806 | {0, 0xfff8, 0x0124}, | ||
| 2807 | {0, 0xfffd, 0x0124}, | ||
| 2808 | {0, 0x0021, 0x0127}, | ||
| 2809 | {0, 0xfff8, 0x0124}, | ||
| 2810 | {0, 0xfffd, 0x0124}, | ||
| 2811 | {0, 0xfffa, 0x0124}, | ||
| 2812 | {0, 0xfff9, 0x0124}, | ||
| 2813 | {0, 0x0086, 0x0127}, | ||
| 2814 | {0, 0xfff8, 0x0124}, | ||
| 2815 | {0, 0xfffd, 0x0124}, | ||
| 2816 | {0, 0x0038, 0x0127}, | ||
| 2817 | {0, 0xfff8, 0x0124}, | ||
| 2818 | {0, 0xfffd, 0x0124}, | ||
| 2819 | {0, 0x0006, 0x0127}, | ||
| 2820 | {0, 0xfff8, 0x0124}, | ||
| 2821 | {0, 0xfffd, 0x0124}, | ||
| 2822 | {0, 0x0045, 0x0127}, | ||
| 2823 | {0, 0xfff8, 0x0124}, | ||
| 2824 | {0, 0xfffd, 0x0124}, | ||
| 2825 | {0, 0xfffa, 0x0124}, | ||
| 2826 | {0, 0xfff9, 0x0124}, | ||
| 2827 | {0, 0x0086, 0x0127}, | ||
| 2828 | {0, 0xfff8, 0x0124}, | ||
| 2829 | {0, 0xfffd, 0x0124}, | ||
| 2830 | {0, 0x0037, 0x0127}, | ||
| 2831 | {0, 0xfff8, 0x0124}, | ||
| 2832 | {0, 0xfffd, 0x0124}, | ||
| 2833 | {0, 0x0001, 0x0127}, | ||
| 2834 | {0, 0xfff8, 0x0124}, | ||
| 2835 | {0, 0xfffd, 0x0124}, | ||
| 2836 | {0, 0x002a, 0x0127}, | ||
| 2837 | {0, 0xfff8, 0x0124}, | ||
| 2838 | {0, 0xfffd, 0x0124}, | ||
| 2839 | {0, 0xfffa, 0x0124}, | ||
| 2840 | {0, 0xfff9, 0x0124}, | ||
| 2841 | {0, 0x0086, 0x0127}, | ||
| 2842 | {0, 0xfff8, 0x0124}, | ||
| 2843 | {0, 0xfffd, 0x0124}, | ||
| 2844 | {0, 0x0038, 0x0127}, | ||
| 2845 | {0, 0xfff8, 0x0124}, | ||
| 2846 | {0, 0xfffd, 0x0124}, | ||
| 2847 | {0, 0x0000, 0x0127}, | ||
| 2848 | {0, 0xfff8, 0x0124}, | ||
| 2849 | {0, 0xfffd, 0x0124}, | ||
| 2850 | {0, 0x000e, 0x0127}, | ||
| 2851 | {0, 0xfff8, 0x0124}, | ||
| 2852 | {0, 0xfffd, 0x0124}, | ||
| 2853 | {0, 0xfffa, 0x0124}, | ||
| 2854 | {0, 0xfff9, 0x0124}, | ||
| 2855 | {0, 0x0086, 0x0127}, | ||
| 2856 | {0, 0xfff8, 0x0124}, | ||
| 2857 | {0, 0xfffd, 0x0124}, | ||
| 2858 | {0, 0x0037, 0x0127}, | ||
| 2859 | {0, 0xfff8, 0x0124}, | ||
| 2860 | {0, 0xfffd, 0x0124}, | ||
| 2861 | {0, 0x0001, 0x0127}, | ||
| 2862 | {0, 0xfff8, 0x0124}, | ||
| 2863 | {0, 0xfffd, 0x0124}, | ||
| 2864 | {0, 0x002b, 0x0127}, | ||
| 2865 | {0, 0xfff8, 0x0124}, | ||
| 2866 | {0, 0xfffd, 0x0124}, | ||
| 2867 | {0, 0xfffa, 0x0124}, | ||
| 2868 | {0, 0xfff9, 0x0124}, | ||
| 2869 | {0, 0x0086, 0x0127}, | ||
| 2870 | {0, 0xfff8, 0x0124}, | ||
| 2871 | {0, 0xfffd, 0x0124}, | ||
| 2872 | {0, 0x0038, 0x0127}, | ||
| 2873 | {0, 0xfff8, 0x0124}, | ||
| 2874 | {0, 0xfffd, 0x0124}, | ||
| 2875 | {0, 0x0001, 0x0127}, | ||
| 2876 | {0, 0xfff8, 0x0124}, | ||
| 2877 | {0, 0xfffd, 0x0124}, | ||
| 2878 | {0, 0x00f4, 0x0127}, | ||
| 2879 | {0, 0xfff8, 0x0124}, | ||
| 2880 | {0, 0xfffd, 0x0124}, | ||
| 2881 | {0, 0xfffa, 0x0124}, | ||
| 2882 | {0, 0xfff9, 0x0124}, | ||
| 2883 | {0, 0x0086, 0x0127}, | ||
| 2884 | {0, 0xfff8, 0x0124}, | ||
| 2885 | {0, 0xfffd, 0x0124}, | ||
| 2886 | {0, 0x0037, 0x0127}, | ||
| 2887 | {0, 0xfff8, 0x0124}, | ||
| 2888 | {0, 0xfffd, 0x0124}, | ||
| 2889 | {0, 0x0001, 0x0127}, | ||
| 2890 | {0, 0xfff8, 0x0124}, | ||
| 2891 | {0, 0xfffd, 0x0124}, | ||
| 2892 | {0, 0x002c, 0x0127}, | ||
| 2893 | {0, 0xfff8, 0x0124}, | ||
| 2894 | {0, 0xfffd, 0x0124}, | ||
| 2895 | {0, 0xfffa, 0x0124}, | ||
| 2896 | {0, 0xfff9, 0x0124}, | ||
| 2897 | {0, 0x0086, 0x0127}, | ||
| 2898 | {0, 0xfff8, 0x0124}, | ||
| 2899 | {0, 0xfffd, 0x0124}, | ||
| 2900 | {0, 0x0038, 0x0127}, | ||
| 2901 | {0, 0xfff8, 0x0124}, | ||
| 2902 | {0, 0xfffd, 0x0124}, | ||
| 2903 | {0, 0x0001, 0x0127}, | ||
| 2904 | {0, 0xfff8, 0x0124}, | ||
| 2905 | {0, 0xfffd, 0x0124}, | ||
| 2906 | {0, 0x0004, 0x0127}, | ||
| 2907 | {0, 0xfff8, 0x0124}, | ||
| 2908 | {0, 0xfffd, 0x0124}, | ||
| 2909 | {0, 0xfffa, 0x0124}, | ||
| 2910 | {0, 0xfff9, 0x0124}, | ||
| 2911 | {0, 0x0086, 0x0127}, | ||
| 2912 | {0, 0xfff8, 0x0124}, | ||
| 2913 | {0, 0xfffd, 0x0124}, | ||
| 2914 | {0, 0x0037, 0x0127}, | ||
| 2915 | {0, 0xfff8, 0x0124}, | ||
| 2916 | {0, 0xfffd, 0x0124}, | ||
| 2917 | {0, 0x0001, 0x0127}, | ||
| 2918 | {0, 0xfff8, 0x0124}, | ||
| 2919 | {0, 0xfffd, 0x0124}, | ||
| 2920 | {0, 0x002d, 0x0127}, | ||
| 2921 | {0, 0xfff8, 0x0124}, | ||
| 2922 | {0, 0xfffd, 0x0124}, | ||
| 2923 | {0, 0xfffa, 0x0124}, | ||
| 2924 | {0, 0xfff9, 0x0124}, | ||
| 2925 | {0, 0x0086, 0x0127}, | ||
| 2926 | {0, 0xfff8, 0x0124}, | ||
| 2927 | {0, 0xfffd, 0x0124}, | ||
| 2928 | {0, 0x0038, 0x0127}, | ||
| 2929 | {0, 0xfff8, 0x0124}, | ||
| 2930 | {0, 0xfffd, 0x0124}, | ||
| 2931 | {0, 0x0000, 0x0127}, | ||
| 2932 | {0, 0xfff8, 0x0124}, | ||
| 2933 | {0, 0xfffd, 0x0124}, | ||
| 2934 | {0, 0x0014, 0x0127}, | ||
| 2935 | {0, 0xfff8, 0x0124}, | ||
| 2936 | {0, 0xfffd, 0x0124}, | ||
| 2937 | {0, 0xfffa, 0x0124}, | ||
| 2938 | {0, 0xfff9, 0x0124}, | ||
| 2939 | {0, 0x0086, 0x0127}, | ||
| 2940 | {0, 0xfff8, 0x0124}, | ||
| 2941 | {0, 0xfffd, 0x0124}, | ||
| 2942 | {0, 0x0037, 0x0127}, | ||
| 2943 | {0, 0xfff8, 0x0124}, | ||
| 2944 | {0, 0xfffd, 0x0124}, | ||
| 2945 | {0, 0x0001, 0x0127}, | ||
| 2946 | {0, 0xfff8, 0x0124}, | ||
| 2947 | {0, 0xfffd, 0x0124}, | ||
| 2948 | {0, 0x002e, 0x0127}, | ||
| 2949 | {0, 0xfff8, 0x0124}, | ||
| 2950 | {0, 0xfffd, 0x0124}, | ||
| 2951 | {0, 0xfffa, 0x0124}, | ||
| 2952 | {0, 0xfff9, 0x0124}, | ||
| 2953 | {0, 0x0086, 0x0127}, | ||
| 2954 | {0, 0xfff8, 0x0124}, | ||
| 2955 | {0, 0xfffd, 0x0124}, | ||
| 2956 | {0, 0x0038, 0x0127}, | ||
| 2957 | {0, 0xfff8, 0x0124}, | ||
| 2958 | {0, 0xfffd, 0x0124}, | ||
| 2959 | {0, 0x0003, 0x0127}, | ||
| 2960 | {0, 0xfff8, 0x0124}, | ||
| 2961 | {0, 0xfffd, 0x0124}, | ||
| 2962 | {0, 0x0000, 0x0127}, | ||
| 2963 | {0, 0xfff8, 0x0124}, | ||
| 2964 | {0, 0xfffd, 0x0124}, | ||
| 2965 | {0, 0xfffa, 0x0124}, | ||
| 2966 | {0, 0xfff9, 0x0124}, | ||
| 2967 | {0, 0x0086, 0x0127}, | ||
| 2968 | {0, 0xfff8, 0x0124}, | ||
| 2969 | {0, 0xfffd, 0x0124}, | ||
| 2970 | {0, 0x0037, 0x0127}, | ||
| 2971 | {0, 0xfff8, 0x0124}, | ||
| 2972 | {0, 0xfffd, 0x0124}, | ||
| 2973 | {0, 0x0001, 0x0127}, | ||
| 2974 | {0, 0xfff8, 0x0124}, | ||
| 2975 | {0, 0xfffd, 0x0124}, | ||
| 2976 | {0, 0x002f, 0x0127}, | ||
| 2977 | {0, 0xfff8, 0x0124}, | ||
| 2978 | {0, 0xfffd, 0x0124}, | ||
| 2979 | {0, 0xfffa, 0x0124}, | ||
| 2980 | {0, 0xfff9, 0x0124}, | ||
| 2981 | {0, 0x0086, 0x0127}, | ||
| 2982 | {0, 0xfff8, 0x0124}, | ||
| 2983 | {0, 0xfffd, 0x0124}, | ||
| 2984 | {0, 0x0038, 0x0127}, | ||
| 2985 | {0, 0xfff8, 0x0124}, | ||
| 2986 | {0, 0xfffd, 0x0124}, | ||
| 2987 | {0, 0x0003, 0x0127}, | ||
| 2988 | {0, 0xfff8, 0x0124}, | ||
| 2989 | {0, 0xfffd, 0x0124}, | ||
| 2990 | {0, 0x0014, 0x0127}, | ||
| 2991 | {0, 0xfff8, 0x0124}, | ||
| 2992 | {0, 0xfffd, 0x0124}, | ||
| 2993 | {0, 0xfffa, 0x0124}, | ||
| 2994 | {0, 0xfff9, 0x0124}, | ||
| 2995 | {0, 0x0086, 0x0127}, | ||
| 2996 | {0, 0xfff8, 0x0124}, | ||
| 2997 | {0, 0xfffd, 0x0124}, | ||
| 2998 | {0, 0x0037, 0x0127}, | ||
| 2999 | {0, 0xfff8, 0x0124}, | ||
| 3000 | {0, 0xfffd, 0x0124}, | ||
| 3001 | {0, 0x0001, 0x0127}, | ||
| 3002 | {0, 0xfff8, 0x0124}, | ||
| 3003 | {0, 0xfffd, 0x0124}, | ||
| 3004 | {0, 0x0040, 0x0127}, | ||
| 3005 | {0, 0xfff8, 0x0124}, | ||
| 3006 | {0, 0xfffd, 0x0124}, | ||
| 3007 | {0, 0xfffa, 0x0124}, | ||
| 3008 | {0, 0xfff9, 0x0124}, | ||
| 3009 | {0, 0x0086, 0x0127}, | ||
| 3010 | {0, 0xfff8, 0x0124}, | ||
| 3011 | {0, 0xfffd, 0x0124}, | ||
| 3012 | {0, 0x0038, 0x0127}, | ||
| 3013 | {0, 0xfff8, 0x0124}, | ||
| 3014 | {0, 0xfffd, 0x0124}, | ||
| 3015 | {0, 0x0000, 0x0127}, | ||
| 3016 | {0, 0xfff8, 0x0124}, | ||
| 3017 | {0, 0xfffd, 0x0124}, | ||
| 3018 | {0, 0x0040, 0x0127}, | ||
| 3019 | {0, 0xfff8, 0x0124}, | ||
| 3020 | {0, 0xfffd, 0x0124}, | ||
| 3021 | {0, 0xfffa, 0x0124}, | ||
| 3022 | {0, 0xfff9, 0x0124}, | ||
| 3023 | {0, 0x0086, 0x0127}, | ||
| 3024 | {0, 0xfff8, 0x0124}, | ||
| 3025 | {0, 0xfffd, 0x0124}, | ||
| 3026 | {0, 0x0037, 0x0127}, | ||
| 3027 | {0, 0xfff8, 0x0124}, | ||
| 3028 | {0, 0xfffd, 0x0124}, | ||
| 3029 | {0, 0x0001, 0x0127}, | ||
| 3030 | {0, 0xfff8, 0x0124}, | ||
| 3031 | {0, 0xfffd, 0x0124}, | ||
| 3032 | {0, 0x0053, 0x0127}, | ||
| 3033 | {0, 0xfff8, 0x0124}, | ||
| 3034 | {0, 0xfffd, 0x0124}, | ||
| 3035 | {0, 0xfffa, 0x0124}, | ||
| 3036 | {0, 0xfff9, 0x0124}, | ||
| 3037 | {0, 0x0086, 0x0127}, | ||
| 3038 | {0, 0xfff8, 0x0124}, | ||
| 3039 | {0, 0xfffd, 0x0124}, | ||
| 3040 | {0, 0x0038, 0x0127}, | ||
| 3041 | {0, 0xfff8, 0x0124}, | ||
| 3042 | {0, 0xfffd, 0x0124}, | ||
| 3043 | {0, 0x0000, 0x0127}, | ||
| 3044 | {0, 0xfff8, 0x0124}, | ||
| 3045 | {0, 0xfffd, 0x0124}, | ||
| 3046 | {0, 0x0038, 0x0127}, | ||
| 3047 | {0, 0xfff8, 0x0124}, | ||
| 3048 | {0, 0xfffd, 0x0124}, | ||
| 3049 | {0, 0xfffa, 0x0124}, | ||
| 3050 | {0, 0x0000, 0x0101}, | ||
| 3051 | {0, 0x00a0, 0x0103}, | ||
| 3052 | {0, 0x0078, 0x0105}, | ||
| 3053 | {0, 0x0000, 0x010a}, | ||
| 3054 | {0, 0x0024, 0x010b}, | ||
| 3055 | {0, 0x0028, 0x0119}, | ||
| 3056 | {0, 0x0088, 0x011b}, | ||
| 3057 | {0, 0x0002, 0x011d}, | ||
| 3058 | {0, 0x0003, 0x011e}, | ||
| 3059 | {0, 0x0000, 0x0129}, | ||
| 3060 | {0, 0x00fc, 0x012b}, | ||
| 3061 | {0, 0x0008, 0x0102}, | ||
| 3062 | {0, 0x0000, 0x0104}, | ||
| 3063 | {0, 0x0008, 0x011a}, | ||
| 3064 | {0, 0x0028, 0x011c}, | ||
| 3065 | {0, 0x0021, 0x012a}, | ||
| 3066 | {0, 0x0000, 0x0118}, | ||
| 3067 | {0, 0x0000, 0x0132}, | ||
| 3068 | {0, 0x0000, 0x0109}, | ||
| 3069 | {0, 0xfff9, 0x0124}, | ||
| 3070 | {0, 0x0086, 0x0127}, | ||
| 3071 | {0, 0xfff8, 0x0124}, | ||
| 3072 | {0, 0xfffd, 0x0124}, | ||
| 3073 | {0, 0x0037, 0x0127}, | ||
| 3074 | {0, 0xfff8, 0x0124}, | ||
| 3075 | {0, 0xfffd, 0x0124}, | ||
| 3076 | {0, 0x0001, 0x0127}, | ||
| 3077 | {0, 0xfff8, 0x0124}, | ||
| 3078 | {0, 0xfffd, 0x0124}, | ||
| 3079 | {0, 0x0031, 0x0127}, | ||
| 3080 | {0, 0xfff8, 0x0124}, | ||
| 3081 | {0, 0xfffd, 0x0124}, | ||
| 3082 | {0, 0xfffa, 0x0124}, | ||
| 3083 | {0, 0xfff9, 0x0124}, | ||
| 3084 | {0, 0x0086, 0x0127}, | ||
| 3085 | {0, 0xfff8, 0x0124}, | ||
| 3086 | {0, 0xfffd, 0x0124}, | ||
| 3087 | {0, 0x0038, 0x0127}, | ||
| 3088 | {0, 0xfff8, 0x0124}, | ||
| 3089 | {0, 0xfffd, 0x0124}, | ||
| 3090 | {0, 0x0000, 0x0127}, | ||
| 3091 | {0, 0xfff8, 0x0124}, | ||
| 3092 | {0, 0xfffd, 0x0124}, | ||
| 3093 | {0, 0x0000, 0x0127}, | ||
| 3094 | {0, 0xfff8, 0x0124}, | ||
| 3095 | {0, 0xfffd, 0x0124}, | ||
| 3096 | {0, 0xfffa, 0x0124}, | ||
| 3097 | {0, 0xfff9, 0x0124}, | ||
| 3098 | {0, 0x0086, 0x0127}, | ||
| 3099 | {0, 0xfff8, 0x0124}, | ||
| 3100 | {0, 0xfffd, 0x0124}, | ||
| 3101 | {0, 0x0037, 0x0127}, | ||
| 3102 | {0, 0xfff8, 0x0124}, | ||
| 3103 | {0, 0xfffd, 0x0124}, | ||
| 3104 | {0, 0x0001, 0x0127}, | ||
| 3105 | {0, 0xfff8, 0x0124}, | ||
| 3106 | {0, 0xfffd, 0x0124}, | ||
| 3107 | {0, 0x0040, 0x0127}, | ||
| 3108 | {0, 0xfff8, 0x0124}, | ||
| 3109 | {0, 0xfffd, 0x0124}, | ||
| 3110 | {0, 0xfffa, 0x0124}, | ||
| 3111 | {0, 0xfff9, 0x0124}, | ||
| 3112 | {0, 0x0086, 0x0127}, | ||
| 3113 | {0, 0xfff8, 0x0124}, | ||
| 3114 | {0, 0xfffd, 0x0124}, | ||
| 3115 | {0, 0x0038, 0x0127}, | ||
| 3116 | {0, 0xfff8, 0x0124}, | ||
| 3117 | {0, 0xfffd, 0x0124}, | ||
| 3118 | {0, 0x0000, 0x0127}, | ||
| 3119 | {0, 0xfff8, 0x0124}, | ||
| 3120 | {0, 0xfffd, 0x0124}, | ||
| 3121 | {0, 0x0040, 0x0127}, | ||
| 3122 | {0, 0xfff8, 0x0124}, | ||
| 3123 | {0, 0xfffd, 0x0124}, | ||
| 3124 | {0, 0xfffa, 0x0124}, | ||
| 3125 | {0, 0xfff9, 0x0124}, | ||
| 3126 | {0, 0x0086, 0x0127}, | ||
| 3127 | {0, 0xfff8, 0x0124}, | ||
| 3128 | {0, 0xfffd, 0x0124}, | ||
| 3129 | {0, 0x0037, 0x0127}, | ||
| 3130 | {0, 0xfff8, 0x0124}, | ||
| 3131 | {0, 0xfffd, 0x0124}, | ||
| 3132 | {0, 0x0000, 0x0127}, | ||
| 3133 | {0, 0xfff8, 0x0124}, | ||
| 3134 | {0, 0xfffd, 0x0124}, | ||
| 3135 | {0, 0x00dc, 0x0127}, | ||
| 3136 | {0, 0xfff8, 0x0124}, | ||
| 3137 | {0, 0xfffd, 0x0124}, | ||
| 3138 | {0, 0xfffa, 0x0124}, | ||
| 3139 | {0, 0xfff9, 0x0124}, | ||
| 3140 | {0, 0x0086, 0x0127}, | ||
| 3141 | {0, 0xfff8, 0x0124}, | ||
| 3142 | {0, 0xfffd, 0x0124}, | ||
| 3143 | {0, 0x0038, 0x0127}, | ||
| 3144 | {0, 0xfff8, 0x0124}, | ||
| 3145 | {0, 0xfffd, 0x0124}, | ||
| 3146 | {0, 0x0000, 0x0127}, | ||
| 3147 | {0, 0xfff8, 0x0124}, | ||
| 3148 | {0, 0xfffd, 0x0124}, | ||
| 3149 | {0, 0x0000, 0x0127}, | ||
| 3150 | {0, 0xfff8, 0x0124}, | ||
| 3151 | {0, 0xfffd, 0x0124}, | ||
| 3152 | {0, 0xfffa, 0x0124}, | ||
| 3153 | {0, 0xfff9, 0x0124}, | ||
| 3154 | {0, 0x0086, 0x0127}, | ||
| 3155 | {0, 0xfff8, 0x0124}, | ||
| 3156 | {0, 0xfffd, 0x0124}, | ||
| 3157 | {0, 0x0037, 0x0127}, | ||
| 3158 | {0, 0xfff8, 0x0124}, | ||
| 3159 | {0, 0xfffd, 0x0124}, | ||
| 3160 | {0, 0x0001, 0x0127}, | ||
| 3161 | {0, 0xfff8, 0x0124}, | ||
| 3162 | {0, 0xfffd, 0x0124}, | ||
| 3163 | {0, 0x0032, 0x0127}, | ||
| 3164 | {0, 0xfff8, 0x0124}, | ||
| 3165 | {0, 0xfffd, 0x0124}, | ||
| 3166 | {0, 0xfffa, 0x0124}, | ||
| 3167 | {0, 0xfff9, 0x0124}, | ||
| 3168 | {0, 0x0086, 0x0127}, | ||
| 3169 | {0, 0xfff8, 0x0124}, | ||
| 3170 | {0, 0xfffd, 0x0124}, | ||
| 3171 | {0, 0x0038, 0x0127}, | ||
| 3172 | {0, 0xfff8, 0x0124}, | ||
| 3173 | {0, 0xfffd, 0x0124}, | ||
| 3174 | {0, 0x0001, 0x0127}, | ||
| 3175 | {0, 0xfff8, 0x0124}, | ||
| 3176 | {0, 0xfffd, 0x0124}, | ||
| 3177 | {0, 0x0020, 0x0127}, | ||
| 3178 | {0, 0xfff8, 0x0124}, | ||
| 3179 | {0, 0xfffd, 0x0124}, | ||
| 3180 | {0, 0xfffa, 0x0124}, | ||
| 3181 | {0, 0xfff9, 0x0124}, | ||
| 3182 | {0, 0x0086, 0x0127}, | ||
| 3183 | {0, 0xfff8, 0x0124}, | ||
| 3184 | {0, 0xfffd, 0x0124}, | ||
| 3185 | {0, 0x0037, 0x0127}, | ||
| 3186 | {0, 0xfff8, 0x0124}, | ||
| 3187 | {0, 0xfffd, 0x0124}, | ||
| 3188 | {0, 0x0001, 0x0127}, | ||
| 3189 | {0, 0xfff8, 0x0124}, | ||
| 3190 | {0, 0xfffd, 0x0124}, | ||
| 3191 | {0, 0x0040, 0x0127}, | ||
| 3192 | {0, 0xfff8, 0x0124}, | ||
| 3193 | {0, 0xfffd, 0x0124}, | ||
| 3194 | {0, 0xfffa, 0x0124}, | ||
| 3195 | {0, 0xfff9, 0x0124}, | ||
| 3196 | {0, 0x0086, 0x0127}, | ||
| 3197 | {0, 0xfff8, 0x0124}, | ||
| 3198 | {0, 0xfffd, 0x0124}, | ||
| 3199 | {0, 0x0038, 0x0127}, | ||
| 3200 | {0, 0xfff8, 0x0124}, | ||
| 3201 | {0, 0xfffd, 0x0124}, | ||
| 3202 | {0, 0x0000, 0x0127}, | ||
| 3203 | {0, 0xfff8, 0x0124}, | ||
| 3204 | {0, 0xfffd, 0x0124}, | ||
| 3205 | {0, 0x0040, 0x0127}, | ||
| 3206 | {0, 0xfff8, 0x0124}, | ||
| 3207 | {0, 0xfffd, 0x0124}, | ||
| 3208 | {0, 0xfffa, 0x0124}, | ||
| 3209 | {0, 0xfff9, 0x0124}, | ||
| 3210 | {0, 0x0086, 0x0127}, | ||
| 3211 | {0, 0xfff8, 0x0124}, | ||
| 3212 | {0, 0xfffd, 0x0124}, | ||
| 3213 | {0, 0x0037, 0x0127}, | ||
| 3214 | {0, 0xfff8, 0x0124}, | ||
| 3215 | {0, 0xfffd, 0x0124}, | ||
| 3216 | {0, 0x0000, 0x0127}, | ||
| 3217 | {0, 0xfff8, 0x0124}, | ||
| 3218 | {0, 0xfffd, 0x0124}, | ||
| 3219 | {0, 0x0030, 0x0127}, | ||
| 3220 | {0, 0xfff8, 0x0124}, | ||
| 3221 | {0, 0xfffd, 0x0124}, | ||
| 3222 | {0, 0xfffa, 0x0124}, | ||
| 3223 | {0, 0xfff9, 0x0124}, | ||
| 3224 | {0, 0x0086, 0x0127}, | ||
| 3225 | {0, 0xfff8, 0x0124}, | ||
| 3226 | {0, 0xfffd, 0x0124}, | ||
| 3227 | {0, 0x0038, 0x0127}, | ||
| 3228 | {0, 0xfff8, 0x0124}, | ||
| 3229 | {0, 0xfffd, 0x0124}, | ||
| 3230 | {0, 0x0008, 0x0127}, | ||
| 3231 | {0, 0xfff8, 0x0124}, | ||
| 3232 | {0, 0xfffd, 0x0124}, | ||
| 3233 | {0, 0x0000, 0x0127}, | ||
| 3234 | {0, 0xfff8, 0x0124}, | ||
| 3235 | {0, 0xfffd, 0x0124}, | ||
| 3236 | {0, 0xfffa, 0x0124}, | ||
| 3237 | {0, 0x0003, 0x0106}, | ||
| 3238 | {0, 0x0062, 0x0107}, | ||
| 3239 | {0, 0x0003, 0x0111}, | ||
| 3240 | }; | ||
| 3241 | #define NUM_INIT_DATA | ||
| 3242 | |||
| 3243 | unsigned short compression = 0; /* 0=none, 7=best frame rate */ | ||
| 3244 | int f_rate; /* 0=Fastest 7=slowest */ | ||
| 3245 | |||
| 3246 | if (IBMCAM_T(uvd)->initialized) | ||
| 3247 | return; | ||
| 3248 | |||
| 3249 | /* Internal frame rate is controlled by f_rate value */ | ||
| 3250 | f_rate = 7 - framerate; | ||
| 3251 | RESTRICT_TO_RANGE(f_rate, 0, 7); | ||
| 3252 | |||
| 3253 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
| 3254 | ibmcam_veio(uvd, 1, 0x0000, 0x0116); | ||
| 3255 | ibmcam_veio(uvd, 0, 0x0060, 0x0116); | ||
| 3256 | ibmcam_veio(uvd, 0, 0x0002, 0x0112); | ||
| 3257 | ibmcam_veio(uvd, 0, 0x0000, 0x0123); | ||
| 3258 | ibmcam_veio(uvd, 0, 0x0001, 0x0117); | ||
| 3259 | ibmcam_veio(uvd, 0, 0x0040, 0x0108); | ||
| 3260 | ibmcam_veio(uvd, 0, 0x0019, 0x012c); | ||
| 3261 | ibmcam_veio(uvd, 0, 0x0060, 0x0116); | ||
| 3262 | ibmcam_veio(uvd, 0, 0x0002, 0x0115); | ||
| 3263 | ibmcam_veio(uvd, 0, 0x0003, 0x0115); | ||
| 3264 | ibmcam_veio(uvd, 1, 0x0000, 0x0115); | ||
| 3265 | ibmcam_veio(uvd, 0, 0x000b, 0x0115); | ||
| 3266 | ibmcam_model3_Packet1(uvd, 0x000a, 0x0040); | ||
| 3267 | ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6); | ||
| 3268 | ibmcam_model3_Packet1(uvd, 0x000c, 0x0002); | ||
| 3269 | ibmcam_model3_Packet1(uvd, 0x000d, 0x0020); | ||
| 3270 | ibmcam_model3_Packet1(uvd, 0x000e, 0x0033); | ||
| 3271 | ibmcam_model3_Packet1(uvd, 0x000f, 0x0007); | ||
| 3272 | ibmcam_model3_Packet1(uvd, 0x0010, 0x0000); | ||
| 3273 | ibmcam_model3_Packet1(uvd, 0x0011, 0x0070); | ||
| 3274 | ibmcam_model3_Packet1(uvd, 0x0012, 0x0030); | ||
| 3275 | ibmcam_model3_Packet1(uvd, 0x0013, 0x0000); | ||
| 3276 | ibmcam_model3_Packet1(uvd, 0x0014, 0x0001); | ||
| 3277 | ibmcam_model3_Packet1(uvd, 0x0015, 0x0001); | ||
| 3278 | ibmcam_model3_Packet1(uvd, 0x0016, 0x0001); | ||
| 3279 | ibmcam_model3_Packet1(uvd, 0x0017, 0x0001); | ||
| 3280 | ibmcam_model3_Packet1(uvd, 0x0018, 0x0000); | ||
| 3281 | ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3); | ||
| 3282 | ibmcam_model3_Packet1(uvd, 0x0020, 0x0000); | ||
| 3283 | ibmcam_model3_Packet1(uvd, 0x0028, 0x0010); | ||
| 3284 | ibmcam_model3_Packet1(uvd, 0x0029, 0x0054); | ||
| 3285 | ibmcam_model3_Packet1(uvd, 0x002a, 0x0013); | ||
| 3286 | ibmcam_model3_Packet1(uvd, 0x002b, 0x0007); | ||
| 3287 | ibmcam_model3_Packet1(uvd, 0x002d, 0x0028); | ||
| 3288 | ibmcam_model3_Packet1(uvd, 0x002e, 0x0000); | ||
| 3289 | ibmcam_model3_Packet1(uvd, 0x0031, 0x0000); | ||
| 3290 | ibmcam_model3_Packet1(uvd, 0x0032, 0x0000); | ||
| 3291 | ibmcam_model3_Packet1(uvd, 0x0033, 0x0000); | ||
| 3292 | ibmcam_model3_Packet1(uvd, 0x0034, 0x0000); | ||
| 3293 | ibmcam_model3_Packet1(uvd, 0x0035, 0x0038); | ||
| 3294 | ibmcam_model3_Packet1(uvd, 0x003a, 0x0001); | ||
| 3295 | ibmcam_model3_Packet1(uvd, 0x003c, 0x001e); | ||
| 3296 | ibmcam_model3_Packet1(uvd, 0x003f, 0x000a); | ||
| 3297 | ibmcam_model3_Packet1(uvd, 0x0041, 0x0000); | ||
| 3298 | ibmcam_model3_Packet1(uvd, 0x0046, 0x003f); | ||
| 3299 | ibmcam_model3_Packet1(uvd, 0x0047, 0x0000); | ||
| 3300 | ibmcam_model3_Packet1(uvd, 0x0050, 0x0005); | ||
| 3301 | ibmcam_model3_Packet1(uvd, 0x0052, 0x001a); | ||
| 3302 | ibmcam_model3_Packet1(uvd, 0x0053, 0x0003); | ||
| 3303 | ibmcam_model3_Packet1(uvd, 0x005a, 0x006b); | ||
| 3304 | ibmcam_model3_Packet1(uvd, 0x005d, 0x001e); | ||
| 3305 | ibmcam_model3_Packet1(uvd, 0x005e, 0x0030); | ||
| 3306 | ibmcam_model3_Packet1(uvd, 0x005f, 0x0041); | ||
| 3307 | ibmcam_model3_Packet1(uvd, 0x0064, 0x0008); | ||
| 3308 | ibmcam_model3_Packet1(uvd, 0x0065, 0x0015); | ||
| 3309 | ibmcam_model3_Packet1(uvd, 0x0068, 0x000f); | ||
| 3310 | ibmcam_model3_Packet1(uvd, 0x0079, 0x0000); | ||
| 3311 | ibmcam_model3_Packet1(uvd, 0x007a, 0x0000); | ||
| 3312 | ibmcam_model3_Packet1(uvd, 0x007c, 0x003f); | ||
| 3313 | ibmcam_model3_Packet1(uvd, 0x0082, 0x000f); | ||
| 3314 | ibmcam_model3_Packet1(uvd, 0x0085, 0x0000); | ||
| 3315 | ibmcam_model3_Packet1(uvd, 0x0099, 0x0000); | ||
| 3316 | ibmcam_model3_Packet1(uvd, 0x009b, 0x0023); | ||
| 3317 | ibmcam_model3_Packet1(uvd, 0x009c, 0x0022); | ||
| 3318 | ibmcam_model3_Packet1(uvd, 0x009d, 0x0096); | ||
| 3319 | ibmcam_model3_Packet1(uvd, 0x009e, 0x0096); | ||
| 3320 | ibmcam_model3_Packet1(uvd, 0x009f, 0x000a); | ||
| 3321 | |||
| 3322 | switch (uvd->videosize) { | ||
| 3323 | case VIDEOSIZE_160x120: | ||
| 3324 | ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */ | ||
| 3325 | ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */ | ||
| 3326 | ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */ | ||
| 3327 | ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ | ||
| 3328 | ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */ | ||
| 3329 | ibmcam_veio(uvd, 0, 0x00a9, 0x0119); | ||
| 3330 | ibmcam_veio(uvd, 0, 0x0016, 0x011b); | ||
| 3331 | ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */ | ||
| 3332 | ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */ | ||
| 3333 | ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ | ||
| 3334 | ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ | ||
| 3335 | ibmcam_veio(uvd, 0, 0x0018, 0x0102); | ||
| 3336 | ibmcam_veio(uvd, 0, 0x0004, 0x0104); | ||
| 3337 | ibmcam_veio(uvd, 0, 0x0004, 0x011a); | ||
| 3338 | ibmcam_veio(uvd, 0, 0x0028, 0x011c); | ||
| 3339 | ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ | ||
| 3340 | ibmcam_veio(uvd, 0, 0x0000, 0x0118); | ||
| 3341 | ibmcam_veio(uvd, 0, 0x0000, 0x0132); | ||
| 3342 | ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ | ||
| 3343 | ibmcam_veio(uvd, 0, compression, 0x0109); | ||
| 3344 | break; | ||
| 3345 | case VIDEOSIZE_320x240: | ||
| 3346 | ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */ | ||
| 3347 | ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */ | ||
| 3348 | ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */ | ||
| 3349 | ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ | ||
| 3350 | ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */ | ||
| 3351 | ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */ | ||
| 3352 | ibmcam_veio(uvd, 0, 0x0000, 0x011e); | ||
| 3353 | ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ | ||
| 3354 | ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ | ||
| 3355 | /* 4 commands from 160x120 skipped */ | ||
| 3356 | ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ | ||
| 3357 | ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ | ||
| 3358 | ibmcam_veio(uvd, 0, compression, 0x0109); | ||
| 3359 | ibmcam_veio(uvd, 0, 0x00d9, 0x0119); | ||
| 3360 | ibmcam_veio(uvd, 0, 0x0006, 0x011b); | ||
| 3361 | ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ | ||
| 3362 | ibmcam_veio(uvd, 0, 0x0010, 0x0104); | ||
| 3363 | ibmcam_veio(uvd, 0, 0x0004, 0x011a); | ||
| 3364 | ibmcam_veio(uvd, 0, 0x003f, 0x011c); | ||
| 3365 | ibmcam_veio(uvd, 0, 0x001c, 0x0118); | ||
| 3366 | ibmcam_veio(uvd, 0, 0x0000, 0x0132); | ||
| 3367 | break; | ||
| 3368 | case VIDEOSIZE_640x480: | ||
| 3369 | ibmcam_veio(uvd, 0, 0x00f0, 0x0105); | ||
| 3370 | ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ | ||
| 3371 | ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */ | ||
| 3372 | ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */ | ||
| 3373 | ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */ | ||
| 3374 | ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */ | ||
| 3375 | ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */ | ||
| 3376 | ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ | ||
| 3377 | ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ | ||
| 3378 | ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ | ||
| 3379 | ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */ | ||
| 3380 | ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */ | ||
| 3381 | ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */ | ||
| 3382 | ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ | ||
| 3383 | ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */ | ||
| 3384 | ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ | ||
| 3385 | ibmcam_veio(uvd, 0, compression, 0x0109); | ||
| 3386 | ibmcam_veio(uvd, 0, 0x0040, 0x0101); | ||
| 3387 | ibmcam_veio(uvd, 0, 0x0040, 0x0103); | ||
| 3388 | ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */ | ||
| 3389 | break; | ||
| 3390 | } | ||
| 3391 | ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); /* Hue */ | ||
| 3392 | ibmcam_model3_Packet1(uvd, 0x0036, 0x0011); /* Brightness */ | ||
| 3393 | ibmcam_model3_Packet1(uvd, 0x0060, 0x0002); /* Sharpness */ | ||
| 3394 | ibmcam_model3_Packet1(uvd, 0x0061, 0x0004); /* Sharpness */ | ||
| 3395 | ibmcam_model3_Packet1(uvd, 0x0062, 0x0005); /* Sharpness */ | ||
| 3396 | ibmcam_model3_Packet1(uvd, 0x0063, 0x0014); /* Sharpness */ | ||
| 3397 | ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */ | ||
| 3398 | ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */ | ||
| 3399 | ibmcam_model3_Packet1(uvd, 0x0067, 0x0001); /* Contrast */ | ||
| 3400 | ibmcam_model3_Packet1(uvd, 0x005b, 0x000c); /* Contrast */ | ||
| 3401 | ibmcam_model3_Packet1(uvd, 0x005c, 0x0016); /* Contrast */ | ||
| 3402 | ibmcam_model3_Packet1(uvd, 0x0098, 0x000b); | ||
| 3403 | ibmcam_model3_Packet1(uvd, 0x002c, 0x0003); /* Was 1, broke 640x480 */ | ||
| 3404 | ibmcam_model3_Packet1(uvd, 0x002f, 0x002a); | ||
| 3405 | ibmcam_model3_Packet1(uvd, 0x0030, 0x0029); | ||
| 3406 | ibmcam_model3_Packet1(uvd, 0x0037, 0x0002); | ||
| 3407 | ibmcam_model3_Packet1(uvd, 0x0038, 0x0059); | ||
| 3408 | ibmcam_model3_Packet1(uvd, 0x003d, 0x002e); | ||
| 3409 | ibmcam_model3_Packet1(uvd, 0x003e, 0x0028); | ||
| 3410 | ibmcam_model3_Packet1(uvd, 0x0078, 0x0005); | ||
| 3411 | ibmcam_model3_Packet1(uvd, 0x007b, 0x0011); | ||
| 3412 | ibmcam_model3_Packet1(uvd, 0x007d, 0x004b); | ||
| 3413 | ibmcam_model3_Packet1(uvd, 0x007f, 0x0022); | ||
| 3414 | ibmcam_model3_Packet1(uvd, 0x0080, 0x000c); | ||
| 3415 | ibmcam_model3_Packet1(uvd, 0x0081, 0x000b); | ||
| 3416 | ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd); | ||
| 3417 | ibmcam_model3_Packet1(uvd, 0x0086, 0x000b); | ||
| 3418 | ibmcam_model3_Packet1(uvd, 0x0087, 0x000b); | ||
| 3419 | ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); | ||
| 3420 | ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */ | ||
| 3421 | ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */ | ||
| 3422 | ibmcam_model3_Packet1(uvd, 0x0098, 0x000b); | ||
| 3423 | |||
| 3424 | switch (uvd->videosize) { | ||
| 3425 | case VIDEOSIZE_160x120: | ||
| 3426 | ibmcam_veio(uvd, 0, 0x0002, 0x0106); | ||
| 3427 | ibmcam_veio(uvd, 0, 0x0008, 0x0107); | ||
| 3428 | ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ | ||
| 3429 | ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */ | ||
| 3430 | ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */ | ||
| 3431 | ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */ | ||
| 3432 | ibmcam_model3_Packet1(uvd, 0x0040, 0x000a); | ||
| 3433 | ibmcam_model3_Packet1(uvd, 0x0051, 0x000a); | ||
| 3434 | break; | ||
| 3435 | case VIDEOSIZE_320x240: | ||
| 3436 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
| 3437 | ibmcam_veio(uvd, 0, 0x0062, 0x0107); | ||
| 3438 | ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ | ||
| 3439 | ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */ | ||
| 3440 | ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */ | ||
| 3441 | ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */ | ||
| 3442 | ibmcam_model3_Packet1(uvd, 0x0040, 0x0008); | ||
| 3443 | ibmcam_model3_Packet1(uvd, 0x0051, 0x000b); | ||
| 3444 | break; | ||
| 3445 | case VIDEOSIZE_640x480: | ||
| 3446 | ibmcam_veio(uvd, 0, 0x0002, 0x0106); /* Adjustments */ | ||
| 3447 | ibmcam_veio(uvd, 0, 0x00b4, 0x0107); /* Adjustments */ | ||
| 3448 | ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ | ||
| 3449 | ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */ | ||
| 3450 | ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */ | ||
| 3451 | ibmcam_model3_Packet1(uvd, 0x0040, 0x0008); | ||
| 3452 | ibmcam_model3_Packet1(uvd, 0x0051, 0x000a); | ||
| 3453 | break; | ||
| 3454 | } | ||
| 3455 | |||
| 3456 | /* 01.01.08 - Added for RCA video in support -LO */ | ||
| 3457 | if(init_model3_input) { | ||
| 3458 | if (debug > 0) | ||
| 3459 | info("Setting input to RCA."); | ||
| 3460 | for (i=0; i < ARRAY_SIZE(initData); i++) { | ||
| 3461 | ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index); | ||
| 3462 | } | ||
| 3463 | } | ||
| 3464 | |||
| 3465 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
| 3466 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
| 3467 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
| 3468 | } | ||
| 3469 | |||
| 3470 | /* | ||
| 3471 | * ibmcam_video_stop() | ||
| 3472 | * | ||
| 3473 | * This code tells camera to stop streaming. The interface remains | ||
| 3474 | * configured and bandwidth - claimed. | ||
| 3475 | */ | ||
| 3476 | static void ibmcam_video_stop(struct uvd *uvd) | ||
| 3477 | { | ||
| 3478 | switch (IBMCAM_T(uvd)->camera_model) { | ||
| 3479 | case IBMCAM_MODEL_1: | ||
| 3480 | ibmcam_veio(uvd, 0, 0x00, 0x010c); | ||
| 3481 | ibmcam_veio(uvd, 0, 0x00, 0x010c); | ||
| 3482 | ibmcam_veio(uvd, 0, 0x01, 0x0114); | ||
| 3483 | ibmcam_veio(uvd, 0, 0xc0, 0x010c); | ||
| 3484 | ibmcam_veio(uvd, 0, 0x00, 0x010c); | ||
| 3485 | ibmcam_send_FF_04_02(uvd); | ||
| 3486 | ibmcam_veio(uvd, 1, 0x00, 0x0100); | ||
| 3487 | ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */ | ||
| 3488 | break; | ||
| 3489 | case IBMCAM_MODEL_2: | ||
| 3490 | case IBMCAM_MODEL_4: | ||
| 3491 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop the camera */ | ||
| 3492 | |||
| 3493 | ibmcam_model2_Packet1(uvd, 0x0030, 0x0004); | ||
| 3494 | |||
| 3495 | ibmcam_veio(uvd, 0, 0x0080, 0x0100); /* LED Off */ | ||
| 3496 | ibmcam_veio(uvd, 0, 0x0020, 0x0111); | ||
| 3497 | ibmcam_veio(uvd, 0, 0x00a0, 0x0111); | ||
| 3498 | |||
| 3499 | ibmcam_model2_Packet1(uvd, 0x0030, 0x0002); | ||
| 3500 | |||
| 3501 | ibmcam_veio(uvd, 0, 0x0020, 0x0111); | ||
| 3502 | ibmcam_veio(uvd, 0, 0x0000, 0x0112); | ||
| 3503 | break; | ||
| 3504 | case IBMCAM_MODEL_3: | ||
| 3505 | #if 1 | ||
| 3506 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); | ||
| 3507 | |||
| 3508 | /* Here we are supposed to select video interface alt. setting 0 */ | ||
| 3509 | ibmcam_veio(uvd, 0, 0x0006, 0x012c); | ||
| 3510 | |||
| 3511 | ibmcam_model3_Packet1(uvd, 0x0046, 0x0000); | ||
| 3512 | |||
| 3513 | ibmcam_veio(uvd, 1, 0x0000, 0x0116); | ||
| 3514 | ibmcam_veio(uvd, 0, 0x0064, 0x0116); | ||
| 3515 | ibmcam_veio(uvd, 1, 0x0000, 0x0115); | ||
| 3516 | ibmcam_veio(uvd, 0, 0x0003, 0x0115); | ||
| 3517 | ibmcam_veio(uvd, 0, 0x0008, 0x0123); | ||
| 3518 | ibmcam_veio(uvd, 0, 0x0000, 0x0117); | ||
| 3519 | ibmcam_veio(uvd, 0, 0x0000, 0x0112); | ||
| 3520 | ibmcam_veio(uvd, 0, 0x0080, 0x0100); | ||
| 3521 | IBMCAM_T(uvd)->initialized = 0; | ||
| 3522 | #endif | ||
| 3523 | break; | ||
| 3524 | } /* switch */ | ||
| 3525 | } | ||
| 3526 | |||
| 3527 | /* | ||
| 3528 | * ibmcam_reinit_iso() | ||
| 3529 | * | ||
| 3530 | * This procedure sends couple of commands to the camera and then | ||
| 3531 | * resets the video pipe. This sequence was observed to reinit the | ||
| 3532 | * camera or, at least, to initiate ISO data stream. | ||
| 3533 | * | ||
| 3534 | * History: | ||
| 3535 | * 1/2/00 Created. | ||
| 3536 | */ | ||
| 3537 | static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop) | ||
| 3538 | { | ||
| 3539 | switch (IBMCAM_T(uvd)->camera_model) { | ||
| 3540 | case IBMCAM_MODEL_1: | ||
| 3541 | if (do_stop) | ||
| 3542 | ibmcam_video_stop(uvd); | ||
| 3543 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
| 3544 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
| 3545 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
| 3546 | ibmcam_model1_setup_after_video_if(uvd); | ||
| 3547 | break; | ||
| 3548 | case IBMCAM_MODEL_2: | ||
| 3549 | ibmcam_model2_setup_after_video_if(uvd); | ||
| 3550 | break; | ||
| 3551 | case IBMCAM_MODEL_3: | ||
| 3552 | ibmcam_video_stop(uvd); | ||
| 3553 | ibmcam_model3_setup_after_video_if(uvd); | ||
| 3554 | break; | ||
| 3555 | case IBMCAM_MODEL_4: | ||
| 3556 | ibmcam_model4_setup_after_video_if(uvd); | ||
| 3557 | break; | ||
| 3558 | } | ||
| 3559 | } | ||
| 3560 | |||
| 3561 | static void ibmcam_video_start(struct uvd *uvd) | ||
| 3562 | { | ||
| 3563 | ibmcam_change_lighting_conditions(uvd); | ||
| 3564 | ibmcam_set_sharpness(uvd); | ||
| 3565 | ibmcam_reinit_iso(uvd, 0); | ||
| 3566 | } | ||
| 3567 | |||
| 3568 | /* | ||
| 3569 | * Return negative code on failure, 0 on success. | ||
| 3570 | */ | ||
| 3571 | static int ibmcam_setup_on_open(struct uvd *uvd) | ||
| 3572 | { | ||
| 3573 | int setup_ok = 0; /* Success by default */ | ||
| 3574 | /* Send init sequence only once, it's large! */ | ||
| 3575 | if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */ | ||
| 3576 | switch (IBMCAM_T(uvd)->camera_model) { | ||
| 3577 | case IBMCAM_MODEL_1: | ||
| 3578 | setup_ok = ibmcam_model1_setup(uvd); | ||
| 3579 | break; | ||
| 3580 | case IBMCAM_MODEL_2: | ||
| 3581 | setup_ok = ibmcam_model2_setup(uvd); | ||
| 3582 | break; | ||
| 3583 | case IBMCAM_MODEL_3: | ||
| 3584 | case IBMCAM_MODEL_4: | ||
| 3585 | /* We do all setup when Isoc stream is requested */ | ||
| 3586 | break; | ||
| 3587 | } | ||
| 3588 | IBMCAM_T(uvd)->initialized = (setup_ok != 0); | ||
| 3589 | } | ||
| 3590 | return setup_ok; | ||
| 3591 | } | ||
| 3592 | |||
| 3593 | static void ibmcam_configure_video(struct uvd *uvd) | ||
| 3594 | { | ||
| 3595 | if (uvd == NULL) | ||
| 3596 | return; | ||
| 3597 | |||
| 3598 | RESTRICT_TO_RANGE(init_brightness, 0, 255); | ||
| 3599 | RESTRICT_TO_RANGE(init_contrast, 0, 255); | ||
| 3600 | RESTRICT_TO_RANGE(init_color, 0, 255); | ||
| 3601 | RESTRICT_TO_RANGE(init_hue, 0, 255); | ||
| 3602 | RESTRICT_TO_RANGE(hue_correction, 0, 255); | ||
| 3603 | |||
| 3604 | memset(&uvd->vpic, 0, sizeof(uvd->vpic)); | ||
| 3605 | memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); | ||
| 3606 | |||
| 3607 | uvd->vpic.colour = init_color << 8; | ||
| 3608 | uvd->vpic.hue = init_hue << 8; | ||
| 3609 | uvd->vpic.brightness = init_brightness << 8; | ||
| 3610 | uvd->vpic.contrast = init_contrast << 8; | ||
| 3611 | uvd->vpic.whiteness = 105 << 8; /* This one isn't used */ | ||
| 3612 | uvd->vpic.depth = 24; | ||
| 3613 | uvd->vpic.palette = VIDEO_PALETTE_RGB24; | ||
| 3614 | |||
| 3615 | memset(&uvd->vcap, 0, sizeof(uvd->vcap)); | ||
| 3616 | strcpy(uvd->vcap.name, "IBM USB Camera"); | ||
| 3617 | uvd->vcap.type = VID_TYPE_CAPTURE; | ||
| 3618 | uvd->vcap.channels = 1; | ||
| 3619 | uvd->vcap.audios = 0; | ||
| 3620 | uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas); | ||
| 3621 | uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas); | ||
| 3622 | uvd->vcap.minwidth = min_canvasWidth; | ||
| 3623 | uvd->vcap.minheight = min_canvasHeight; | ||
| 3624 | |||
| 3625 | memset(&uvd->vchan, 0, sizeof(uvd->vchan)); | ||
| 3626 | uvd->vchan.flags = 0; | ||
| 3627 | uvd->vchan.tuners = 0; | ||
| 3628 | uvd->vchan.channel = 0; | ||
| 3629 | uvd->vchan.type = VIDEO_TYPE_CAMERA; | ||
| 3630 | strcpy(uvd->vchan.name, "Camera"); | ||
| 3631 | } | ||
| 3632 | |||
| 3633 | /* | ||
| 3634 | * ibmcam_probe() | ||
| 3635 | * | ||
| 3636 | * This procedure queries device descriptor and accepts the interface | ||
| 3637 | * if it looks like IBM C-it camera. | ||
| 3638 | * | ||
| 3639 | * History: | ||
| 3640 | * 22-Jan-2000 Moved camera init code to ibmcam_open() | ||
| 3641 | * 27=Jan-2000 Changed to use static structures, added locking. | ||
| 3642 | * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). | ||
| 3643 | * 03-Jul-2000 Fixed endianness bug. | ||
| 3644 | * 12-Nov-2000 Reworked to comply with new probe() signature. | ||
| 3645 | * 23-Jan-2001 Added compatibility with 2.2.x kernels. | ||
| 3646 | */ | ||
| 3647 | static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *devid) | ||
| 3648 | { | ||
| 3649 | struct usb_device *dev = interface_to_usbdev(intf); | ||
| 3650 | struct uvd *uvd = NULL; | ||
| 3651 | int ix, i, nas, model=0, canvasX=0, canvasY=0; | ||
| 3652 | int actInterface=-1, inactInterface=-1, maxPS=0; | ||
| 3653 | __u8 ifnum = intf->altsetting->desc.bInterfaceNumber; | ||
| 3654 | unsigned char video_ep = 0; | ||
| 3655 | |||
| 3656 | if (debug >= 1) | ||
| 3657 | info("ibmcam_probe(%p,%u.)", intf, ifnum); | ||
| 3658 | |||
| 3659 | /* We don't handle multi-config cameras */ | ||
| 3660 | if (dev->descriptor.bNumConfigurations != 1) | ||
| 3661 | return -ENODEV; | ||
| 3662 | |||
| 3663 | /* Check the version/revision */ | ||
| 3664 | switch (le16_to_cpu(dev->descriptor.bcdDevice)) { | ||
| 3665 | case 0x0002: | ||
| 3666 | if (ifnum != 2) | ||
| 3667 | return -ENODEV; | ||
| 3668 | model = IBMCAM_MODEL_1; | ||
| 3669 | break; | ||
| 3670 | case 0x030A: | ||
| 3671 | if (ifnum != 0) | ||
| 3672 | return -ENODEV; | ||
| 3673 | if ((le16_to_cpu(dev->descriptor.idProduct) == NETCAM_PRODUCT_ID) || | ||
| 3674 | (le16_to_cpu(dev->descriptor.idProduct) == VEO_800D_PRODUCT_ID)) | ||
| 3675 | model = IBMCAM_MODEL_4; | ||
| 3676 | else | ||
| 3677 | model = IBMCAM_MODEL_2; | ||
| 3678 | break; | ||
| 3679 | case 0x0301: | ||
| 3680 | if (ifnum != 0) | ||
| 3681 | return -ENODEV; | ||
| 3682 | model = IBMCAM_MODEL_3; | ||
| 3683 | break; | ||
| 3684 | default: | ||
| 3685 | err("IBM camera with revision 0x%04x is not supported.", | ||
| 3686 | le16_to_cpu(dev->descriptor.bcdDevice)); | ||
| 3687 | return -ENODEV; | ||
| 3688 | } | ||
| 3689 | |||
| 3690 | /* Print detailed info on what we found so far */ | ||
| 3691 | do { | ||
| 3692 | char *brand = NULL; | ||
| 3693 | switch (le16_to_cpu(dev->descriptor.idProduct)) { | ||
| 3694 | case NETCAM_PRODUCT_ID: | ||
| 3695 | brand = "IBM NetCamera"; | ||
| 3696 | break; | ||
| 3697 | case VEO_800C_PRODUCT_ID: | ||
| 3698 | brand = "Veo Stingray [800C]"; | ||
| 3699 | break; | ||
| 3700 | case VEO_800D_PRODUCT_ID: | ||
| 3701 | brand = "Veo Stingray [800D]"; | ||
| 3702 | break; | ||
| 3703 | case IBMCAM_PRODUCT_ID: | ||
| 3704 | default: | ||
| 3705 | brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */ | ||
| 3706 | break; | ||
| 3707 | } | ||
| 3708 | info("%s USB camera found (model %d, rev. 0x%04x)", | ||
| 3709 | brand, model, le16_to_cpu(dev->descriptor.bcdDevice)); | ||
| 3710 | } while (0); | ||
| 3711 | |||
| 3712 | /* Validate found interface: must have one ISO endpoint */ | ||
| 3713 | nas = intf->num_altsetting; | ||
| 3714 | if (debug > 0) | ||
| 3715 | info("Number of alternate settings=%d.", nas); | ||
| 3716 | if (nas < 2) { | ||
| 3717 | err("Too few alternate settings for this camera!"); | ||
| 3718 | return -ENODEV; | ||
| 3719 | } | ||
| 3720 | /* Validate all alternate settings */ | ||
| 3721 | for (ix=0; ix < nas; ix++) { | ||
| 3722 | const struct usb_host_interface *interface; | ||
| 3723 | const struct usb_endpoint_descriptor *endpoint; | ||
| 3724 | |||
| 3725 | interface = &intf->altsetting[ix]; | ||
| 3726 | i = interface->desc.bAlternateSetting; | ||
| 3727 | if (interface->desc.bNumEndpoints != 1) { | ||
| 3728 | err("Interface %d. has %u. endpoints!", | ||
| 3729 | ifnum, (unsigned)(interface->desc.bNumEndpoints)); | ||
| 3730 | return -ENODEV; | ||
| 3731 | } | ||
| 3732 | endpoint = &interface->endpoint[0].desc; | ||
| 3733 | if (video_ep == 0) | ||
| 3734 | video_ep = endpoint->bEndpointAddress; | ||
| 3735 | else if (video_ep != endpoint->bEndpointAddress) { | ||
| 3736 | err("Alternate settings have different endpoint addresses!"); | ||
| 3737 | return -ENODEV; | ||
| 3738 | } | ||
| 3739 | if ((endpoint->bmAttributes & 0x03) != 0x01) { | ||
| 3740 | err("Interface %d. has non-ISO endpoint!", ifnum); | ||
| 3741 | return -ENODEV; | ||
| 3742 | } | ||
| 3743 | if ((endpoint->bEndpointAddress & 0x80) == 0) { | ||
| 3744 | err("Interface %d. has ISO OUT endpoint!", ifnum); | ||
| 3745 | return -ENODEV; | ||
| 3746 | } | ||
| 3747 | if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { | ||
| 3748 | if (inactInterface < 0) | ||
| 3749 | inactInterface = i; | ||
| 3750 | else { | ||
| 3751 | err("More than one inactive alt. setting!"); | ||
| 3752 | return -ENODEV; | ||
| 3753 | } | ||
| 3754 | } else { | ||
| 3755 | if (actInterface < 0) { | ||
| 3756 | actInterface = i; | ||
| 3757 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | ||
| 3758 | if (debug > 0) | ||
| 3759 | info("Active setting=%d. maxPS=%d.", i, maxPS); | ||
| 3760 | } else | ||
| 3761 | err("More than one active alt. setting! Ignoring #%d.", i); | ||
| 3762 | } | ||
| 3763 | } | ||
| 3764 | if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { | ||
| 3765 | err("Failed to recognize the camera!"); | ||
| 3766 | return -ENODEV; | ||
| 3767 | } | ||
| 3768 | |||
| 3769 | /* Validate options */ | ||
| 3770 | switch (model) { | ||
| 3771 | case IBMCAM_MODEL_1: | ||
| 3772 | RESTRICT_TO_RANGE(lighting, 0, 2); | ||
| 3773 | RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288); | ||
| 3774 | if (framerate < 0) | ||
| 3775 | framerate = 2; | ||
| 3776 | canvasX = 352; | ||
| 3777 | canvasY = 288; | ||
| 3778 | break; | ||
| 3779 | case IBMCAM_MODEL_2: | ||
| 3780 | RESTRICT_TO_RANGE(lighting, 0, 15); | ||
| 3781 | RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240); | ||
| 3782 | if (framerate < 0) | ||
| 3783 | framerate = 2; | ||
| 3784 | canvasX = 352; | ||
| 3785 | canvasY = 240; | ||
| 3786 | break; | ||
| 3787 | case IBMCAM_MODEL_3: | ||
| 3788 | RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */ | ||
| 3789 | switch (size) { | ||
| 3790 | case SIZE_160x120: | ||
| 3791 | canvasX = 160; | ||
| 3792 | canvasY = 120; | ||
| 3793 | if (framerate < 0) | ||
| 3794 | framerate = 2; | ||
| 3795 | RESTRICT_TO_RANGE(framerate, 0, 5); | ||
| 3796 | break; | ||
| 3797 | default: | ||
| 3798 | info("IBM camera: using 320x240"); | ||
| 3799 | size = SIZE_320x240; | ||
| 3800 | /* No break here */ | ||
| 3801 | case SIZE_320x240: | ||
| 3802 | canvasX = 320; | ||
| 3803 | canvasY = 240; | ||
| 3804 | if (framerate < 0) | ||
| 3805 | framerate = 3; | ||
| 3806 | RESTRICT_TO_RANGE(framerate, 0, 5); | ||
| 3807 | break; | ||
| 3808 | case SIZE_640x480: | ||
| 3809 | canvasX = 640; | ||
| 3810 | canvasY = 480; | ||
| 3811 | framerate = 0; /* Slowest, and maybe even that is too fast */ | ||
| 3812 | break; | ||
| 3813 | } | ||
| 3814 | break; | ||
| 3815 | case IBMCAM_MODEL_4: | ||
| 3816 | RESTRICT_TO_RANGE(lighting, 0, 2); | ||
| 3817 | switch (size) { | ||
| 3818 | case SIZE_128x96: | ||
| 3819 | canvasX = 128; | ||
| 3820 | canvasY = 96; | ||
| 3821 | break; | ||
| 3822 | case SIZE_160x120: | ||
| 3823 | canvasX = 160; | ||
| 3824 | canvasY = 120; | ||
| 3825 | break; | ||
| 3826 | default: | ||
| 3827 | info("IBM NetCamera: using 176x144"); | ||
| 3828 | size = SIZE_176x144; | ||
| 3829 | /* No break here */ | ||
| 3830 | case SIZE_176x144: | ||
| 3831 | canvasX = 176; | ||
| 3832 | canvasY = 144; | ||
| 3833 | break; | ||
| 3834 | case SIZE_320x240: | ||
| 3835 | canvasX = 320; | ||
| 3836 | canvasY = 240; | ||
| 3837 | break; | ||
| 3838 | case SIZE_352x288: | ||
| 3839 | canvasX = 352; | ||
| 3840 | canvasY = 288; | ||
| 3841 | break; | ||
| 3842 | } | ||
| 3843 | break; | ||
| 3844 | default: | ||
| 3845 | err("IBM camera: Model %d. not supported!", model); | ||
| 3846 | return -ENODEV; | ||
| 3847 | } | ||
| 3848 | |||
| 3849 | uvd = usbvideo_AllocateDevice(cams); | ||
| 3850 | if (uvd != NULL) { | ||
| 3851 | /* Here uvd is a fully allocated uvd object */ | ||
| 3852 | uvd->flags = flags; | ||
| 3853 | uvd->debug = debug; | ||
| 3854 | uvd->dev = dev; | ||
| 3855 | uvd->iface = ifnum; | ||
| 3856 | uvd->ifaceAltInactive = inactInterface; | ||
| 3857 | uvd->ifaceAltActive = actInterface; | ||
| 3858 | uvd->video_endp = video_ep; | ||
| 3859 | uvd->iso_packet_len = maxPS; | ||
| 3860 | uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; | ||
| 3861 | uvd->defaultPalette = VIDEO_PALETTE_RGB24; | ||
| 3862 | uvd->canvas = VIDEOSIZE(canvasX, canvasY); | ||
| 3863 | uvd->videosize = ibmcam_size_to_videosize(size); | ||
| 3864 | |||
| 3865 | /* Initialize ibmcam-specific data */ | ||
| 3866 | assert(IBMCAM_T(uvd) != NULL); | ||
| 3867 | IBMCAM_T(uvd)->camera_model = model; | ||
| 3868 | IBMCAM_T(uvd)->initialized = 0; | ||
| 3869 | |||
| 3870 | ibmcam_configure_video(uvd); | ||
| 3871 | |||
| 3872 | i = usbvideo_RegisterVideoDevice(uvd); | ||
| 3873 | if (i != 0) { | ||
| 3874 | err("usbvideo_RegisterVideoDevice() failed."); | ||
| 3875 | uvd = NULL; | ||
| 3876 | } | ||
| 3877 | } | ||
| 3878 | usb_set_intfdata (intf, uvd); | ||
| 3879 | return 0; | ||
| 3880 | } | ||
| 3881 | |||
| 3882 | |||
| 3883 | static struct usb_device_id id_table[] = { | ||
| 3884 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) }, /* Model 1 */ | ||
| 3885 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */ | ||
| 3886 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) }, /* Model 3 */ | ||
| 3887 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */ | ||
| 3888 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */ | ||
| 3889 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */ | ||
| 3890 | { } /* Terminating entry */ | ||
| 3891 | }; | ||
| 3892 | |||
| 3893 | /* | ||
| 3894 | * ibmcam_init() | ||
| 3895 | * | ||
| 3896 | * This code is run to initialize the driver. | ||
| 3897 | * | ||
| 3898 | * History: | ||
| 3899 | * 1/27/00 Reworked to use statically allocated ibmcam structures. | ||
| 3900 | * 21/10/00 Completely redesigned to use usbvideo services. | ||
| 3901 | */ | ||
| 3902 | static int __init ibmcam_init(void) | ||
| 3903 | { | ||
| 3904 | struct usbvideo_cb cbTbl; | ||
| 3905 | memset(&cbTbl, 0, sizeof(cbTbl)); | ||
| 3906 | cbTbl.probe = ibmcam_probe; | ||
| 3907 | cbTbl.setupOnOpen = ibmcam_setup_on_open; | ||
| 3908 | cbTbl.videoStart = ibmcam_video_start; | ||
| 3909 | cbTbl.videoStop = ibmcam_video_stop; | ||
| 3910 | cbTbl.processData = ibmcam_ProcessIsocData; | ||
| 3911 | cbTbl.postProcess = usbvideo_DeinterlaceFrame; | ||
| 3912 | cbTbl.adjustPicture = ibmcam_adjust_picture; | ||
| 3913 | cbTbl.getFPS = ibmcam_calculate_fps; | ||
| 3914 | return usbvideo_register( | ||
| 3915 | &cams, | ||
| 3916 | MAX_IBMCAM, | ||
| 3917 | sizeof(ibmcam_t), | ||
| 3918 | "ibmcam", | ||
| 3919 | &cbTbl, | ||
| 3920 | THIS_MODULE, | ||
| 3921 | id_table); | ||
| 3922 | } | ||
| 3923 | |||
| 3924 | static void __exit ibmcam_cleanup(void) | ||
| 3925 | { | ||
| 3926 | usbvideo_Deregister(&cams); | ||
| 3927 | } | ||
| 3928 | |||
| 3929 | MODULE_DEVICE_TABLE(usb, id_table); | ||
| 3930 | |||
| 3931 | module_init(ibmcam_init); | ||
| 3932 | module_exit(ibmcam_cleanup); | ||
diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c deleted file mode 100644 index e2ede583518f..000000000000 --- a/drivers/usb/media/konicawc.c +++ /dev/null | |||
| @@ -1,978 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * konicawc.c - konica webcam driver | ||
| 3 | * | ||
| 4 | * Author: Simon Evans <spse@secret.org.uk> | ||
| 5 | * | ||
| 6 | * Copyright (C) 2002 Simon Evans | ||
| 7 | * | ||
| 8 | * Licence: GPL | ||
| 9 | * | ||
| 10 | * Driver for USB webcams based on Konica chipset. This | ||
| 11 | * chipset is used in Intel YC76 camera. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/input.h> | ||
| 19 | #include <linux/usb_input.h> | ||
| 20 | |||
| 21 | #include "usbvideo.h" | ||
| 22 | |||
| 23 | #define MAX_BRIGHTNESS 108 | ||
| 24 | #define MAX_CONTRAST 108 | ||
| 25 | #define MAX_SATURATION 108 | ||
| 26 | #define MAX_SHARPNESS 108 | ||
| 27 | #define MAX_WHITEBAL 372 | ||
| 28 | #define MAX_SPEED 6 | ||
| 29 | |||
| 30 | |||
| 31 | #define MAX_CAMERAS 1 | ||
| 32 | |||
| 33 | #define DRIVER_VERSION "v1.4" | ||
| 34 | #define DRIVER_DESC "Konica Webcam driver" | ||
| 35 | |||
| 36 | enum ctrl_req { | ||
| 37 | SetWhitebal = 0x01, | ||
| 38 | SetBrightness = 0x02, | ||
| 39 | SetSharpness = 0x03, | ||
| 40 | SetContrast = 0x04, | ||
| 41 | SetSaturation = 0x05, | ||
| 42 | }; | ||
| 43 | |||
| 44 | |||
| 45 | enum frame_sizes { | ||
| 46 | SIZE_160X120 = 0, | ||
| 47 | SIZE_160X136 = 1, | ||
| 48 | SIZE_176X144 = 2, | ||
| 49 | SIZE_320X240 = 3, | ||
| 50 | |||
| 51 | }; | ||
| 52 | |||
| 53 | #define MAX_FRAME_SIZE SIZE_320X240 | ||
| 54 | |||
| 55 | static struct usbvideo *cams; | ||
| 56 | |||
| 57 | #ifdef CONFIG_USB_DEBUG | ||
| 58 | static int debug; | ||
| 59 | #define DEBUG(n, format, arg...) \ | ||
| 60 | if (n <= debug) { \ | ||
| 61 | printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \ | ||
| 62 | } | ||
| 63 | #else | ||
| 64 | #define DEBUG(n, arg...) | ||
| 65 | static const int debug = 0; | ||
| 66 | #endif | ||
| 67 | |||
| 68 | |||
| 69 | /* Some default values for initial camera settings, | ||
| 70 | can be set by modprobe */ | ||
| 71 | |||
| 72 | static int size; | ||
| 73 | static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */ | ||
| 74 | static int brightness = MAX_BRIGHTNESS/2; | ||
| 75 | static int contrast = MAX_CONTRAST/2; | ||
| 76 | static int saturation = MAX_SATURATION/2; | ||
| 77 | static int sharpness = MAX_SHARPNESS/2; | ||
| 78 | static int whitebal = 3*(MAX_WHITEBAL/4); | ||
| 79 | |||
| 80 | static const int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 }; | ||
| 81 | |||
| 82 | /* These FPS speeds are from the windows config box. They are | ||
| 83 | * indexed on size (0-2) and speed (0-6). Divide by 3 to get the | ||
| 84 | * real fps. | ||
| 85 | */ | ||
| 86 | |||
| 87 | static const int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 }, | ||
| 88 | { 24, 40, 48, 60, 72, 80, 100 }, | ||
| 89 | { 18, 30, 36, 45, 54, 60, 75 }, | ||
| 90 | { 6, 10, 12, 15, 18, 21, 25 } }; | ||
| 91 | |||
| 92 | struct cam_size { | ||
| 93 | u16 width; | ||
| 94 | u16 height; | ||
| 95 | u8 cmd; | ||
| 96 | }; | ||
| 97 | |||
| 98 | static const struct cam_size camera_sizes[] = { { 160, 120, 0x7 }, | ||
| 99 | { 160, 136, 0xa }, | ||
| 100 | { 176, 144, 0x4 }, | ||
| 101 | { 320, 240, 0x5 } }; | ||
| 102 | |||
| 103 | struct konicawc { | ||
| 104 | u8 brightness; /* camera uses 0 - 9, x11 for real value */ | ||
| 105 | u8 contrast; /* as above */ | ||
| 106 | u8 saturation; /* as above */ | ||
| 107 | u8 sharpness; /* as above */ | ||
| 108 | u8 white_bal; /* 0 - 33, x11 for real value */ | ||
| 109 | u8 speed; /* Stored as 0 - 6, used as index in spd_to_* (above) */ | ||
| 110 | u8 size; /* Frame Size */ | ||
| 111 | int height; | ||
| 112 | int width; | ||
| 113 | struct urb *sts_urb[USBVIDEO_NUMSBUF]; | ||
| 114 | u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC]; | ||
| 115 | struct urb *last_data_urb; | ||
| 116 | int lastframe; | ||
| 117 | int cur_frame_size; /* number of bytes in current frame size */ | ||
| 118 | int maxline; /* number of lines per frame */ | ||
| 119 | int yplanesz; /* Number of bytes in the Y plane */ | ||
| 120 | unsigned int buttonsts:1; | ||
| 121 | #ifdef CONFIG_INPUT | ||
| 122 | struct input_dev *input; | ||
| 123 | char input_physname[64]; | ||
| 124 | #endif | ||
| 125 | }; | ||
| 126 | |||
| 127 | |||
| 128 | #define konicawc_set_misc(uvd, req, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0) | ||
| 129 | #define konicawc_get_misc(uvd, req, value, index, buf, sz) konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz) | ||
| 130 | #define konicawc_set_value(uvd, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0) | ||
| 131 | |||
| 132 | |||
| 133 | static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len) | ||
| 134 | { | ||
| 135 | int retval = usb_control_msg(uvd->dev, | ||
| 136 | dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0), | ||
| 137 | request, 0x40 | dir, value, index, buf, len, 1000); | ||
| 138 | return retval < 0 ? retval : 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | |||
| 142 | static inline void konicawc_camera_on(struct uvd *uvd) | ||
| 143 | { | ||
| 144 | DEBUG(0, "camera on"); | ||
| 145 | konicawc_set_misc(uvd, 0x2, 1, 0x0b); | ||
| 146 | } | ||
| 147 | |||
| 148 | |||
| 149 | static inline void konicawc_camera_off(struct uvd *uvd) | ||
| 150 | { | ||
| 151 | DEBUG(0, "camera off"); | ||
| 152 | konicawc_set_misc(uvd, 0x2, 0, 0x0b); | ||
| 153 | } | ||
| 154 | |||
| 155 | |||
| 156 | static void konicawc_set_camera_size(struct uvd *uvd) | ||
| 157 | { | ||
| 158 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 159 | |||
| 160 | konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08); | ||
| 161 | cam->width = camera_sizes[cam->size].width; | ||
| 162 | cam->height = camera_sizes[cam->size].height; | ||
| 163 | cam->yplanesz = cam->height * cam->width; | ||
| 164 | cam->cur_frame_size = (cam->yplanesz * 3) / 2; | ||
| 165 | cam->maxline = cam->yplanesz / 256; | ||
| 166 | uvd->videosize = VIDEOSIZE(cam->width, cam->height); | ||
| 167 | } | ||
| 168 | |||
| 169 | |||
| 170 | static int konicawc_setup_on_open(struct uvd *uvd) | ||
| 171 | { | ||
| 172 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 173 | |||
| 174 | DEBUG(1, "setting brightness to %d (%d)", cam->brightness, | ||
| 175 | cam->brightness * 11); | ||
| 176 | konicawc_set_value(uvd, cam->brightness, SetBrightness); | ||
| 177 | DEBUG(1, "setting white balance to %d (%d)", cam->white_bal, | ||
| 178 | cam->white_bal * 11); | ||
| 179 | konicawc_set_value(uvd, cam->white_bal, SetWhitebal); | ||
| 180 | DEBUG(1, "setting contrast to %d (%d)", cam->contrast, | ||
| 181 | cam->contrast * 11); | ||
| 182 | konicawc_set_value(uvd, cam->contrast, SetContrast); | ||
| 183 | DEBUG(1, "setting saturation to %d (%d)", cam->saturation, | ||
| 184 | cam->saturation * 11); | ||
| 185 | konicawc_set_value(uvd, cam->saturation, SetSaturation); | ||
| 186 | DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness, | ||
| 187 | cam->sharpness * 11); | ||
| 188 | konicawc_set_value(uvd, cam->sharpness, SetSharpness); | ||
| 189 | konicawc_set_camera_size(uvd); | ||
| 190 | cam->lastframe = -2; | ||
| 191 | cam->buttonsts = 0; | ||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | |||
| 196 | static void konicawc_adjust_picture(struct uvd *uvd) | ||
| 197 | { | ||
| 198 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 199 | |||
| 200 | konicawc_camera_off(uvd); | ||
| 201 | DEBUG(1, "new brightness: %d", uvd->vpic.brightness); | ||
| 202 | uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness; | ||
| 203 | if(cam->brightness != uvd->vpic.brightness / 11) { | ||
| 204 | cam->brightness = uvd->vpic.brightness / 11; | ||
| 205 | DEBUG(1, "setting brightness to %d (%d)", cam->brightness, | ||
| 206 | cam->brightness * 11); | ||
| 207 | konicawc_set_value(uvd, cam->brightness, SetBrightness); | ||
| 208 | } | ||
| 209 | |||
| 210 | DEBUG(1, "new contrast: %d", uvd->vpic.contrast); | ||
| 211 | uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast; | ||
| 212 | if(cam->contrast != uvd->vpic.contrast / 11) { | ||
| 213 | cam->contrast = uvd->vpic.contrast / 11; | ||
| 214 | DEBUG(1, "setting contrast to %d (%d)", cam->contrast, | ||
| 215 | cam->contrast * 11); | ||
| 216 | konicawc_set_value(uvd, cam->contrast, SetContrast); | ||
| 217 | } | ||
| 218 | konicawc_camera_on(uvd); | ||
| 219 | } | ||
| 220 | |||
| 221 | #ifdef CONFIG_INPUT | ||
| 222 | |||
| 223 | static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) | ||
| 224 | { | ||
| 225 | struct input_dev *input_dev; | ||
| 226 | |||
| 227 | usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname)); | ||
| 228 | strncat(cam->input_physname, "/input0", sizeof(cam->input_physname)); | ||
| 229 | |||
| 230 | cam->input = input_dev = input_allocate_device(); | ||
| 231 | if (!input_dev) { | ||
| 232 | warn("Not enough memory for camera's input device\n"); | ||
| 233 | return; | ||
| 234 | } | ||
| 235 | |||
| 236 | input_dev->name = "Konicawc snapshot button"; | ||
| 237 | input_dev->phys = cam->input_physname; | ||
| 238 | usb_to_input_id(dev, &input_dev->id); | ||
| 239 | input_dev->cdev.dev = &dev->dev; | ||
| 240 | |||
| 241 | input_dev->evbit[0] = BIT(EV_KEY); | ||
| 242 | input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); | ||
| 243 | |||
| 244 | input_dev->private = cam; | ||
| 245 | |||
| 246 | input_register_device(cam->input); | ||
| 247 | } | ||
| 248 | |||
| 249 | static void konicawc_unregister_input(struct konicawc *cam) | ||
| 250 | { | ||
| 251 | if (cam->input) { | ||
| 252 | input_unregister_device(cam->input); | ||
| 253 | cam->input = NULL; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | static void konicawc_report_buttonstat(struct konicawc *cam) | ||
| 258 | { | ||
| 259 | if (cam->input) { | ||
| 260 | input_report_key(cam->input, BTN_0, cam->buttonsts); | ||
| 261 | input_sync(cam->input); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | #else | ||
| 266 | |||
| 267 | static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { } | ||
| 268 | static inline void konicawc_unregister_input(struct konicawc *cam) { } | ||
| 269 | static inline void konicawc_report_buttonstat(struct konicawc *cam) { } | ||
| 270 | |||
| 271 | #endif /* CONFIG_INPUT */ | ||
| 272 | |||
| 273 | static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb) | ||
| 274 | { | ||
| 275 | char *cdata; | ||
| 276 | int i, totlen = 0; | ||
| 277 | unsigned char *status = stsurb->transfer_buffer; | ||
| 278 | int keep = 0, discard = 0, bad = 0; | ||
| 279 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 280 | |||
| 281 | for (i = 0; i < dataurb->number_of_packets; i++) { | ||
| 282 | int button = cam->buttonsts; | ||
| 283 | unsigned char sts; | ||
| 284 | int n = dataurb->iso_frame_desc[i].actual_length; | ||
| 285 | int st = dataurb->iso_frame_desc[i].status; | ||
| 286 | cdata = dataurb->transfer_buffer + | ||
| 287 | dataurb->iso_frame_desc[i].offset; | ||
| 288 | |||
| 289 | /* Detect and ignore errored packets */ | ||
| 290 | if (st < 0) { | ||
| 291 | DEBUG(1, "Data error: packet=%d. len=%d. status=%d.", | ||
| 292 | i, n, st); | ||
| 293 | uvd->stats.iso_err_count++; | ||
| 294 | continue; | ||
| 295 | } | ||
| 296 | |||
| 297 | /* Detect and ignore empty packets */ | ||
| 298 | if (n <= 0) { | ||
| 299 | uvd->stats.iso_skip_count++; | ||
| 300 | continue; | ||
| 301 | } | ||
| 302 | |||
| 303 | /* See what the status data said about the packet */ | ||
| 304 | sts = *(status+stsurb->iso_frame_desc[i].offset); | ||
| 305 | |||
| 306 | /* sts: 0x80-0xff: frame start with frame number (ie 0-7f) | ||
| 307 | * otherwise: | ||
| 308 | * bit 0 0: keep packet | ||
| 309 | * 1: drop packet (padding data) | ||
| 310 | * | ||
| 311 | * bit 4 0 button not clicked | ||
| 312 | * 1 button clicked | ||
| 313 | * button is used to `take a picture' (in software) | ||
| 314 | */ | ||
| 315 | |||
| 316 | if(sts < 0x80) { | ||
| 317 | button = !!(sts & 0x40); | ||
| 318 | sts &= ~0x40; | ||
| 319 | } | ||
| 320 | |||
| 321 | /* work out the button status, but don't do | ||
| 322 | anything with it for now */ | ||
| 323 | |||
| 324 | if(button != cam->buttonsts) { | ||
| 325 | DEBUG(2, "button: %sclicked", button ? "" : "un"); | ||
| 326 | cam->buttonsts = button; | ||
| 327 | konicawc_report_buttonstat(cam); | ||
| 328 | } | ||
| 329 | |||
| 330 | if(sts == 0x01) { /* drop frame */ | ||
| 331 | discard++; | ||
| 332 | continue; | ||
| 333 | } | ||
| 334 | |||
| 335 | if((sts > 0x01) && (sts < 0x80)) { | ||
| 336 | info("unknown status %2.2x", sts); | ||
| 337 | bad++; | ||
| 338 | continue; | ||
| 339 | } | ||
| 340 | if(!sts && cam->lastframe == -2) { | ||
| 341 | DEBUG(2, "dropping frame looking for image start"); | ||
| 342 | continue; | ||
| 343 | } | ||
| 344 | |||
| 345 | keep++; | ||
| 346 | if(sts & 0x80) { /* frame start */ | ||
| 347 | unsigned char marker[] = { 0, 0xff, 0, 0x00 }; | ||
| 348 | |||
| 349 | if(cam->lastframe == -2) { | ||
| 350 | DEBUG(2, "found initial image"); | ||
| 351 | cam->lastframe = -1; | ||
| 352 | } | ||
| 353 | |||
| 354 | marker[3] = sts & 0x7F; | ||
| 355 | RingQueue_Enqueue(&uvd->dp, marker, 4); | ||
| 356 | totlen += 4; | ||
| 357 | } | ||
| 358 | |||
| 359 | totlen += n; /* Little local accounting */ | ||
| 360 | RingQueue_Enqueue(&uvd->dp, cdata, n); | ||
| 361 | } | ||
| 362 | DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes", | ||
| 363 | keep, discard, bad, totlen); | ||
| 364 | return totlen; | ||
| 365 | } | ||
| 366 | |||
| 367 | |||
| 368 | static void resubmit_urb(struct uvd *uvd, struct urb *urb) | ||
| 369 | { | ||
| 370 | int i, ret; | ||
| 371 | for (i = 0; i < FRAMES_PER_DESC; i++) { | ||
| 372 | urb->iso_frame_desc[i].status = 0; | ||
| 373 | } | ||
| 374 | urb->dev = uvd->dev; | ||
| 375 | urb->status = 0; | ||
| 376 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 377 | DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length); | ||
| 378 | if(ret) | ||
| 379 | err("usb_submit_urb error (%d)", ret); | ||
| 380 | |||
| 381 | } | ||
| 382 | |||
| 383 | |||
| 384 | static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs) | ||
| 385 | { | ||
| 386 | struct uvd *uvd = urb->context; | ||
| 387 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 388 | |||
| 389 | /* We don't want to do anything if we are about to be removed! */ | ||
| 390 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
| 391 | return; | ||
| 392 | |||
| 393 | if (!uvd->streaming) { | ||
| 394 | DEBUG(1, "Not streaming, but interrupt!"); | ||
| 395 | return; | ||
| 396 | } | ||
| 397 | |||
| 398 | DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length); | ||
| 399 | |||
| 400 | uvd->stats.urb_count++; | ||
| 401 | |||
| 402 | if (urb->transfer_buffer_length > 32) { | ||
| 403 | cam->last_data_urb = urb; | ||
| 404 | return; | ||
| 405 | } | ||
| 406 | /* Copy the data received into ring queue */ | ||
| 407 | if(cam->last_data_urb) { | ||
| 408 | int len = 0; | ||
| 409 | if(urb->start_frame != cam->last_data_urb->start_frame) | ||
| 410 | err("Lost sync on frames"); | ||
| 411 | else if (!urb->status && !cam->last_data_urb->status) | ||
| 412 | len = konicawc_compress_iso(uvd, cam->last_data_urb, urb); | ||
| 413 | |||
| 414 | resubmit_urb(uvd, cam->last_data_urb); | ||
| 415 | resubmit_urb(uvd, urb); | ||
| 416 | cam->last_data_urb = NULL; | ||
| 417 | uvd->stats.urb_length = len; | ||
| 418 | uvd->stats.data_count += len; | ||
| 419 | if(len) | ||
| 420 | RingQueue_WakeUpInterruptible(&uvd->dp); | ||
| 421 | return; | ||
| 422 | } | ||
| 423 | return; | ||
| 424 | } | ||
| 425 | |||
| 426 | |||
| 427 | static int konicawc_start_data(struct uvd *uvd) | ||
| 428 | { | ||
| 429 | struct usb_device *dev = uvd->dev; | ||
| 430 | int i, errFlag; | ||
| 431 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 432 | int pktsz; | ||
| 433 | struct usb_interface *intf; | ||
| 434 | struct usb_host_interface *interface = NULL; | ||
| 435 | |||
| 436 | intf = usb_ifnum_to_if(dev, uvd->iface); | ||
| 437 | if (intf) | ||
| 438 | interface = usb_altnum_to_altsetting(intf, | ||
| 439 | spd_to_iface[cam->speed]); | ||
| 440 | if (!interface) | ||
| 441 | return -ENXIO; | ||
| 442 | pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize); | ||
| 443 | DEBUG(1, "pktsz = %d", pktsz); | ||
| 444 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
| 445 | err("Camera is not operational"); | ||
| 446 | return -EFAULT; | ||
| 447 | } | ||
| 448 | uvd->curframe = -1; | ||
| 449 | konicawc_camera_on(uvd); | ||
| 450 | /* Alternate interface 1 is is the biggest frame size */ | ||
| 451 | i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); | ||
| 452 | if (i < 0) { | ||
| 453 | err("usb_set_interface error"); | ||
| 454 | uvd->last_error = i; | ||
| 455 | return -EBUSY; | ||
| 456 | } | ||
| 457 | |||
| 458 | /* We double buffer the Iso lists */ | ||
| 459 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 460 | int j, k; | ||
| 461 | struct urb *urb = uvd->sbuf[i].urb; | ||
| 462 | urb->dev = dev; | ||
| 463 | urb->context = uvd; | ||
| 464 | urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); | ||
| 465 | urb->interval = 1; | ||
| 466 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 467 | urb->transfer_buffer = uvd->sbuf[i].data; | ||
| 468 | urb->complete = konicawc_isoc_irq; | ||
| 469 | urb->number_of_packets = FRAMES_PER_DESC; | ||
| 470 | urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC; | ||
| 471 | for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) { | ||
| 472 | urb->iso_frame_desc[j].offset = k; | ||
| 473 | urb->iso_frame_desc[j].length = pktsz; | ||
| 474 | } | ||
| 475 | |||
| 476 | urb = cam->sts_urb[i]; | ||
| 477 | urb->dev = dev; | ||
| 478 | urb->context = uvd; | ||
| 479 | urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1); | ||
| 480 | urb->interval = 1; | ||
| 481 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 482 | urb->transfer_buffer = cam->sts_buf[i]; | ||
| 483 | urb->complete = konicawc_isoc_irq; | ||
| 484 | urb->number_of_packets = FRAMES_PER_DESC; | ||
| 485 | urb->transfer_buffer_length = FRAMES_PER_DESC; | ||
| 486 | for (j=0; j < FRAMES_PER_DESC; j++) { | ||
| 487 | urb->iso_frame_desc[j].offset = j; | ||
| 488 | urb->iso_frame_desc[j].length = 1; | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | cam->last_data_urb = NULL; | ||
| 493 | |||
| 494 | /* Submit all URBs */ | ||
| 495 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 496 | errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL); | ||
| 497 | if (errFlag) | ||
| 498 | err("usb_submit_isoc(%d) ret %d", i, errFlag); | ||
| 499 | |||
| 500 | errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); | ||
| 501 | if (errFlag) | ||
| 502 | err ("usb_submit_isoc(%d) ret %d", i, errFlag); | ||
| 503 | } | ||
| 504 | |||
| 505 | uvd->streaming = 1; | ||
| 506 | DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp); | ||
| 507 | return 0; | ||
| 508 | } | ||
| 509 | |||
| 510 | |||
| 511 | static void konicawc_stop_data(struct uvd *uvd) | ||
| 512 | { | ||
| 513 | int i, j; | ||
| 514 | struct konicawc *cam; | ||
| 515 | |||
| 516 | if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) | ||
| 517 | return; | ||
| 518 | |||
| 519 | konicawc_camera_off(uvd); | ||
| 520 | uvd->streaming = 0; | ||
| 521 | cam = (struct konicawc *)uvd->user_data; | ||
| 522 | cam->last_data_urb = NULL; | ||
| 523 | |||
| 524 | /* Unschedule all of the iso td's */ | ||
| 525 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 526 | usb_kill_urb(uvd->sbuf[i].urb); | ||
| 527 | usb_kill_urb(cam->sts_urb[i]); | ||
| 528 | } | ||
| 529 | |||
| 530 | if (!uvd->remove_pending) { | ||
| 531 | /* Set packet size to 0 */ | ||
| 532 | j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); | ||
| 533 | if (j < 0) { | ||
| 534 | err("usb_set_interface() error %d.", j); | ||
| 535 | uvd->last_error = j; | ||
| 536 | } | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | |||
| 541 | static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame) | ||
| 542 | { | ||
| 543 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 544 | int maxline = cam->maxline; | ||
| 545 | int yplanesz = cam->yplanesz; | ||
| 546 | |||
| 547 | assert(frame != NULL); | ||
| 548 | |||
| 549 | DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz); | ||
| 550 | DEBUG(3, "Frame state = %d", frame->scanstate); | ||
| 551 | |||
| 552 | if(frame->scanstate == ScanState_Scanning) { | ||
| 553 | int drop = 0; | ||
| 554 | int curframe; | ||
| 555 | int fdrops = 0; | ||
| 556 | DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp)); | ||
| 557 | while(RingQueue_GetLength(&uvd->dp) >= 4) { | ||
| 558 | if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && | ||
| 559 | (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) && | ||
| 560 | (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) && | ||
| 561 | (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) { | ||
| 562 | curframe = RING_QUEUE_PEEK(&uvd->dp, 3); | ||
| 563 | if(cam->lastframe >= 0) { | ||
| 564 | fdrops = (0x80 + curframe - cam->lastframe) & 0x7F; | ||
| 565 | fdrops--; | ||
| 566 | if(fdrops) { | ||
| 567 | info("Dropped %d frames (%d -> %d)", fdrops, | ||
| 568 | cam->lastframe, curframe); | ||
| 569 | } | ||
| 570 | } | ||
| 571 | cam->lastframe = curframe; | ||
| 572 | frame->curline = 0; | ||
| 573 | frame->scanstate = ScanState_Lines; | ||
| 574 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4); | ||
| 575 | break; | ||
| 576 | } | ||
| 577 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); | ||
| 578 | drop++; | ||
| 579 | } | ||
| 580 | if(drop) | ||
| 581 | DEBUG(2, "dropped %d bytes looking for new frame", drop); | ||
| 582 | } | ||
| 583 | |||
| 584 | if(frame->scanstate == ScanState_Scanning) | ||
| 585 | return; | ||
| 586 | |||
| 587 | /* Try to move data from queue into frame buffer | ||
| 588 | * We get data in blocks of 384 bytes made up of: | ||
| 589 | * 256 Y, 64 U, 64 V. | ||
| 590 | * This needs to be written out as a Y plane, a U plane and a V plane. | ||
| 591 | */ | ||
| 592 | |||
| 593 | while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) { | ||
| 594 | /* Y */ | ||
| 595 | RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256); | ||
| 596 | /* U */ | ||
| 597 | RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64); | ||
| 598 | /* V */ | ||
| 599 | RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64); | ||
| 600 | frame->seqRead_Length += 384; | ||
| 601 | frame->curline++; | ||
| 602 | } | ||
| 603 | /* See if we filled the frame */ | ||
| 604 | if (frame->curline == maxline) { | ||
| 605 | DEBUG(5, "got whole frame"); | ||
| 606 | |||
| 607 | frame->frameState = FrameState_Done_Hold; | ||
| 608 | frame->curline = 0; | ||
| 609 | uvd->curframe = -1; | ||
| 610 | uvd->stats.frame_num++; | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | |||
| 615 | static int konicawc_find_fps(int size, int fps) | ||
| 616 | { | ||
| 617 | int i; | ||
| 618 | |||
| 619 | fps *= 3; | ||
| 620 | DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps); | ||
| 621 | if(fps <= spd_to_fps[size][0]) | ||
| 622 | return 0; | ||
| 623 | |||
| 624 | if(fps >= spd_to_fps[size][MAX_SPEED]) | ||
| 625 | return MAX_SPEED; | ||
| 626 | |||
| 627 | for(i = 0; i < MAX_SPEED; i++) { | ||
| 628 | if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) { | ||
| 629 | DEBUG(2, "fps %d between %d and %d", fps, i, i+1); | ||
| 630 | if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps)) | ||
| 631 | return i; | ||
| 632 | else | ||
| 633 | return i+1; | ||
| 634 | } | ||
| 635 | } | ||
| 636 | return MAX_SPEED+1; | ||
| 637 | } | ||
| 638 | |||
| 639 | |||
| 640 | static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw) | ||
| 641 | { | ||
| 642 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 643 | int newspeed = cam->speed; | ||
| 644 | int newsize; | ||
| 645 | int x = vw->width; | ||
| 646 | int y = vw->height; | ||
| 647 | int fps = vw->flags; | ||
| 648 | |||
| 649 | if(x > 0 && y > 0) { | ||
| 650 | DEBUG(2, "trying to find size %d,%d", x, y); | ||
| 651 | for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) { | ||
| 652 | if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y)) | ||
| 653 | break; | ||
| 654 | } | ||
| 655 | } else { | ||
| 656 | newsize = cam->size; | ||
| 657 | } | ||
| 658 | |||
| 659 | if(newsize > MAX_FRAME_SIZE) { | ||
| 660 | DEBUG(1, "couldn't find size %d,%d", x, y); | ||
| 661 | return -EINVAL; | ||
| 662 | } | ||
| 663 | |||
| 664 | if(fps > 0) { | ||
| 665 | DEBUG(1, "trying to set fps to %d", fps); | ||
| 666 | newspeed = konicawc_find_fps(newsize, fps); | ||
| 667 | DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]); | ||
| 668 | } | ||
| 669 | |||
| 670 | if(newspeed > MAX_SPEED) | ||
| 671 | return -EINVAL; | ||
| 672 | |||
| 673 | DEBUG(1, "setting size to %d speed to %d", newsize, newspeed); | ||
| 674 | if((newsize == cam->size) && (newspeed == cam->speed)) { | ||
| 675 | DEBUG(1, "Nothing to do"); | ||
| 676 | return 0; | ||
| 677 | } | ||
| 678 | DEBUG(0, "setting to %dx%d @ %d fps", camera_sizes[newsize].width, | ||
| 679 | camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3); | ||
| 680 | |||
| 681 | konicawc_stop_data(uvd); | ||
| 682 | uvd->ifaceAltActive = spd_to_iface[newspeed]; | ||
| 683 | DEBUG(1, "new interface = %d", uvd->ifaceAltActive); | ||
| 684 | cam->speed = newspeed; | ||
| 685 | |||
| 686 | if(cam->size != newsize) { | ||
| 687 | cam->size = newsize; | ||
| 688 | konicawc_set_camera_size(uvd); | ||
| 689 | } | ||
| 690 | |||
| 691 | /* Flush the input queue and clear any current frame in progress */ | ||
| 692 | |||
| 693 | RingQueue_Flush(&uvd->dp); | ||
| 694 | cam->lastframe = -2; | ||
| 695 | if(uvd->curframe != -1) { | ||
| 696 | uvd->frame[uvd->curframe].curline = 0; | ||
| 697 | uvd->frame[uvd->curframe].seqRead_Length = 0; | ||
| 698 | uvd->frame[uvd->curframe].seqRead_Index = 0; | ||
| 699 | } | ||
| 700 | |||
| 701 | konicawc_start_data(uvd); | ||
| 702 | return 0; | ||
| 703 | } | ||
| 704 | |||
| 705 | |||
| 706 | static int konicawc_calculate_fps(struct uvd *uvd) | ||
| 707 | { | ||
| 708 | struct konicawc *cam = uvd->user_data; | ||
| 709 | return spd_to_fps[cam->size][cam->speed]/3; | ||
| 710 | } | ||
| 711 | |||
| 712 | |||
| 713 | static void konicawc_configure_video(struct uvd *uvd) | ||
| 714 | { | ||
| 715 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 716 | u8 buf[2]; | ||
| 717 | |||
| 718 | memset(&uvd->vpic, 0, sizeof(uvd->vpic)); | ||
| 719 | memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); | ||
| 720 | |||
| 721 | RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS); | ||
| 722 | RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST); | ||
| 723 | RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION); | ||
| 724 | RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS); | ||
| 725 | RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL); | ||
| 726 | |||
| 727 | cam->brightness = brightness / 11; | ||
| 728 | cam->contrast = contrast / 11; | ||
| 729 | cam->saturation = saturation / 11; | ||
| 730 | cam->sharpness = sharpness / 11; | ||
| 731 | cam->white_bal = whitebal / 11; | ||
| 732 | |||
| 733 | uvd->vpic.colour = 108; | ||
| 734 | uvd->vpic.hue = 108; | ||
| 735 | uvd->vpic.brightness = brightness; | ||
| 736 | uvd->vpic.contrast = contrast; | ||
| 737 | uvd->vpic.whiteness = whitebal; | ||
| 738 | uvd->vpic.depth = 6; | ||
| 739 | uvd->vpic.palette = VIDEO_PALETTE_YUV420P; | ||
| 740 | |||
| 741 | memset(&uvd->vcap, 0, sizeof(uvd->vcap)); | ||
| 742 | strcpy(uvd->vcap.name, "Konica Webcam"); | ||
| 743 | uvd->vcap.type = VID_TYPE_CAPTURE; | ||
| 744 | uvd->vcap.channels = 1; | ||
| 745 | uvd->vcap.audios = 0; | ||
| 746 | uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width; | ||
| 747 | uvd->vcap.minheight = camera_sizes[SIZE_160X120].height; | ||
| 748 | uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width; | ||
| 749 | uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height; | ||
| 750 | |||
| 751 | memset(&uvd->vchan, 0, sizeof(uvd->vchan)); | ||
| 752 | uvd->vchan.flags = 0 ; | ||
| 753 | uvd->vchan.tuners = 0; | ||
| 754 | uvd->vchan.channel = 0; | ||
| 755 | uvd->vchan.type = VIDEO_TYPE_CAMERA; | ||
| 756 | strcpy(uvd->vchan.name, "Camera"); | ||
| 757 | |||
| 758 | /* Talk to device */ | ||
| 759 | DEBUG(1, "device init"); | ||
| 760 | if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2)) | ||
| 761 | DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]); | ||
| 762 | if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2)) | ||
| 763 | DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]); | ||
| 764 | if(konicawc_set_misc(uvd, 0x2, 0, 0xd)) | ||
| 765 | DEBUG(2, "2,0,d failed"); | ||
| 766 | DEBUG(1, "setting initial values"); | ||
| 767 | } | ||
| 768 | |||
| 769 | static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid) | ||
| 770 | { | ||
| 771 | struct usb_device *dev = interface_to_usbdev(intf); | ||
| 772 | struct uvd *uvd = NULL; | ||
| 773 | int ix, i, nas; | ||
| 774 | int actInterface=-1, inactInterface=-1, maxPS=0; | ||
| 775 | unsigned char video_ep = 0; | ||
| 776 | |||
| 777 | DEBUG(1, "konicawc_probe(%p)", intf); | ||
| 778 | |||
| 779 | /* We don't handle multi-config cameras */ | ||
| 780 | if (dev->descriptor.bNumConfigurations != 1) | ||
| 781 | return -ENODEV; | ||
| 782 | |||
| 783 | info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice)); | ||
| 784 | RESTRICT_TO_RANGE(speed, 0, MAX_SPEED); | ||
| 785 | |||
| 786 | /* Validate found interface: must have one ISO endpoint */ | ||
| 787 | nas = intf->num_altsetting; | ||
| 788 | if (nas != 8) { | ||
| 789 | err("Incorrect number of alternate settings (%d) for this camera!", nas); | ||
| 790 | return -ENODEV; | ||
| 791 | } | ||
| 792 | /* Validate all alternate settings */ | ||
| 793 | for (ix=0; ix < nas; ix++) { | ||
| 794 | const struct usb_host_interface *interface; | ||
| 795 | const struct usb_endpoint_descriptor *endpoint; | ||
| 796 | |||
| 797 | interface = &intf->altsetting[ix]; | ||
| 798 | i = interface->desc.bAlternateSetting; | ||
| 799 | if (interface->desc.bNumEndpoints != 2) { | ||
| 800 | err("Interface %d. has %u. endpoints!", | ||
| 801 | interface->desc.bInterfaceNumber, | ||
| 802 | (unsigned)(interface->desc.bNumEndpoints)); | ||
| 803 | return -ENODEV; | ||
| 804 | } | ||
| 805 | endpoint = &interface->endpoint[1].desc; | ||
| 806 | DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x", | ||
| 807 | endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize)); | ||
| 808 | if (video_ep == 0) | ||
| 809 | video_ep = endpoint->bEndpointAddress; | ||
| 810 | else if (video_ep != endpoint->bEndpointAddress) { | ||
| 811 | err("Alternate settings have different endpoint addresses!"); | ||
| 812 | return -ENODEV; | ||
| 813 | } | ||
| 814 | if ((endpoint->bmAttributes & 0x03) != 0x01) { | ||
| 815 | err("Interface %d. has non-ISO endpoint!", | ||
| 816 | interface->desc.bInterfaceNumber); | ||
| 817 | return -ENODEV; | ||
| 818 | } | ||
| 819 | if ((endpoint->bEndpointAddress & 0x80) == 0) { | ||
| 820 | err("Interface %d. has ISO OUT endpoint!", | ||
| 821 | interface->desc.bInterfaceNumber); | ||
| 822 | return -ENODEV; | ||
| 823 | } | ||
| 824 | if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { | ||
| 825 | if (inactInterface < 0) | ||
| 826 | inactInterface = i; | ||
| 827 | else { | ||
| 828 | err("More than one inactive alt. setting!"); | ||
| 829 | return -ENODEV; | ||
| 830 | } | ||
| 831 | } else { | ||
| 832 | if (i == spd_to_iface[speed]) { | ||
| 833 | /* This one is the requested one */ | ||
| 834 | actInterface = i; | ||
| 835 | } | ||
| 836 | } | ||
| 837 | if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS) | ||
| 838 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | ||
| 839 | } | ||
| 840 | if(actInterface == -1) { | ||
| 841 | err("Cant find required endpoint"); | ||
| 842 | return -ENODEV; | ||
| 843 | } | ||
| 844 | |||
| 845 | DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS); | ||
| 846 | |||
| 847 | uvd = usbvideo_AllocateDevice(cams); | ||
| 848 | if (uvd != NULL) { | ||
| 849 | struct konicawc *cam = (struct konicawc *)(uvd->user_data); | ||
| 850 | /* Here uvd is a fully allocated uvd object */ | ||
| 851 | for(i = 0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 852 | cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); | ||
| 853 | if(cam->sts_urb[i] == NULL) { | ||
| 854 | while(i--) { | ||
| 855 | usb_free_urb(cam->sts_urb[i]); | ||
| 856 | } | ||
| 857 | err("can't allocate urbs"); | ||
| 858 | return -ENOMEM; | ||
| 859 | } | ||
| 860 | } | ||
| 861 | cam->speed = speed; | ||
| 862 | RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240); | ||
| 863 | cam->width = camera_sizes[size].width; | ||
| 864 | cam->height = camera_sizes[size].height; | ||
| 865 | cam->size = size; | ||
| 866 | |||
| 867 | uvd->flags = 0; | ||
| 868 | uvd->debug = debug; | ||
| 869 | uvd->dev = dev; | ||
| 870 | uvd->iface = intf->altsetting->desc.bInterfaceNumber; | ||
| 871 | uvd->ifaceAltInactive = inactInterface; | ||
| 872 | uvd->ifaceAltActive = actInterface; | ||
| 873 | uvd->video_endp = video_ep; | ||
| 874 | uvd->iso_packet_len = maxPS; | ||
| 875 | uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P; | ||
| 876 | uvd->defaultPalette = VIDEO_PALETTE_YUV420P; | ||
| 877 | uvd->canvas = VIDEOSIZE(320, 240); | ||
| 878 | uvd->videosize = VIDEOSIZE(cam->width, cam->height); | ||
| 879 | |||
| 880 | /* Initialize konicawc specific data */ | ||
| 881 | konicawc_configure_video(uvd); | ||
| 882 | |||
| 883 | i = usbvideo_RegisterVideoDevice(uvd); | ||
| 884 | uvd->max_frame_size = (320 * 240 * 3)/2; | ||
| 885 | if (i != 0) { | ||
| 886 | err("usbvideo_RegisterVideoDevice() failed."); | ||
| 887 | uvd = NULL; | ||
| 888 | } | ||
| 889 | |||
| 890 | konicawc_register_input(cam, dev); | ||
| 891 | } | ||
| 892 | |||
| 893 | if (uvd) { | ||
| 894 | usb_set_intfdata (intf, uvd); | ||
| 895 | return 0; | ||
| 896 | } | ||
| 897 | return -EIO; | ||
| 898 | } | ||
| 899 | |||
| 900 | |||
| 901 | static void konicawc_free_uvd(struct uvd *uvd) | ||
| 902 | { | ||
| 903 | int i; | ||
| 904 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
| 905 | |||
| 906 | konicawc_unregister_input(cam); | ||
| 907 | |||
| 908 | for (i = 0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 909 | usb_free_urb(cam->sts_urb[i]); | ||
| 910 | cam->sts_urb[i] = NULL; | ||
| 911 | } | ||
| 912 | } | ||
| 913 | |||
| 914 | |||
| 915 | static struct usb_device_id id_table[] = { | ||
| 916 | { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */ | ||
| 917 | { } /* Terminating entry */ | ||
| 918 | }; | ||
| 919 | |||
| 920 | |||
| 921 | static int __init konicawc_init(void) | ||
| 922 | { | ||
| 923 | struct usbvideo_cb cbTbl; | ||
| 924 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
| 925 | memset(&cbTbl, 0, sizeof(cbTbl)); | ||
| 926 | cbTbl.probe = konicawc_probe; | ||
| 927 | cbTbl.setupOnOpen = konicawc_setup_on_open; | ||
| 928 | cbTbl.processData = konicawc_process_isoc; | ||
| 929 | cbTbl.getFPS = konicawc_calculate_fps; | ||
| 930 | cbTbl.setVideoMode = konicawc_set_video_mode; | ||
| 931 | cbTbl.startDataPump = konicawc_start_data; | ||
| 932 | cbTbl.stopDataPump = konicawc_stop_data; | ||
| 933 | cbTbl.adjustPicture = konicawc_adjust_picture; | ||
| 934 | cbTbl.userFree = konicawc_free_uvd; | ||
| 935 | return usbvideo_register( | ||
| 936 | &cams, | ||
| 937 | MAX_CAMERAS, | ||
| 938 | sizeof(struct konicawc), | ||
| 939 | "konicawc", | ||
| 940 | &cbTbl, | ||
| 941 | THIS_MODULE, | ||
| 942 | id_table); | ||
| 943 | } | ||
| 944 | |||
| 945 | |||
| 946 | static void __exit konicawc_cleanup(void) | ||
| 947 | { | ||
| 948 | usbvideo_Deregister(&cams); | ||
| 949 | } | ||
| 950 | |||
| 951 | |||
| 952 | MODULE_DEVICE_TABLE(usb, id_table); | ||
| 953 | |||
| 954 | MODULE_LICENSE("GPL"); | ||
| 955 | MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>"); | ||
| 956 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 957 | module_param(speed, int, 0); | ||
| 958 | MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)"); | ||
| 959 | module_param(size, int, 0); | ||
| 960 | MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240"); | ||
| 961 | module_param(brightness, int, 0); | ||
| 962 | MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108"); | ||
| 963 | module_param(contrast, int, 0); | ||
| 964 | MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108"); | ||
| 965 | module_param(saturation, int, 0); | ||
| 966 | MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108"); | ||
| 967 | module_param(sharpness, int, 0); | ||
| 968 | MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108"); | ||
| 969 | module_param(whitebal, int, 0); | ||
| 970 | MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363"); | ||
| 971 | |||
| 972 | #ifdef CONFIG_USB_DEBUG | ||
| 973 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
| 974 | MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); | ||
| 975 | #endif | ||
| 976 | |||
| 977 | module_init(konicawc_init); | ||
| 978 | module_exit(konicawc_cleanup); | ||
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c deleted file mode 100644 index da44579d6f29..000000000000 --- a/drivers/usb/media/ov511.c +++ /dev/null | |||
| @@ -1,5932 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * OmniVision OV511 Camera-to-USB Bridge Driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 1999-2003 Mark W. McClelland | ||
| 5 | * Original decompression code Copyright 1998-2000 OmniVision Technologies | ||
| 6 | * Many improvements by Bret Wallach <bwallac1@san.rr.com> | ||
| 7 | * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000) | ||
| 8 | * Snapshot code by Kevin Moore | ||
| 9 | * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org> | ||
| 10 | * Changes by Claudio Matsuoka <claudio@conectiva.com> | ||
| 11 | * Original SAA7111A code by Dave Perks <dperks@ibm.net> | ||
| 12 | * URB error messages from pwc driver by Nemosoft | ||
| 13 | * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox | ||
| 14 | * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others | ||
| 15 | * | ||
| 16 | * Based on the Linux CPiA driver written by Peter Pregler, | ||
| 17 | * Scott J. Bertin and Johannes Erdfelt. | ||
| 18 | * | ||
| 19 | * Please see the file: Documentation/usb/ov511.txt | ||
| 20 | * and the website at: http://alpha.dyndns.org/ov511 | ||
| 21 | * for more info. | ||
| 22 | * | ||
| 23 | * This program is free software; you can redistribute it and/or modify it | ||
| 24 | * under the terms of the GNU General Public License as published by the | ||
| 25 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 26 | * option) any later version. | ||
| 27 | * | ||
| 28 | * This program is distributed in the hope that it will be useful, but | ||
| 29 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 30 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 31 | * for more details. | ||
| 32 | * | ||
| 33 | * You should have received a copy of the GNU General Public License | ||
| 34 | * along with this program; if not, write to the Free Software Foundation, | ||
| 35 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 36 | */ | ||
| 37 | |||
| 38 | #include <linux/config.h> | ||
| 39 | #include <linux/module.h> | ||
| 40 | #include <linux/init.h> | ||
| 41 | #include <linux/vmalloc.h> | ||
| 42 | #include <linux/slab.h> | ||
| 43 | #include <linux/ctype.h> | ||
| 44 | #include <linux/pagemap.h> | ||
| 45 | #include <asm/semaphore.h> | ||
| 46 | #include <asm/processor.h> | ||
| 47 | #include <linux/mm.h> | ||
| 48 | #include <linux/device.h> | ||
| 49 | |||
| 50 | #if defined (__i386__) | ||
| 51 | #include <asm/cpufeature.h> | ||
| 52 | #endif | ||
| 53 | |||
| 54 | #include "ov511.h" | ||
| 55 | |||
| 56 | /* | ||
| 57 | * Version Information | ||
| 58 | */ | ||
| 59 | #define DRIVER_VERSION "v1.64 for Linux 2.5" | ||
| 60 | #define EMAIL "mark@alpha.dyndns.org" | ||
| 61 | #define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \ | ||
| 62 | & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \ | ||
| 63 | <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>" | ||
| 64 | #define DRIVER_DESC "ov511 USB Camera Driver" | ||
| 65 | |||
| 66 | #define OV511_I2C_RETRIES 3 | ||
| 67 | #define ENABLE_Y_QUANTABLE 1 | ||
| 68 | #define ENABLE_UV_QUANTABLE 1 | ||
| 69 | |||
| 70 | #define OV511_MAX_UNIT_VIDEO 16 | ||
| 71 | |||
| 72 | /* Pixel count * bytes per YUV420 pixel (1.5) */ | ||
| 73 | #define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2) | ||
| 74 | |||
| 75 | #define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval)) | ||
| 76 | |||
| 77 | /* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */ | ||
| 78 | #define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024) | ||
| 79 | |||
| 80 | #define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM) | ||
| 81 | |||
| 82 | /********************************************************************** | ||
| 83 | * Module Parameters | ||
| 84 | * (See ov511.txt for detailed descriptions of these) | ||
| 85 | **********************************************************************/ | ||
| 86 | |||
| 87 | /* These variables (and all static globals) default to zero */ | ||
| 88 | static int autobright = 1; | ||
| 89 | static int autogain = 1; | ||
| 90 | static int autoexp = 1; | ||
| 91 | static int debug; | ||
| 92 | static int snapshot; | ||
| 93 | static int cams = 1; | ||
| 94 | static int compress; | ||
| 95 | static int testpat; | ||
| 96 | static int dumppix; | ||
| 97 | static int led = 1; | ||
| 98 | static int dump_bridge; | ||
| 99 | static int dump_sensor; | ||
| 100 | static int printph; | ||
| 101 | static int phy = 0x1f; | ||
| 102 | static int phuv = 0x05; | ||
| 103 | static int pvy = 0x06; | ||
| 104 | static int pvuv = 0x06; | ||
| 105 | static int qhy = 0x14; | ||
| 106 | static int qhuv = 0x03; | ||
| 107 | static int qvy = 0x04; | ||
| 108 | static int qvuv = 0x04; | ||
| 109 | static int lightfreq; | ||
| 110 | static int bandingfilter; | ||
| 111 | static int clockdiv = -1; | ||
| 112 | static int packetsize = -1; | ||
| 113 | static int framedrop = -1; | ||
| 114 | static int fastset; | ||
| 115 | static int force_palette; | ||
| 116 | static int backlight; | ||
| 117 | static int unit_video[OV511_MAX_UNIT_VIDEO]; | ||
| 118 | static int remove_zeros; | ||
| 119 | static int mirror; | ||
| 120 | static int ov518_color; | ||
| 121 | |||
| 122 | module_param(autobright, int, 0); | ||
| 123 | MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); | ||
| 124 | module_param(autogain, int, 0); | ||
| 125 | MODULE_PARM_DESC(autogain, "Sensor automatically changes gain"); | ||
| 126 | module_param(autoexp, int, 0); | ||
| 127 | MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure"); | ||
| 128 | module_param(debug, int, 0); | ||
| 129 | MODULE_PARM_DESC(debug, | ||
| 130 | "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); | ||
| 131 | module_param(snapshot, int, 0); | ||
| 132 | MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); | ||
| 133 | module_param(cams, int, 0); | ||
| 134 | MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); | ||
| 135 | module_param(compress, int, 0); | ||
| 136 | MODULE_PARM_DESC(compress, "Turn on compression"); | ||
| 137 | module_param(testpat, int, 0); | ||
| 138 | MODULE_PARM_DESC(testpat, | ||
| 139 | "Replace image with vertical bar testpattern (only partially working)"); | ||
| 140 | module_param(dumppix, int, 0); | ||
| 141 | MODULE_PARM_DESC(dumppix, "Dump raw pixel data"); | ||
| 142 | module_param(led, int, 0); | ||
| 143 | MODULE_PARM_DESC(led, | ||
| 144 | "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)"); | ||
| 145 | module_param(dump_bridge, int, 0); | ||
| 146 | MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers"); | ||
| 147 | module_param(dump_sensor, int, 0); | ||
| 148 | MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers"); | ||
| 149 | module_param(printph, int, 0); | ||
| 150 | MODULE_PARM_DESC(printph, "Print frame start/end headers"); | ||
| 151 | module_param(phy, int, 0); | ||
| 152 | MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)"); | ||
| 153 | module_param(phuv, int, 0); | ||
| 154 | MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)"); | ||
| 155 | module_param(pvy, int, 0); | ||
| 156 | MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)"); | ||
| 157 | module_param(pvuv, int, 0); | ||
| 158 | MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)"); | ||
| 159 | module_param(qhy, int, 0); | ||
| 160 | MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)"); | ||
| 161 | module_param(qhuv, int, 0); | ||
| 162 | MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)"); | ||
| 163 | module_param(qvy, int, 0); | ||
| 164 | MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)"); | ||
| 165 | module_param(qvuv, int, 0); | ||
| 166 | MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)"); | ||
| 167 | module_param(lightfreq, int, 0); | ||
| 168 | MODULE_PARM_DESC(lightfreq, | ||
| 169 | "Light frequency. Set to 50 or 60 Hz, or zero for default settings"); | ||
| 170 | module_param(bandingfilter, int, 0); | ||
| 171 | MODULE_PARM_DESC(bandingfilter, | ||
| 172 | "Enable banding filter (to reduce effects of fluorescent lighting)"); | ||
| 173 | module_param(clockdiv, int, 0); | ||
| 174 | MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value"); | ||
| 175 | module_param(packetsize, int, 0); | ||
| 176 | MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size"); | ||
| 177 | module_param(framedrop, int, 0); | ||
| 178 | MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting"); | ||
| 179 | module_param(fastset, int, 0); | ||
| 180 | MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately"); | ||
| 181 | module_param(force_palette, int, 0); | ||
| 182 | MODULE_PARM_DESC(force_palette, "Force the palette to a specific value"); | ||
| 183 | module_param(backlight, int, 0); | ||
| 184 | MODULE_PARM_DESC(backlight, "For objects that are lit from behind"); | ||
| 185 | static int num_uv; | ||
| 186 | module_param_array(unit_video, int, &num_uv, 0); | ||
| 187 | MODULE_PARM_DESC(unit_video, | ||
| 188 | "Force use of specific minor number(s). 0 is not allowed."); | ||
| 189 | module_param(remove_zeros, int, 0); | ||
| 190 | MODULE_PARM_DESC(remove_zeros, | ||
| 191 | "Remove zero-padding from uncompressed incoming data"); | ||
| 192 | module_param(mirror, int, 0); | ||
| 193 | MODULE_PARM_DESC(mirror, "Reverse image horizontally"); | ||
| 194 | module_param(ov518_color, int, 0); | ||
| 195 | MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)"); | ||
| 196 | |||
| 197 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 198 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 199 | MODULE_LICENSE("GPL"); | ||
| 200 | |||
| 201 | /********************************************************************** | ||
| 202 | * Miscellaneous Globals | ||
| 203 | **********************************************************************/ | ||
| 204 | |||
| 205 | static struct usb_driver ov511_driver; | ||
| 206 | |||
| 207 | /* Number of times to retry a failed I2C transaction. Increase this if you | ||
| 208 | * are getting "Failed to read sensor ID..." */ | ||
| 209 | static const int i2c_detect_tries = 5; | ||
| 210 | |||
| 211 | static struct usb_device_id device_table [] = { | ||
| 212 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) }, | ||
| 213 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) }, | ||
| 214 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) }, | ||
| 215 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) }, | ||
| 216 | { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) }, | ||
| 217 | { } /* Terminating entry */ | ||
| 218 | }; | ||
| 219 | |||
| 220 | MODULE_DEVICE_TABLE (usb, device_table); | ||
| 221 | |||
| 222 | static unsigned char yQuanTable511[] = OV511_YQUANTABLE; | ||
| 223 | static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE; | ||
| 224 | static unsigned char yQuanTable518[] = OV518_YQUANTABLE; | ||
| 225 | static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE; | ||
| 226 | |||
| 227 | /********************************************************************** | ||
| 228 | * Symbolic Names | ||
| 229 | **********************************************************************/ | ||
| 230 | |||
| 231 | /* Known OV511-based cameras */ | ||
| 232 | static struct symbolic_list camlist[] = { | ||
| 233 | { 0, "Generic Camera (no ID)" }, | ||
| 234 | { 1, "Mustek WCam 3X" }, | ||
| 235 | { 3, "D-Link DSB-C300" }, | ||
| 236 | { 4, "Generic OV511/OV7610" }, | ||
| 237 | { 5, "Puretek PT-6007" }, | ||
| 238 | { 6, "Lifeview USB Life TV (NTSC)" }, | ||
| 239 | { 21, "Creative Labs WebCam 3" }, | ||
| 240 | { 22, "Lifeview USB Life TV (PAL D/K+B/G)" }, | ||
| 241 | { 36, "Koala-Cam" }, | ||
| 242 | { 38, "Lifeview USB Life TV (PAL)" }, | ||
| 243 | { 41, "Samsung Anycam MPC-M10" }, | ||
| 244 | { 43, "Mtekvision Zeca MV402" }, | ||
| 245 | { 46, "Suma eON" }, | ||
| 246 | { 70, "Lifeview USB Life TV (PAL/SECAM)" }, | ||
| 247 | { 100, "Lifeview RoboCam" }, | ||
| 248 | { 102, "AverMedia InterCam Elite" }, | ||
| 249 | { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ | ||
| 250 | { 134, "Ezonics EZCam II" }, | ||
| 251 | { 192, "Webeye 2000B" }, | ||
| 252 | { 253, "Alpha Vision Tech. AlphaCam SE" }, | ||
| 253 | { -1, NULL } | ||
| 254 | }; | ||
| 255 | |||
| 256 | /* Video4Linux1 Palettes */ | ||
| 257 | static struct symbolic_list v4l1_plist[] = { | ||
| 258 | { VIDEO_PALETTE_GREY, "GREY" }, | ||
| 259 | { VIDEO_PALETTE_HI240, "HI240" }, | ||
| 260 | { VIDEO_PALETTE_RGB565, "RGB565" }, | ||
| 261 | { VIDEO_PALETTE_RGB24, "RGB24" }, | ||
| 262 | { VIDEO_PALETTE_RGB32, "RGB32" }, | ||
| 263 | { VIDEO_PALETTE_RGB555, "RGB555" }, | ||
| 264 | { VIDEO_PALETTE_YUV422, "YUV422" }, | ||
| 265 | { VIDEO_PALETTE_YUYV, "YUYV" }, | ||
| 266 | { VIDEO_PALETTE_UYVY, "UYVY" }, | ||
| 267 | { VIDEO_PALETTE_YUV420, "YUV420" }, | ||
| 268 | { VIDEO_PALETTE_YUV411, "YUV411" }, | ||
| 269 | { VIDEO_PALETTE_RAW, "RAW" }, | ||
| 270 | { VIDEO_PALETTE_YUV422P,"YUV422P" }, | ||
| 271 | { VIDEO_PALETTE_YUV411P,"YUV411P" }, | ||
| 272 | { VIDEO_PALETTE_YUV420P,"YUV420P" }, | ||
| 273 | { VIDEO_PALETTE_YUV410P,"YUV410P" }, | ||
| 274 | { -1, NULL } | ||
| 275 | }; | ||
| 276 | |||
| 277 | static struct symbolic_list brglist[] = { | ||
| 278 | { BRG_OV511, "OV511" }, | ||
| 279 | { BRG_OV511PLUS, "OV511+" }, | ||
| 280 | { BRG_OV518, "OV518" }, | ||
| 281 | { BRG_OV518PLUS, "OV518+" }, | ||
| 282 | { -1, NULL } | ||
| 283 | }; | ||
| 284 | |||
| 285 | static struct symbolic_list senlist[] = { | ||
| 286 | { SEN_OV76BE, "OV76BE" }, | ||
| 287 | { SEN_OV7610, "OV7610" }, | ||
| 288 | { SEN_OV7620, "OV7620" }, | ||
| 289 | { SEN_OV7620AE, "OV7620AE" }, | ||
| 290 | { SEN_OV6620, "OV6620" }, | ||
| 291 | { SEN_OV6630, "OV6630" }, | ||
| 292 | { SEN_OV6630AE, "OV6630AE" }, | ||
| 293 | { SEN_OV6630AF, "OV6630AF" }, | ||
| 294 | { SEN_OV8600, "OV8600" }, | ||
| 295 | { SEN_KS0127, "KS0127" }, | ||
| 296 | { SEN_KS0127B, "KS0127B" }, | ||
| 297 | { SEN_SAA7111A, "SAA7111A" }, | ||
| 298 | { -1, NULL } | ||
| 299 | }; | ||
| 300 | |||
| 301 | /* URB error codes: */ | ||
| 302 | static struct symbolic_list urb_errlist[] = { | ||
| 303 | { -ENOSR, "Buffer error (overrun)" }, | ||
| 304 | { -EPIPE, "Stalled (device not responding)" }, | ||
| 305 | { -EOVERFLOW, "Babble (bad cable?)" }, | ||
| 306 | { -EPROTO, "Bit-stuff error (bad cable?)" }, | ||
| 307 | { -EILSEQ, "CRC/Timeout" }, | ||
| 308 | { -ETIMEDOUT, "NAK (device does not respond)" }, | ||
| 309 | { -1, NULL } | ||
| 310 | }; | ||
| 311 | |||
| 312 | /********************************************************************** | ||
| 313 | * Memory management | ||
| 314 | **********************************************************************/ | ||
| 315 | static void * | ||
| 316 | rvmalloc(unsigned long size) | ||
| 317 | { | ||
| 318 | void *mem; | ||
| 319 | unsigned long adr; | ||
| 320 | |||
| 321 | size = PAGE_ALIGN(size); | ||
| 322 | mem = vmalloc_32(size); | ||
| 323 | if (!mem) | ||
| 324 | return NULL; | ||
| 325 | |||
| 326 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
| 327 | adr = (unsigned long) mem; | ||
| 328 | while (size > 0) { | ||
| 329 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
| 330 | adr += PAGE_SIZE; | ||
| 331 | size -= PAGE_SIZE; | ||
| 332 | } | ||
| 333 | |||
| 334 | return mem; | ||
| 335 | } | ||
| 336 | |||
| 337 | static void | ||
| 338 | rvfree(void *mem, unsigned long size) | ||
| 339 | { | ||
| 340 | unsigned long adr; | ||
| 341 | |||
| 342 | if (!mem) | ||
| 343 | return; | ||
| 344 | |||
| 345 | adr = (unsigned long) mem; | ||
| 346 | while ((long) size > 0) { | ||
| 347 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
| 348 | adr += PAGE_SIZE; | ||
| 349 | size -= PAGE_SIZE; | ||
| 350 | } | ||
| 351 | vfree(mem); | ||
| 352 | } | ||
| 353 | |||
| 354 | /********************************************************************** | ||
| 355 | * | ||
| 356 | * Register I/O | ||
| 357 | * | ||
| 358 | **********************************************************************/ | ||
| 359 | |||
| 360 | /* Write an OV51x register */ | ||
| 361 | static int | ||
| 362 | reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) | ||
| 363 | { | ||
| 364 | int rc; | ||
| 365 | |||
| 366 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
| 367 | |||
| 368 | mutex_lock(&ov->cbuf_lock); | ||
| 369 | ov->cbuf[0] = value; | ||
| 370 | rc = usb_control_msg(ov->dev, | ||
| 371 | usb_sndctrlpipe(ov->dev, 0), | ||
| 372 | (ov->bclass == BCL_OV518)?1:2 /* REG_IO */, | ||
| 373 | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 374 | 0, (__u16)reg, &ov->cbuf[0], 1, 1000); | ||
| 375 | mutex_unlock(&ov->cbuf_lock); | ||
| 376 | |||
| 377 | if (rc < 0) | ||
| 378 | err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc)); | ||
| 379 | |||
| 380 | return rc; | ||
| 381 | } | ||
| 382 | |||
| 383 | /* Read from an OV51x register */ | ||
| 384 | /* returns: negative is error, pos or zero is data */ | ||
| 385 | static int | ||
| 386 | reg_r(struct usb_ov511 *ov, unsigned char reg) | ||
| 387 | { | ||
| 388 | int rc; | ||
| 389 | |||
| 390 | mutex_lock(&ov->cbuf_lock); | ||
| 391 | rc = usb_control_msg(ov->dev, | ||
| 392 | usb_rcvctrlpipe(ov->dev, 0), | ||
| 393 | (ov->bclass == BCL_OV518)?1:3 /* REG_IO */, | ||
| 394 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 395 | 0, (__u16)reg, &ov->cbuf[0], 1, 1000); | ||
| 396 | |||
| 397 | if (rc < 0) { | ||
| 398 | err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc)); | ||
| 399 | } else { | ||
| 400 | rc = ov->cbuf[0]; | ||
| 401 | PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); | ||
| 402 | } | ||
| 403 | |||
| 404 | mutex_unlock(&ov->cbuf_lock); | ||
| 405 | |||
| 406 | return rc; | ||
| 407 | } | ||
| 408 | |||
| 409 | /* | ||
| 410 | * Writes bits at positions specified by mask to an OV51x reg. Bits that are in | ||
| 411 | * the same position as 1's in "mask" are cleared and set to "value". Bits | ||
| 412 | * that are in the same position as 0's in "mask" are preserved, regardless | ||
| 413 | * of their respective state in "value". | ||
| 414 | */ | ||
| 415 | static int | ||
| 416 | reg_w_mask(struct usb_ov511 *ov, | ||
| 417 | unsigned char reg, | ||
| 418 | unsigned char value, | ||
| 419 | unsigned char mask) | ||
| 420 | { | ||
| 421 | int ret; | ||
| 422 | unsigned char oldval, newval; | ||
| 423 | |||
| 424 | ret = reg_r(ov, reg); | ||
| 425 | if (ret < 0) | ||
| 426 | return ret; | ||
| 427 | |||
| 428 | oldval = (unsigned char) ret; | ||
| 429 | oldval &= (~mask); /* Clear the masked bits */ | ||
| 430 | value &= mask; /* Enforce mask on value */ | ||
| 431 | newval = oldval | value; /* Set the desired bits */ | ||
| 432 | |||
| 433 | return (reg_w(ov, reg, newval)); | ||
| 434 | } | ||
| 435 | |||
| 436 | /* | ||
| 437 | * Writes multiple (n) byte value to a single register. Only valid with certain | ||
| 438 | * registers (0x30 and 0xc4 - 0xce). | ||
| 439 | */ | ||
| 440 | static int | ||
| 441 | ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) | ||
| 442 | { | ||
| 443 | int rc; | ||
| 444 | |||
| 445 | PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); | ||
| 446 | |||
| 447 | mutex_lock(&ov->cbuf_lock); | ||
| 448 | |||
| 449 | *((__le32 *)ov->cbuf) = __cpu_to_le32(val); | ||
| 450 | |||
| 451 | rc = usb_control_msg(ov->dev, | ||
| 452 | usb_sndctrlpipe(ov->dev, 0), | ||
| 453 | 1 /* REG_IO */, | ||
| 454 | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 455 | 0, (__u16)reg, ov->cbuf, n, 1000); | ||
| 456 | mutex_unlock(&ov->cbuf_lock); | ||
| 457 | |||
| 458 | if (rc < 0) | ||
| 459 | err("reg write multiple: error %d: %s", rc, | ||
| 460 | symbolic(urb_errlist, rc)); | ||
| 461 | |||
| 462 | return rc; | ||
| 463 | } | ||
| 464 | |||
| 465 | static int | ||
| 466 | ov511_upload_quan_tables(struct usb_ov511 *ov) | ||
| 467 | { | ||
| 468 | unsigned char *pYTable = yQuanTable511; | ||
| 469 | unsigned char *pUVTable = uvQuanTable511; | ||
| 470 | unsigned char val0, val1; | ||
| 471 | int i, rc, reg = R511_COMP_LUT_BEGIN; | ||
| 472 | |||
| 473 | PDEBUG(4, "Uploading quantization tables"); | ||
| 474 | |||
| 475 | for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) { | ||
| 476 | if (ENABLE_Y_QUANTABLE) { | ||
| 477 | val0 = *pYTable++; | ||
| 478 | val1 = *pYTable++; | ||
| 479 | val0 &= 0x0f; | ||
| 480 | val1 &= 0x0f; | ||
| 481 | val0 |= val1 << 4; | ||
| 482 | rc = reg_w(ov, reg, val0); | ||
| 483 | if (rc < 0) | ||
| 484 | return rc; | ||
| 485 | } | ||
| 486 | |||
| 487 | if (ENABLE_UV_QUANTABLE) { | ||
| 488 | val0 = *pUVTable++; | ||
| 489 | val1 = *pUVTable++; | ||
| 490 | val0 &= 0x0f; | ||
| 491 | val1 &= 0x0f; | ||
| 492 | val0 |= val1 << 4; | ||
| 493 | rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); | ||
| 494 | if (rc < 0) | ||
| 495 | return rc; | ||
| 496 | } | ||
| 497 | |||
| 498 | reg++; | ||
| 499 | } | ||
| 500 | |||
| 501 | return 0; | ||
| 502 | } | ||
| 503 | |||
| 504 | /* OV518 quantization tables are 8x4 (instead of 8x8) */ | ||
| 505 | static int | ||
| 506 | ov518_upload_quan_tables(struct usb_ov511 *ov) | ||
| 507 | { | ||
| 508 | unsigned char *pYTable = yQuanTable518; | ||
| 509 | unsigned char *pUVTable = uvQuanTable518; | ||
| 510 | unsigned char val0, val1; | ||
| 511 | int i, rc, reg = R511_COMP_LUT_BEGIN; | ||
| 512 | |||
| 513 | PDEBUG(4, "Uploading quantization tables"); | ||
| 514 | |||
| 515 | for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) { | ||
| 516 | if (ENABLE_Y_QUANTABLE) { | ||
| 517 | val0 = *pYTable++; | ||
| 518 | val1 = *pYTable++; | ||
| 519 | val0 &= 0x0f; | ||
| 520 | val1 &= 0x0f; | ||
| 521 | val0 |= val1 << 4; | ||
| 522 | rc = reg_w(ov, reg, val0); | ||
| 523 | if (rc < 0) | ||
| 524 | return rc; | ||
| 525 | } | ||
| 526 | |||
| 527 | if (ENABLE_UV_QUANTABLE) { | ||
| 528 | val0 = *pUVTable++; | ||
| 529 | val1 = *pUVTable++; | ||
| 530 | val0 &= 0x0f; | ||
| 531 | val1 &= 0x0f; | ||
| 532 | val0 |= val1 << 4; | ||
| 533 | rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); | ||
| 534 | if (rc < 0) | ||
| 535 | return rc; | ||
| 536 | } | ||
| 537 | |||
| 538 | reg++; | ||
| 539 | } | ||
| 540 | |||
| 541 | return 0; | ||
| 542 | } | ||
| 543 | |||
| 544 | static int | ||
| 545 | ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) | ||
| 546 | { | ||
| 547 | int rc; | ||
| 548 | |||
| 549 | /* Setting bit 0 not allowed on 518/518Plus */ | ||
| 550 | if (ov->bclass == BCL_OV518) | ||
| 551 | reset_type &= 0xfe; | ||
| 552 | |||
| 553 | PDEBUG(4, "Reset: type=0x%02X", reset_type); | ||
| 554 | |||
| 555 | rc = reg_w(ov, R51x_SYS_RESET, reset_type); | ||
| 556 | rc = reg_w(ov, R51x_SYS_RESET, 0); | ||
| 557 | |||
| 558 | if (rc < 0) | ||
| 559 | err("reset: command failed"); | ||
| 560 | |||
| 561 | return rc; | ||
| 562 | } | ||
| 563 | |||
| 564 | /********************************************************************** | ||
| 565 | * | ||
| 566 | * Low-level I2C I/O functions | ||
| 567 | * | ||
| 568 | **********************************************************************/ | ||
| 569 | |||
| 570 | /* NOTE: Do not call this function directly! | ||
| 571 | * The OV518 I2C I/O procedure is different, hence, this function. | ||
| 572 | * This is normally only called from i2c_w(). Note that this function | ||
| 573 | * always succeeds regardless of whether the sensor is present and working. | ||
| 574 | */ | ||
| 575 | static int | ||
| 576 | ov518_i2c_write_internal(struct usb_ov511 *ov, | ||
| 577 | unsigned char reg, | ||
| 578 | unsigned char value) | ||
| 579 | { | ||
| 580 | int rc; | ||
| 581 | |||
| 582 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
| 583 | |||
| 584 | /* Select camera register */ | ||
| 585 | rc = reg_w(ov, R51x_I2C_SADDR_3, reg); | ||
| 586 | if (rc < 0) | ||
| 587 | return rc; | ||
| 588 | |||
| 589 | /* Write "value" to I2C data port of OV511 */ | ||
| 590 | rc = reg_w(ov, R51x_I2C_DATA, value); | ||
| 591 | if (rc < 0) | ||
| 592 | return rc; | ||
| 593 | |||
| 594 | /* Initiate 3-byte write cycle */ | ||
| 595 | rc = reg_w(ov, R518_I2C_CTL, 0x01); | ||
| 596 | if (rc < 0) | ||
| 597 | return rc; | ||
| 598 | |||
| 599 | return 0; | ||
| 600 | } | ||
| 601 | |||
| 602 | /* NOTE: Do not call this function directly! */ | ||
| 603 | static int | ||
| 604 | ov511_i2c_write_internal(struct usb_ov511 *ov, | ||
| 605 | unsigned char reg, | ||
| 606 | unsigned char value) | ||
| 607 | { | ||
| 608 | int rc, retries; | ||
| 609 | |||
| 610 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
| 611 | |||
| 612 | /* Three byte write cycle */ | ||
| 613 | for (retries = OV511_I2C_RETRIES; ; ) { | ||
| 614 | /* Select camera register */ | ||
| 615 | rc = reg_w(ov, R51x_I2C_SADDR_3, reg); | ||
| 616 | if (rc < 0) | ||
| 617 | break; | ||
| 618 | |||
| 619 | /* Write "value" to I2C data port of OV511 */ | ||
| 620 | rc = reg_w(ov, R51x_I2C_DATA, value); | ||
| 621 | if (rc < 0) | ||
| 622 | break; | ||
| 623 | |||
| 624 | /* Initiate 3-byte write cycle */ | ||
| 625 | rc = reg_w(ov, R511_I2C_CTL, 0x01); | ||
| 626 | if (rc < 0) | ||
| 627 | break; | ||
| 628 | |||
| 629 | /* Retry until idle */ | ||
| 630 | do | ||
| 631 | rc = reg_r(ov, R511_I2C_CTL); | ||
| 632 | while (rc > 0 && ((rc&1) == 0)); | ||
| 633 | if (rc < 0) | ||
| 634 | break; | ||
| 635 | |||
| 636 | /* Ack? */ | ||
| 637 | if ((rc&2) == 0) { | ||
| 638 | rc = 0; | ||
| 639 | break; | ||
| 640 | } | ||
| 641 | #if 0 | ||
| 642 | /* I2C abort */ | ||
| 643 | reg_w(ov, R511_I2C_CTL, 0x10); | ||
| 644 | #endif | ||
| 645 | if (--retries < 0) { | ||
| 646 | err("i2c write retries exhausted"); | ||
| 647 | rc = -1; | ||
| 648 | break; | ||
| 649 | } | ||
| 650 | } | ||
| 651 | |||
| 652 | return rc; | ||
| 653 | } | ||
| 654 | |||
| 655 | /* NOTE: Do not call this function directly! | ||
| 656 | * The OV518 I2C I/O procedure is different, hence, this function. | ||
| 657 | * This is normally only called from i2c_r(). Note that this function | ||
| 658 | * always succeeds regardless of whether the sensor is present and working. | ||
| 659 | */ | ||
| 660 | static int | ||
| 661 | ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) | ||
| 662 | { | ||
| 663 | int rc, value; | ||
| 664 | |||
| 665 | /* Select camera register */ | ||
| 666 | rc = reg_w(ov, R51x_I2C_SADDR_2, reg); | ||
| 667 | if (rc < 0) | ||
| 668 | return rc; | ||
| 669 | |||
| 670 | /* Initiate 2-byte write cycle */ | ||
| 671 | rc = reg_w(ov, R518_I2C_CTL, 0x03); | ||
| 672 | if (rc < 0) | ||
| 673 | return rc; | ||
| 674 | |||
| 675 | /* Initiate 2-byte read cycle */ | ||
| 676 | rc = reg_w(ov, R518_I2C_CTL, 0x05); | ||
| 677 | if (rc < 0) | ||
| 678 | return rc; | ||
| 679 | |||
| 680 | value = reg_r(ov, R51x_I2C_DATA); | ||
| 681 | |||
| 682 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
| 683 | |||
| 684 | return value; | ||
| 685 | } | ||
| 686 | |||
| 687 | /* NOTE: Do not call this function directly! | ||
| 688 | * returns: negative is error, pos or zero is data */ | ||
| 689 | static int | ||
| 690 | ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) | ||
| 691 | { | ||
| 692 | int rc, value, retries; | ||
| 693 | |||
| 694 | /* Two byte write cycle */ | ||
| 695 | for (retries = OV511_I2C_RETRIES; ; ) { | ||
| 696 | /* Select camera register */ | ||
| 697 | rc = reg_w(ov, R51x_I2C_SADDR_2, reg); | ||
| 698 | if (rc < 0) | ||
| 699 | return rc; | ||
| 700 | |||
| 701 | /* Initiate 2-byte write cycle */ | ||
| 702 | rc = reg_w(ov, R511_I2C_CTL, 0x03); | ||
| 703 | if (rc < 0) | ||
| 704 | return rc; | ||
| 705 | |||
| 706 | /* Retry until idle */ | ||
| 707 | do | ||
| 708 | rc = reg_r(ov, R511_I2C_CTL); | ||
| 709 | while (rc > 0 && ((rc&1) == 0)); | ||
| 710 | if (rc < 0) | ||
| 711 | return rc; | ||
| 712 | |||
| 713 | if ((rc&2) == 0) /* Ack? */ | ||
| 714 | break; | ||
| 715 | |||
| 716 | /* I2C abort */ | ||
| 717 | reg_w(ov, R511_I2C_CTL, 0x10); | ||
| 718 | |||
| 719 | if (--retries < 0) { | ||
| 720 | err("i2c write retries exhausted"); | ||
| 721 | return -1; | ||
| 722 | } | ||
| 723 | } | ||
| 724 | |||
| 725 | /* Two byte read cycle */ | ||
| 726 | for (retries = OV511_I2C_RETRIES; ; ) { | ||
| 727 | /* Initiate 2-byte read cycle */ | ||
| 728 | rc = reg_w(ov, R511_I2C_CTL, 0x05); | ||
| 729 | if (rc < 0) | ||
| 730 | return rc; | ||
| 731 | |||
| 732 | /* Retry until idle */ | ||
| 733 | do | ||
| 734 | rc = reg_r(ov, R511_I2C_CTL); | ||
| 735 | while (rc > 0 && ((rc&1) == 0)); | ||
| 736 | if (rc < 0) | ||
| 737 | return rc; | ||
| 738 | |||
| 739 | if ((rc&2) == 0) /* Ack? */ | ||
| 740 | break; | ||
| 741 | |||
| 742 | /* I2C abort */ | ||
| 743 | rc = reg_w(ov, R511_I2C_CTL, 0x10); | ||
| 744 | if (rc < 0) | ||
| 745 | return rc; | ||
| 746 | |||
| 747 | if (--retries < 0) { | ||
| 748 | err("i2c read retries exhausted"); | ||
| 749 | return -1; | ||
| 750 | } | ||
| 751 | } | ||
| 752 | |||
| 753 | value = reg_r(ov, R51x_I2C_DATA); | ||
| 754 | |||
| 755 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
| 756 | |||
| 757 | /* This is needed to make i2c_w() work */ | ||
| 758 | rc = reg_w(ov, R511_I2C_CTL, 0x05); | ||
| 759 | if (rc < 0) | ||
| 760 | return rc; | ||
| 761 | |||
| 762 | return value; | ||
| 763 | } | ||
| 764 | |||
| 765 | /* returns: negative is error, pos or zero is data */ | ||
| 766 | static int | ||
| 767 | i2c_r(struct usb_ov511 *ov, unsigned char reg) | ||
| 768 | { | ||
| 769 | int rc; | ||
| 770 | |||
| 771 | mutex_lock(&ov->i2c_lock); | ||
| 772 | |||
| 773 | if (ov->bclass == BCL_OV518) | ||
| 774 | rc = ov518_i2c_read_internal(ov, reg); | ||
| 775 | else | ||
| 776 | rc = ov511_i2c_read_internal(ov, reg); | ||
| 777 | |||
| 778 | mutex_unlock(&ov->i2c_lock); | ||
| 779 | |||
| 780 | return rc; | ||
| 781 | } | ||
| 782 | |||
| 783 | static int | ||
| 784 | i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) | ||
| 785 | { | ||
| 786 | int rc; | ||
| 787 | |||
| 788 | mutex_lock(&ov->i2c_lock); | ||
| 789 | |||
| 790 | if (ov->bclass == BCL_OV518) | ||
| 791 | rc = ov518_i2c_write_internal(ov, reg, value); | ||
| 792 | else | ||
| 793 | rc = ov511_i2c_write_internal(ov, reg, value); | ||
| 794 | |||
| 795 | mutex_unlock(&ov->i2c_lock); | ||
| 796 | |||
| 797 | return rc; | ||
| 798 | } | ||
| 799 | |||
| 800 | /* Do not call this function directly! */ | ||
| 801 | static int | ||
| 802 | ov51x_i2c_write_mask_internal(struct usb_ov511 *ov, | ||
| 803 | unsigned char reg, | ||
| 804 | unsigned char value, | ||
| 805 | unsigned char mask) | ||
| 806 | { | ||
| 807 | int rc; | ||
| 808 | unsigned char oldval, newval; | ||
| 809 | |||
| 810 | if (mask == 0xff) { | ||
| 811 | newval = value; | ||
| 812 | } else { | ||
| 813 | if (ov->bclass == BCL_OV518) | ||
| 814 | rc = ov518_i2c_read_internal(ov, reg); | ||
| 815 | else | ||
| 816 | rc = ov511_i2c_read_internal(ov, reg); | ||
| 817 | if (rc < 0) | ||
| 818 | return rc; | ||
| 819 | |||
| 820 | oldval = (unsigned char) rc; | ||
| 821 | oldval &= (~mask); /* Clear the masked bits */ | ||
| 822 | value &= mask; /* Enforce mask on value */ | ||
| 823 | newval = oldval | value; /* Set the desired bits */ | ||
| 824 | } | ||
| 825 | |||
| 826 | if (ov->bclass == BCL_OV518) | ||
| 827 | return (ov518_i2c_write_internal(ov, reg, newval)); | ||
| 828 | else | ||
| 829 | return (ov511_i2c_write_internal(ov, reg, newval)); | ||
| 830 | } | ||
| 831 | |||
| 832 | /* Writes bits at positions specified by mask to an I2C reg. Bits that are in | ||
| 833 | * the same position as 1's in "mask" are cleared and set to "value". Bits | ||
| 834 | * that are in the same position as 0's in "mask" are preserved, regardless | ||
| 835 | * of their respective state in "value". | ||
| 836 | */ | ||
| 837 | static int | ||
| 838 | i2c_w_mask(struct usb_ov511 *ov, | ||
| 839 | unsigned char reg, | ||
| 840 | unsigned char value, | ||
| 841 | unsigned char mask) | ||
| 842 | { | ||
| 843 | int rc; | ||
| 844 | |||
| 845 | mutex_lock(&ov->i2c_lock); | ||
| 846 | rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); | ||
| 847 | mutex_unlock(&ov->i2c_lock); | ||
| 848 | |||
| 849 | return rc; | ||
| 850 | } | ||
| 851 | |||
| 852 | /* Set the read and write slave IDs. The "slave" argument is the write slave, | ||
| 853 | * and the read slave will be set to (slave + 1). ov->i2c_lock should be held | ||
| 854 | * when calling this. This should not be called from outside the i2c I/O | ||
| 855 | * functions. | ||
| 856 | */ | ||
| 857 | static int | ||
| 858 | i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave) | ||
| 859 | { | ||
| 860 | int rc; | ||
| 861 | |||
| 862 | rc = reg_w(ov, R51x_I2C_W_SID, slave); | ||
| 863 | if (rc < 0) | ||
| 864 | return rc; | ||
| 865 | |||
| 866 | rc = reg_w(ov, R51x_I2C_R_SID, slave + 1); | ||
| 867 | if (rc < 0) | ||
| 868 | return rc; | ||
| 869 | |||
| 870 | return 0; | ||
| 871 | } | ||
| 872 | |||
| 873 | /* Write to a specific I2C slave ID and register, using the specified mask */ | ||
| 874 | static int | ||
| 875 | i2c_w_slave(struct usb_ov511 *ov, | ||
| 876 | unsigned char slave, | ||
| 877 | unsigned char reg, | ||
| 878 | unsigned char value, | ||
| 879 | unsigned char mask) | ||
| 880 | { | ||
| 881 | int rc = 0; | ||
| 882 | |||
| 883 | mutex_lock(&ov->i2c_lock); | ||
| 884 | |||
| 885 | /* Set new slave IDs */ | ||
| 886 | rc = i2c_set_slave_internal(ov, slave); | ||
| 887 | if (rc < 0) | ||
| 888 | goto out; | ||
| 889 | |||
| 890 | rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); | ||
| 891 | |||
| 892 | out: | ||
| 893 | /* Restore primary IDs */ | ||
| 894 | if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) | ||
| 895 | err("Couldn't restore primary I2C slave"); | ||
| 896 | |||
| 897 | mutex_unlock(&ov->i2c_lock); | ||
| 898 | return rc; | ||
| 899 | } | ||
| 900 | |||
| 901 | /* Read from a specific I2C slave ID and register */ | ||
| 902 | static int | ||
| 903 | i2c_r_slave(struct usb_ov511 *ov, | ||
| 904 | unsigned char slave, | ||
| 905 | unsigned char reg) | ||
| 906 | { | ||
| 907 | int rc; | ||
| 908 | |||
| 909 | mutex_lock(&ov->i2c_lock); | ||
| 910 | |||
| 911 | /* Set new slave IDs */ | ||
| 912 | rc = i2c_set_slave_internal(ov, slave); | ||
| 913 | if (rc < 0) | ||
| 914 | goto out; | ||
| 915 | |||
| 916 | if (ov->bclass == BCL_OV518) | ||
| 917 | rc = ov518_i2c_read_internal(ov, reg); | ||
| 918 | else | ||
| 919 | rc = ov511_i2c_read_internal(ov, reg); | ||
| 920 | |||
| 921 | out: | ||
| 922 | /* Restore primary IDs */ | ||
| 923 | if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) | ||
| 924 | err("Couldn't restore primary I2C slave"); | ||
| 925 | |||
| 926 | mutex_unlock(&ov->i2c_lock); | ||
| 927 | return rc; | ||
| 928 | } | ||
| 929 | |||
| 930 | /* Sets I2C read and write slave IDs. Returns <0 for error */ | ||
| 931 | static int | ||
| 932 | ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) | ||
| 933 | { | ||
| 934 | int rc; | ||
| 935 | |||
| 936 | mutex_lock(&ov->i2c_lock); | ||
| 937 | |||
| 938 | rc = i2c_set_slave_internal(ov, sid); | ||
| 939 | if (rc < 0) | ||
| 940 | goto out; | ||
| 941 | |||
| 942 | // FIXME: Is this actually necessary? | ||
| 943 | rc = ov51x_reset(ov, OV511_RESET_NOREGS); | ||
| 944 | out: | ||
| 945 | mutex_unlock(&ov->i2c_lock); | ||
| 946 | return rc; | ||
| 947 | } | ||
| 948 | |||
| 949 | static int | ||
| 950 | write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) | ||
| 951 | { | ||
| 952 | int rc; | ||
| 953 | |||
| 954 | while (pRegvals->bus != OV511_DONE_BUS) { | ||
| 955 | if (pRegvals->bus == OV511_REG_BUS) { | ||
| 956 | if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) | ||
| 957 | return rc; | ||
| 958 | } else if (pRegvals->bus == OV511_I2C_BUS) { | ||
| 959 | if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) | ||
| 960 | return rc; | ||
| 961 | } else { | ||
| 962 | err("Bad regval array"); | ||
| 963 | return -1; | ||
| 964 | } | ||
| 965 | pRegvals++; | ||
| 966 | } | ||
| 967 | return 0; | ||
| 968 | } | ||
| 969 | |||
| 970 | #ifdef OV511_DEBUG | ||
| 971 | static void | ||
| 972 | dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) | ||
| 973 | { | ||
| 974 | int i, rc; | ||
| 975 | |||
| 976 | for (i = reg1; i <= regn; i++) { | ||
| 977 | rc = i2c_r(ov, i); | ||
| 978 | info("Sensor[0x%02X] = 0x%02X", i, rc); | ||
| 979 | } | ||
| 980 | } | ||
| 981 | |||
| 982 | static void | ||
| 983 | dump_i2c_regs(struct usb_ov511 *ov) | ||
| 984 | { | ||
| 985 | info("I2C REGS"); | ||
| 986 | dump_i2c_range(ov, 0x00, 0x7C); | ||
| 987 | } | ||
| 988 | |||
| 989 | static void | ||
| 990 | dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) | ||
| 991 | { | ||
| 992 | int i, rc; | ||
| 993 | |||
| 994 | for (i = reg1; i <= regn; i++) { | ||
| 995 | rc = reg_r(ov, i); | ||
| 996 | info("OV511[0x%02X] = 0x%02X", i, rc); | ||
| 997 | } | ||
| 998 | } | ||
| 999 | |||
| 1000 | static void | ||
| 1001 | ov511_dump_regs(struct usb_ov511 *ov) | ||
| 1002 | { | ||
| 1003 | info("CAMERA INTERFACE REGS"); | ||
| 1004 | dump_reg_range(ov, 0x10, 0x1f); | ||
| 1005 | info("DRAM INTERFACE REGS"); | ||
| 1006 | dump_reg_range(ov, 0x20, 0x23); | ||
| 1007 | info("ISO FIFO REGS"); | ||
| 1008 | dump_reg_range(ov, 0x30, 0x31); | ||
| 1009 | info("PIO REGS"); | ||
| 1010 | dump_reg_range(ov, 0x38, 0x39); | ||
| 1011 | dump_reg_range(ov, 0x3e, 0x3e); | ||
| 1012 | info("I2C REGS"); | ||
| 1013 | dump_reg_range(ov, 0x40, 0x49); | ||
| 1014 | info("SYSTEM CONTROL REGS"); | ||
| 1015 | dump_reg_range(ov, 0x50, 0x55); | ||
| 1016 | dump_reg_range(ov, 0x5e, 0x5f); | ||
| 1017 | info("OmniCE REGS"); | ||
| 1018 | dump_reg_range(ov, 0x70, 0x79); | ||
| 1019 | /* NOTE: Quantization tables are not readable. You will get the value | ||
| 1020 | * in reg. 0x79 for every table register */ | ||
| 1021 | dump_reg_range(ov, 0x80, 0x9f); | ||
| 1022 | dump_reg_range(ov, 0xa0, 0xbf); | ||
| 1023 | |||
| 1024 | } | ||
| 1025 | |||
| 1026 | static void | ||
| 1027 | ov518_dump_regs(struct usb_ov511 *ov) | ||
| 1028 | { | ||
| 1029 | info("VIDEO MODE REGS"); | ||
| 1030 | dump_reg_range(ov, 0x20, 0x2f); | ||
| 1031 | info("DATA PUMP AND SNAPSHOT REGS"); | ||
| 1032 | dump_reg_range(ov, 0x30, 0x3f); | ||
| 1033 | info("I2C REGS"); | ||
| 1034 | dump_reg_range(ov, 0x40, 0x4f); | ||
| 1035 | info("SYSTEM CONTROL AND VENDOR REGS"); | ||
| 1036 | dump_reg_range(ov, 0x50, 0x5f); | ||
| 1037 | info("60 - 6F"); | ||
| 1038 | dump_reg_range(ov, 0x60, 0x6f); | ||
| 1039 | info("70 - 7F"); | ||
| 1040 | dump_reg_range(ov, 0x70, 0x7f); | ||
| 1041 | info("Y QUANTIZATION TABLE"); | ||
| 1042 | dump_reg_range(ov, 0x80, 0x8f); | ||
| 1043 | info("UV QUANTIZATION TABLE"); | ||
| 1044 | dump_reg_range(ov, 0x90, 0x9f); | ||
| 1045 | info("A0 - BF"); | ||
| 1046 | dump_reg_range(ov, 0xa0, 0xbf); | ||
| 1047 | info("CBR"); | ||
| 1048 | dump_reg_range(ov, 0xc0, 0xcf); | ||
| 1049 | } | ||
| 1050 | #endif | ||
| 1051 | |||
| 1052 | /*****************************************************************************/ | ||
| 1053 | |||
| 1054 | /* Temporarily stops OV511 from functioning. Must do this before changing | ||
| 1055 | * registers while the camera is streaming */ | ||
| 1056 | static inline int | ||
| 1057 | ov51x_stop(struct usb_ov511 *ov) | ||
| 1058 | { | ||
| 1059 | PDEBUG(4, "stopping"); | ||
| 1060 | ov->stopped = 1; | ||
| 1061 | if (ov->bclass == BCL_OV518) | ||
| 1062 | return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a)); | ||
| 1063 | else | ||
| 1064 | return (reg_w(ov, R51x_SYS_RESET, 0x3d)); | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not | ||
| 1068 | * actually stopped (for performance). */ | ||
| 1069 | static inline int | ||
| 1070 | ov51x_restart(struct usb_ov511 *ov) | ||
| 1071 | { | ||
| 1072 | if (ov->stopped) { | ||
| 1073 | PDEBUG(4, "restarting"); | ||
| 1074 | ov->stopped = 0; | ||
| 1075 | |||
| 1076 | /* Reinitialize the stream */ | ||
| 1077 | if (ov->bclass == BCL_OV518) | ||
| 1078 | reg_w(ov, 0x2f, 0x80); | ||
| 1079 | |||
| 1080 | return (reg_w(ov, R51x_SYS_RESET, 0x00)); | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | return 0; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | /* Sleeps until no frames are active. Returns !0 if got signal */ | ||
| 1087 | static int | ||
| 1088 | ov51x_wait_frames_inactive(struct usb_ov511 *ov) | ||
| 1089 | { | ||
| 1090 | return wait_event_interruptible(ov->wq, ov->curframe < 0); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /* Resets the hardware snapshot button */ | ||
| 1094 | static void | ||
| 1095 | ov51x_clear_snapshot(struct usb_ov511 *ov) | ||
| 1096 | { | ||
| 1097 | if (ov->bclass == BCL_OV511) { | ||
| 1098 | reg_w(ov, R51x_SYS_SNAP, 0x00); | ||
| 1099 | reg_w(ov, R51x_SYS_SNAP, 0x02); | ||
| 1100 | reg_w(ov, R51x_SYS_SNAP, 0x00); | ||
| 1101 | } else if (ov->bclass == BCL_OV518) { | ||
| 1102 | warn("snapshot reset not supported yet on OV518(+)"); | ||
| 1103 | } else { | ||
| 1104 | err("clear snap: invalid bridge type"); | ||
| 1105 | } | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | #if 0 | ||
| 1109 | /* Checks the status of the snapshot button. Returns 1 if it was pressed since | ||
| 1110 | * it was last cleared, and zero in all other cases (including errors) */ | ||
| 1111 | static int | ||
| 1112 | ov51x_check_snapshot(struct usb_ov511 *ov) | ||
| 1113 | { | ||
| 1114 | int ret, status = 0; | ||
| 1115 | |||
| 1116 | if (ov->bclass == BCL_OV511) { | ||
| 1117 | ret = reg_r(ov, R51x_SYS_SNAP); | ||
| 1118 | if (ret < 0) { | ||
| 1119 | err("Error checking snspshot status (%d)", ret); | ||
| 1120 | } else if (ret & 0x08) { | ||
| 1121 | status = 1; | ||
| 1122 | } | ||
| 1123 | } else if (ov->bclass == BCL_OV518) { | ||
| 1124 | warn("snapshot check not supported yet on OV518(+)"); | ||
| 1125 | } else { | ||
| 1126 | err("check snap: invalid bridge type"); | ||
| 1127 | } | ||
| 1128 | |||
| 1129 | return status; | ||
| 1130 | } | ||
| 1131 | #endif | ||
| 1132 | |||
| 1133 | /* This does an initial reset of an OmniVision sensor and ensures that I2C | ||
| 1134 | * is synchronized. Returns <0 for failure. | ||
| 1135 | */ | ||
| 1136 | static int | ||
| 1137 | init_ov_sensor(struct usb_ov511 *ov) | ||
| 1138 | { | ||
| 1139 | int i, success; | ||
| 1140 | |||
| 1141 | /* Reset the sensor */ | ||
| 1142 | if (i2c_w(ov, 0x12, 0x80) < 0) | ||
| 1143 | return -EIO; | ||
| 1144 | |||
| 1145 | /* Wait for it to initialize */ | ||
| 1146 | msleep(150); | ||
| 1147 | |||
| 1148 | for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { | ||
| 1149 | if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && | ||
| 1150 | (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { | ||
| 1151 | success = 1; | ||
| 1152 | continue; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | /* Reset the sensor */ | ||
| 1156 | if (i2c_w(ov, 0x12, 0x80) < 0) | ||
| 1157 | return -EIO; | ||
| 1158 | /* Wait for it to initialize */ | ||
| 1159 | msleep(150); | ||
| 1160 | /* Dummy read to sync I2C */ | ||
| 1161 | if (i2c_r(ov, 0x00) < 0) | ||
| 1162 | return -EIO; | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | if (!success) | ||
| 1166 | return -EIO; | ||
| 1167 | |||
| 1168 | PDEBUG(1, "I2C synced in %d attempt(s)", i); | ||
| 1169 | |||
| 1170 | return 0; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | static int | ||
| 1174 | ov511_set_packet_size(struct usb_ov511 *ov, int size) | ||
| 1175 | { | ||
| 1176 | int alt, mult; | ||
| 1177 | |||
| 1178 | if (ov51x_stop(ov) < 0) | ||
| 1179 | return -EIO; | ||
| 1180 | |||
| 1181 | mult = size >> 5; | ||
| 1182 | |||
| 1183 | if (ov->bridge == BRG_OV511) { | ||
| 1184 | if (size == 0) | ||
| 1185 | alt = OV511_ALT_SIZE_0; | ||
| 1186 | else if (size == 257) | ||
| 1187 | alt = OV511_ALT_SIZE_257; | ||
| 1188 | else if (size == 513) | ||
| 1189 | alt = OV511_ALT_SIZE_513; | ||
| 1190 | else if (size == 769) | ||
| 1191 | alt = OV511_ALT_SIZE_769; | ||
| 1192 | else if (size == 993) | ||
| 1193 | alt = OV511_ALT_SIZE_993; | ||
| 1194 | else { | ||
| 1195 | err("Set packet size: invalid size (%d)", size); | ||
| 1196 | return -EINVAL; | ||
| 1197 | } | ||
| 1198 | } else if (ov->bridge == BRG_OV511PLUS) { | ||
| 1199 | if (size == 0) | ||
| 1200 | alt = OV511PLUS_ALT_SIZE_0; | ||
| 1201 | else if (size == 33) | ||
| 1202 | alt = OV511PLUS_ALT_SIZE_33; | ||
| 1203 | else if (size == 129) | ||
| 1204 | alt = OV511PLUS_ALT_SIZE_129; | ||
| 1205 | else if (size == 257) | ||
| 1206 | alt = OV511PLUS_ALT_SIZE_257; | ||
| 1207 | else if (size == 385) | ||
| 1208 | alt = OV511PLUS_ALT_SIZE_385; | ||
| 1209 | else if (size == 513) | ||
| 1210 | alt = OV511PLUS_ALT_SIZE_513; | ||
| 1211 | else if (size == 769) | ||
| 1212 | alt = OV511PLUS_ALT_SIZE_769; | ||
| 1213 | else if (size == 961) | ||
| 1214 | alt = OV511PLUS_ALT_SIZE_961; | ||
| 1215 | else { | ||
| 1216 | err("Set packet size: invalid size (%d)", size); | ||
| 1217 | return -EINVAL; | ||
| 1218 | } | ||
| 1219 | } else { | ||
| 1220 | err("Set packet size: Invalid bridge type"); | ||
| 1221 | return -EINVAL; | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt); | ||
| 1225 | |||
| 1226 | if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) | ||
| 1227 | return -EIO; | ||
| 1228 | |||
| 1229 | if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { | ||
| 1230 | err("Set packet size: set interface error"); | ||
| 1231 | return -EBUSY; | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) | ||
| 1235 | return -EIO; | ||
| 1236 | |||
| 1237 | ov->packet_size = size; | ||
| 1238 | |||
| 1239 | if (ov51x_restart(ov) < 0) | ||
| 1240 | return -EIO; | ||
| 1241 | |||
| 1242 | return 0; | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | /* Note: Unlike the OV511/OV511+, the size argument does NOT include the | ||
| 1246 | * optional packet number byte. The actual size *is* stored in ov->packet_size, | ||
| 1247 | * though. */ | ||
| 1248 | static int | ||
| 1249 | ov518_set_packet_size(struct usb_ov511 *ov, int size) | ||
| 1250 | { | ||
| 1251 | int alt; | ||
| 1252 | |||
| 1253 | if (ov51x_stop(ov) < 0) | ||
| 1254 | return -EIO; | ||
| 1255 | |||
| 1256 | if (ov->bclass == BCL_OV518) { | ||
| 1257 | if (size == 0) | ||
| 1258 | alt = OV518_ALT_SIZE_0; | ||
| 1259 | else if (size == 128) | ||
| 1260 | alt = OV518_ALT_SIZE_128; | ||
| 1261 | else if (size == 256) | ||
| 1262 | alt = OV518_ALT_SIZE_256; | ||
| 1263 | else if (size == 384) | ||
| 1264 | alt = OV518_ALT_SIZE_384; | ||
| 1265 | else if (size == 512) | ||
| 1266 | alt = OV518_ALT_SIZE_512; | ||
| 1267 | else if (size == 640) | ||
| 1268 | alt = OV518_ALT_SIZE_640; | ||
| 1269 | else if (size == 768) | ||
| 1270 | alt = OV518_ALT_SIZE_768; | ||
| 1271 | else if (size == 896) | ||
| 1272 | alt = OV518_ALT_SIZE_896; | ||
| 1273 | else { | ||
| 1274 | err("Set packet size: invalid size (%d)", size); | ||
| 1275 | return -EINVAL; | ||
| 1276 | } | ||
| 1277 | } else { | ||
| 1278 | err("Set packet size: Invalid bridge type"); | ||
| 1279 | return -EINVAL; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | PDEBUG(3, "%d, alt=%d", size, alt); | ||
| 1283 | |||
| 1284 | ov->packet_size = size; | ||
| 1285 | if (size > 0) { | ||
| 1286 | /* Program ISO FIFO size reg (packet number isn't included) */ | ||
| 1287 | ov518_reg_w32(ov, 0x30, size, 2); | ||
| 1288 | |||
| 1289 | if (ov->packet_numbering) | ||
| 1290 | ++ov->packet_size; | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { | ||
| 1294 | err("Set packet size: set interface error"); | ||
| 1295 | return -EBUSY; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | /* Initialize the stream */ | ||
| 1299 | if (reg_w(ov, 0x2f, 0x80) < 0) | ||
| 1300 | return -EIO; | ||
| 1301 | |||
| 1302 | if (ov51x_restart(ov) < 0) | ||
| 1303 | return -EIO; | ||
| 1304 | |||
| 1305 | if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) | ||
| 1306 | return -EIO; | ||
| 1307 | |||
| 1308 | return 0; | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | /* Upload compression params and quantization tables. Returns 0 for success. */ | ||
| 1312 | static int | ||
| 1313 | ov511_init_compression(struct usb_ov511 *ov) | ||
| 1314 | { | ||
| 1315 | int rc = 0; | ||
| 1316 | |||
| 1317 | if (!ov->compress_inited) { | ||
| 1318 | reg_w(ov, 0x70, phy); | ||
| 1319 | reg_w(ov, 0x71, phuv); | ||
| 1320 | reg_w(ov, 0x72, pvy); | ||
| 1321 | reg_w(ov, 0x73, pvuv); | ||
| 1322 | reg_w(ov, 0x74, qhy); | ||
| 1323 | reg_w(ov, 0x75, qhuv); | ||
| 1324 | reg_w(ov, 0x76, qvy); | ||
| 1325 | reg_w(ov, 0x77, qvuv); | ||
| 1326 | |||
| 1327 | if (ov511_upload_quan_tables(ov) < 0) { | ||
| 1328 | err("Error uploading quantization tables"); | ||
| 1329 | rc = -EIO; | ||
| 1330 | goto out; | ||
| 1331 | } | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | ov->compress_inited = 1; | ||
| 1335 | out: | ||
| 1336 | return rc; | ||
| 1337 | } | ||
| 1338 | |||
| 1339 | /* Upload compression params and quantization tables. Returns 0 for success. */ | ||
| 1340 | static int | ||
| 1341 | ov518_init_compression(struct usb_ov511 *ov) | ||
| 1342 | { | ||
| 1343 | int rc = 0; | ||
| 1344 | |||
| 1345 | if (!ov->compress_inited) { | ||
| 1346 | if (ov518_upload_quan_tables(ov) < 0) { | ||
| 1347 | err("Error uploading quantization tables"); | ||
| 1348 | rc = -EIO; | ||
| 1349 | goto out; | ||
| 1350 | } | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | ov->compress_inited = 1; | ||
| 1354 | out: | ||
| 1355 | return rc; | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | /* -------------------------------------------------------------------------- */ | ||
| 1359 | |||
| 1360 | /* Sets sensor's contrast setting to "val" */ | ||
| 1361 | static int | ||
| 1362 | sensor_set_contrast(struct usb_ov511 *ov, unsigned short val) | ||
| 1363 | { | ||
| 1364 | int rc; | ||
| 1365 | |||
| 1366 | PDEBUG(3, "%d", val); | ||
| 1367 | |||
| 1368 | if (ov->stop_during_set) | ||
| 1369 | if (ov51x_stop(ov) < 0) | ||
| 1370 | return -EIO; | ||
| 1371 | |||
| 1372 | switch (ov->sensor) { | ||
| 1373 | case SEN_OV7610: | ||
| 1374 | case SEN_OV6620: | ||
| 1375 | { | ||
| 1376 | rc = i2c_w(ov, OV7610_REG_CNT, val >> 8); | ||
| 1377 | if (rc < 0) | ||
| 1378 | goto out; | ||
| 1379 | break; | ||
| 1380 | } | ||
| 1381 | case SEN_OV6630: | ||
| 1382 | { | ||
| 1383 | rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f); | ||
| 1384 | if (rc < 0) | ||
| 1385 | goto out; | ||
| 1386 | break; | ||
| 1387 | } | ||
| 1388 | case SEN_OV7620: | ||
| 1389 | { | ||
| 1390 | unsigned char ctab[] = { | ||
| 1391 | 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, | ||
| 1392 | 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff | ||
| 1393 | }; | ||
| 1394 | |||
| 1395 | /* Use Y gamma control instead. Bit 0 enables it. */ | ||
| 1396 | rc = i2c_w(ov, 0x64, ctab[val>>12]); | ||
| 1397 | if (rc < 0) | ||
| 1398 | goto out; | ||
| 1399 | break; | ||
| 1400 | } | ||
| 1401 | case SEN_SAA7111A: | ||
| 1402 | { | ||
| 1403 | rc = i2c_w(ov, 0x0b, val >> 9); | ||
| 1404 | if (rc < 0) | ||
| 1405 | goto out; | ||
| 1406 | break; | ||
| 1407 | } | ||
| 1408 | default: | ||
| 1409 | { | ||
| 1410 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1411 | rc = -EPERM; | ||
| 1412 | goto out; | ||
| 1413 | } | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | rc = 0; /* Success */ | ||
| 1417 | ov->contrast = val; | ||
| 1418 | out: | ||
| 1419 | if (ov51x_restart(ov) < 0) | ||
| 1420 | return -EIO; | ||
| 1421 | |||
| 1422 | return rc; | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | /* Gets sensor's contrast setting */ | ||
| 1426 | static int | ||
| 1427 | sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val) | ||
| 1428 | { | ||
| 1429 | int rc; | ||
| 1430 | |||
| 1431 | switch (ov->sensor) { | ||
| 1432 | case SEN_OV7610: | ||
| 1433 | case SEN_OV6620: | ||
| 1434 | rc = i2c_r(ov, OV7610_REG_CNT); | ||
| 1435 | if (rc < 0) | ||
| 1436 | return rc; | ||
| 1437 | else | ||
| 1438 | *val = rc << 8; | ||
| 1439 | break; | ||
| 1440 | case SEN_OV6630: | ||
| 1441 | rc = i2c_r(ov, OV7610_REG_CNT); | ||
| 1442 | if (rc < 0) | ||
| 1443 | return rc; | ||
| 1444 | else | ||
| 1445 | *val = rc << 12; | ||
| 1446 | break; | ||
| 1447 | case SEN_OV7620: | ||
| 1448 | /* Use Y gamma reg instead. Bit 0 is the enable bit. */ | ||
| 1449 | rc = i2c_r(ov, 0x64); | ||
| 1450 | if (rc < 0) | ||
| 1451 | return rc; | ||
| 1452 | else | ||
| 1453 | *val = (rc & 0xfe) << 8; | ||
| 1454 | break; | ||
| 1455 | case SEN_SAA7111A: | ||
| 1456 | *val = ov->contrast; | ||
| 1457 | break; | ||
| 1458 | default: | ||
| 1459 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1460 | return -EPERM; | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | PDEBUG(3, "%d", *val); | ||
| 1464 | ov->contrast = *val; | ||
| 1465 | |||
| 1466 | return 0; | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | /* -------------------------------------------------------------------------- */ | ||
| 1470 | |||
| 1471 | /* Sets sensor's brightness setting to "val" */ | ||
| 1472 | static int | ||
| 1473 | sensor_set_brightness(struct usb_ov511 *ov, unsigned short val) | ||
| 1474 | { | ||
| 1475 | int rc; | ||
| 1476 | |||
| 1477 | PDEBUG(4, "%d", val); | ||
| 1478 | |||
| 1479 | if (ov->stop_during_set) | ||
| 1480 | if (ov51x_stop(ov) < 0) | ||
| 1481 | return -EIO; | ||
| 1482 | |||
| 1483 | switch (ov->sensor) { | ||
| 1484 | case SEN_OV7610: | ||
| 1485 | case SEN_OV76BE: | ||
| 1486 | case SEN_OV6620: | ||
| 1487 | case SEN_OV6630: | ||
| 1488 | rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); | ||
| 1489 | if (rc < 0) | ||
| 1490 | goto out; | ||
| 1491 | break; | ||
| 1492 | case SEN_OV7620: | ||
| 1493 | /* 7620 doesn't like manual changes when in auto mode */ | ||
| 1494 | if (!ov->auto_brt) { | ||
| 1495 | rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); | ||
| 1496 | if (rc < 0) | ||
| 1497 | goto out; | ||
| 1498 | } | ||
| 1499 | break; | ||
| 1500 | case SEN_SAA7111A: | ||
| 1501 | rc = i2c_w(ov, 0x0a, val >> 8); | ||
| 1502 | if (rc < 0) | ||
| 1503 | goto out; | ||
| 1504 | break; | ||
| 1505 | default: | ||
| 1506 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1507 | rc = -EPERM; | ||
| 1508 | goto out; | ||
| 1509 | } | ||
| 1510 | |||
| 1511 | rc = 0; /* Success */ | ||
| 1512 | ov->brightness = val; | ||
| 1513 | out: | ||
| 1514 | if (ov51x_restart(ov) < 0) | ||
| 1515 | return -EIO; | ||
| 1516 | |||
| 1517 | return rc; | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | /* Gets sensor's brightness setting */ | ||
| 1521 | static int | ||
| 1522 | sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val) | ||
| 1523 | { | ||
| 1524 | int rc; | ||
| 1525 | |||
| 1526 | switch (ov->sensor) { | ||
| 1527 | case SEN_OV7610: | ||
| 1528 | case SEN_OV76BE: | ||
| 1529 | case SEN_OV7620: | ||
| 1530 | case SEN_OV6620: | ||
| 1531 | case SEN_OV6630: | ||
| 1532 | rc = i2c_r(ov, OV7610_REG_BRT); | ||
| 1533 | if (rc < 0) | ||
| 1534 | return rc; | ||
| 1535 | else | ||
| 1536 | *val = rc << 8; | ||
| 1537 | break; | ||
| 1538 | case SEN_SAA7111A: | ||
| 1539 | *val = ov->brightness; | ||
| 1540 | break; | ||
| 1541 | default: | ||
| 1542 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1543 | return -EPERM; | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | PDEBUG(3, "%d", *val); | ||
| 1547 | ov->brightness = *val; | ||
| 1548 | |||
| 1549 | return 0; | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | /* -------------------------------------------------------------------------- */ | ||
| 1553 | |||
| 1554 | /* Sets sensor's saturation (color intensity) setting to "val" */ | ||
| 1555 | static int | ||
| 1556 | sensor_set_saturation(struct usb_ov511 *ov, unsigned short val) | ||
| 1557 | { | ||
| 1558 | int rc; | ||
| 1559 | |||
| 1560 | PDEBUG(3, "%d", val); | ||
| 1561 | |||
| 1562 | if (ov->stop_during_set) | ||
| 1563 | if (ov51x_stop(ov) < 0) | ||
| 1564 | return -EIO; | ||
| 1565 | |||
| 1566 | switch (ov->sensor) { | ||
| 1567 | case SEN_OV7610: | ||
| 1568 | case SEN_OV76BE: | ||
| 1569 | case SEN_OV6620: | ||
| 1570 | case SEN_OV6630: | ||
| 1571 | rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); | ||
| 1572 | if (rc < 0) | ||
| 1573 | goto out; | ||
| 1574 | break; | ||
| 1575 | case SEN_OV7620: | ||
| 1576 | // /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ | ||
| 1577 | // rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e); | ||
| 1578 | // if (rc < 0) | ||
| 1579 | // goto out; | ||
| 1580 | rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); | ||
| 1581 | if (rc < 0) | ||
| 1582 | goto out; | ||
| 1583 | break; | ||
| 1584 | case SEN_SAA7111A: | ||
| 1585 | rc = i2c_w(ov, 0x0c, val >> 9); | ||
| 1586 | if (rc < 0) | ||
| 1587 | goto out; | ||
| 1588 | break; | ||
| 1589 | default: | ||
| 1590 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1591 | rc = -EPERM; | ||
| 1592 | goto out; | ||
| 1593 | } | ||
| 1594 | |||
| 1595 | rc = 0; /* Success */ | ||
| 1596 | ov->colour = val; | ||
| 1597 | out: | ||
| 1598 | if (ov51x_restart(ov) < 0) | ||
| 1599 | return -EIO; | ||
| 1600 | |||
| 1601 | return rc; | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | /* Gets sensor's saturation (color intensity) setting */ | ||
| 1605 | static int | ||
| 1606 | sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val) | ||
| 1607 | { | ||
| 1608 | int rc; | ||
| 1609 | |||
| 1610 | switch (ov->sensor) { | ||
| 1611 | case SEN_OV7610: | ||
| 1612 | case SEN_OV76BE: | ||
| 1613 | case SEN_OV6620: | ||
| 1614 | case SEN_OV6630: | ||
| 1615 | rc = i2c_r(ov, OV7610_REG_SAT); | ||
| 1616 | if (rc < 0) | ||
| 1617 | return rc; | ||
| 1618 | else | ||
| 1619 | *val = rc << 8; | ||
| 1620 | break; | ||
| 1621 | case SEN_OV7620: | ||
| 1622 | // /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ | ||
| 1623 | // rc = i2c_r(ov, 0x62); | ||
| 1624 | // if (rc < 0) | ||
| 1625 | // return rc; | ||
| 1626 | // else | ||
| 1627 | // *val = (rc & 0x7e) << 9; | ||
| 1628 | rc = i2c_r(ov, OV7610_REG_SAT); | ||
| 1629 | if (rc < 0) | ||
| 1630 | return rc; | ||
| 1631 | else | ||
| 1632 | *val = rc << 8; | ||
| 1633 | break; | ||
| 1634 | case SEN_SAA7111A: | ||
| 1635 | *val = ov->colour; | ||
| 1636 | break; | ||
| 1637 | default: | ||
| 1638 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1639 | return -EPERM; | ||
| 1640 | } | ||
| 1641 | |||
| 1642 | PDEBUG(3, "%d", *val); | ||
| 1643 | ov->colour = *val; | ||
| 1644 | |||
| 1645 | return 0; | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | /* -------------------------------------------------------------------------- */ | ||
| 1649 | |||
| 1650 | /* Sets sensor's hue (red/blue balance) setting to "val" */ | ||
| 1651 | static int | ||
| 1652 | sensor_set_hue(struct usb_ov511 *ov, unsigned short val) | ||
| 1653 | { | ||
| 1654 | int rc; | ||
| 1655 | |||
| 1656 | PDEBUG(3, "%d", val); | ||
| 1657 | |||
| 1658 | if (ov->stop_during_set) | ||
| 1659 | if (ov51x_stop(ov) < 0) | ||
| 1660 | return -EIO; | ||
| 1661 | |||
| 1662 | switch (ov->sensor) { | ||
| 1663 | case SEN_OV7610: | ||
| 1664 | case SEN_OV6620: | ||
| 1665 | case SEN_OV6630: | ||
| 1666 | rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8)); | ||
| 1667 | if (rc < 0) | ||
| 1668 | goto out; | ||
| 1669 | |||
| 1670 | rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8); | ||
| 1671 | if (rc < 0) | ||
| 1672 | goto out; | ||
| 1673 | break; | ||
| 1674 | case SEN_OV7620: | ||
| 1675 | // Hue control is causing problems. I will enable it once it's fixed. | ||
| 1676 | #if 0 | ||
| 1677 | rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb); | ||
| 1678 | if (rc < 0) | ||
| 1679 | goto out; | ||
| 1680 | |||
| 1681 | rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb); | ||
| 1682 | if (rc < 0) | ||
| 1683 | goto out; | ||
| 1684 | #endif | ||
| 1685 | break; | ||
| 1686 | case SEN_SAA7111A: | ||
| 1687 | rc = i2c_w(ov, 0x0d, (val + 32768) >> 8); | ||
| 1688 | if (rc < 0) | ||
| 1689 | goto out; | ||
| 1690 | break; | ||
| 1691 | default: | ||
| 1692 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1693 | rc = -EPERM; | ||
| 1694 | goto out; | ||
| 1695 | } | ||
| 1696 | |||
| 1697 | rc = 0; /* Success */ | ||
| 1698 | ov->hue = val; | ||
| 1699 | out: | ||
| 1700 | if (ov51x_restart(ov) < 0) | ||
| 1701 | return -EIO; | ||
| 1702 | |||
| 1703 | return rc; | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | /* Gets sensor's hue (red/blue balance) setting */ | ||
| 1707 | static int | ||
| 1708 | sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) | ||
| 1709 | { | ||
| 1710 | int rc; | ||
| 1711 | |||
| 1712 | switch (ov->sensor) { | ||
| 1713 | case SEN_OV7610: | ||
| 1714 | case SEN_OV6620: | ||
| 1715 | case SEN_OV6630: | ||
| 1716 | rc = i2c_r(ov, OV7610_REG_BLUE); | ||
| 1717 | if (rc < 0) | ||
| 1718 | return rc; | ||
| 1719 | else | ||
| 1720 | *val = rc << 8; | ||
| 1721 | break; | ||
| 1722 | case SEN_OV7620: | ||
| 1723 | rc = i2c_r(ov, 0x7a); | ||
| 1724 | if (rc < 0) | ||
| 1725 | return rc; | ||
| 1726 | else | ||
| 1727 | *val = rc << 8; | ||
| 1728 | break; | ||
| 1729 | case SEN_SAA7111A: | ||
| 1730 | *val = ov->hue; | ||
| 1731 | break; | ||
| 1732 | default: | ||
| 1733 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1734 | return -EPERM; | ||
| 1735 | } | ||
| 1736 | |||
| 1737 | PDEBUG(3, "%d", *val); | ||
| 1738 | ov->hue = *val; | ||
| 1739 | |||
| 1740 | return 0; | ||
| 1741 | } | ||
| 1742 | |||
| 1743 | /* -------------------------------------------------------------------------- */ | ||
| 1744 | |||
| 1745 | static int | ||
| 1746 | sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) | ||
| 1747 | { | ||
| 1748 | int rc; | ||
| 1749 | |||
| 1750 | PDEBUG(4, "sensor_set_picture"); | ||
| 1751 | |||
| 1752 | ov->whiteness = p->whiteness; | ||
| 1753 | |||
| 1754 | /* Don't return error if a setting is unsupported, or rest of settings | ||
| 1755 | * will not be performed */ | ||
| 1756 | |||
| 1757 | rc = sensor_set_contrast(ov, p->contrast); | ||
| 1758 | if (FATAL_ERROR(rc)) | ||
| 1759 | return rc; | ||
| 1760 | |||
| 1761 | rc = sensor_set_brightness(ov, p->brightness); | ||
| 1762 | if (FATAL_ERROR(rc)) | ||
| 1763 | return rc; | ||
| 1764 | |||
| 1765 | rc = sensor_set_saturation(ov, p->colour); | ||
| 1766 | if (FATAL_ERROR(rc)) | ||
| 1767 | return rc; | ||
| 1768 | |||
| 1769 | rc = sensor_set_hue(ov, p->hue); | ||
| 1770 | if (FATAL_ERROR(rc)) | ||
| 1771 | return rc; | ||
| 1772 | |||
| 1773 | return 0; | ||
| 1774 | } | ||
| 1775 | |||
| 1776 | static int | ||
| 1777 | sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) | ||
| 1778 | { | ||
| 1779 | int rc; | ||
| 1780 | |||
| 1781 | PDEBUG(4, "sensor_get_picture"); | ||
| 1782 | |||
| 1783 | /* Don't return error if a setting is unsupported, or rest of settings | ||
| 1784 | * will not be performed */ | ||
| 1785 | |||
| 1786 | rc = sensor_get_contrast(ov, &(p->contrast)); | ||
| 1787 | if (FATAL_ERROR(rc)) | ||
| 1788 | return rc; | ||
| 1789 | |||
| 1790 | rc = sensor_get_brightness(ov, &(p->brightness)); | ||
| 1791 | if (FATAL_ERROR(rc)) | ||
| 1792 | return rc; | ||
| 1793 | |||
| 1794 | rc = sensor_get_saturation(ov, &(p->colour)); | ||
| 1795 | if (FATAL_ERROR(rc)) | ||
| 1796 | return rc; | ||
| 1797 | |||
| 1798 | rc = sensor_get_hue(ov, &(p->hue)); | ||
| 1799 | if (FATAL_ERROR(rc)) | ||
| 1800 | return rc; | ||
| 1801 | |||
| 1802 | p->whiteness = 105 << 8; | ||
| 1803 | |||
| 1804 | return 0; | ||
| 1805 | } | ||
| 1806 | |||
| 1807 | #if 0 | ||
| 1808 | // FIXME: Exposure range is only 0x00-0x7f in interlace mode | ||
| 1809 | /* Sets current exposure for sensor. This only has an effect if auto-exposure | ||
| 1810 | * is off */ | ||
| 1811 | static inline int | ||
| 1812 | sensor_set_exposure(struct usb_ov511 *ov, unsigned char val) | ||
| 1813 | { | ||
| 1814 | int rc; | ||
| 1815 | |||
| 1816 | PDEBUG(3, "%d", val); | ||
| 1817 | |||
| 1818 | if (ov->stop_during_set) | ||
| 1819 | if (ov51x_stop(ov) < 0) | ||
| 1820 | return -EIO; | ||
| 1821 | |||
| 1822 | switch (ov->sensor) { | ||
| 1823 | case SEN_OV6620: | ||
| 1824 | case SEN_OV6630: | ||
| 1825 | case SEN_OV7610: | ||
| 1826 | case SEN_OV7620: | ||
| 1827 | case SEN_OV76BE: | ||
| 1828 | case SEN_OV8600: | ||
| 1829 | rc = i2c_w(ov, 0x10, val); | ||
| 1830 | if (rc < 0) | ||
| 1831 | goto out; | ||
| 1832 | |||
| 1833 | break; | ||
| 1834 | case SEN_KS0127: | ||
| 1835 | case SEN_KS0127B: | ||
| 1836 | case SEN_SAA7111A: | ||
| 1837 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1838 | return -EPERM; | ||
| 1839 | default: | ||
| 1840 | err("Sensor not supported for set_exposure"); | ||
| 1841 | return -EINVAL; | ||
| 1842 | } | ||
| 1843 | |||
| 1844 | rc = 0; /* Success */ | ||
| 1845 | ov->exposure = val; | ||
| 1846 | out: | ||
| 1847 | if (ov51x_restart(ov) < 0) | ||
| 1848 | return -EIO; | ||
| 1849 | |||
| 1850 | return rc; | ||
| 1851 | } | ||
| 1852 | #endif | ||
| 1853 | |||
| 1854 | /* Gets current exposure level from sensor, regardless of whether it is under | ||
| 1855 | * manual control. */ | ||
| 1856 | static int | ||
| 1857 | sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) | ||
| 1858 | { | ||
| 1859 | int rc; | ||
| 1860 | |||
| 1861 | switch (ov->sensor) { | ||
| 1862 | case SEN_OV7610: | ||
| 1863 | case SEN_OV6620: | ||
| 1864 | case SEN_OV6630: | ||
| 1865 | case SEN_OV7620: | ||
| 1866 | case SEN_OV76BE: | ||
| 1867 | case SEN_OV8600: | ||
| 1868 | rc = i2c_r(ov, 0x10); | ||
| 1869 | if (rc < 0) | ||
| 1870 | return rc; | ||
| 1871 | else | ||
| 1872 | *val = rc; | ||
| 1873 | break; | ||
| 1874 | case SEN_KS0127: | ||
| 1875 | case SEN_KS0127B: | ||
| 1876 | case SEN_SAA7111A: | ||
| 1877 | val = NULL; | ||
| 1878 | PDEBUG(3, "Unsupported with this sensor"); | ||
| 1879 | return -EPERM; | ||
| 1880 | default: | ||
| 1881 | err("Sensor not supported for get_exposure"); | ||
| 1882 | return -EINVAL; | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | PDEBUG(3, "%d", *val); | ||
| 1886 | ov->exposure = *val; | ||
| 1887 | |||
| 1888 | return 0; | ||
| 1889 | } | ||
| 1890 | |||
| 1891 | /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ | ||
| 1892 | static void | ||
| 1893 | ov51x_led_control(struct usb_ov511 *ov, int enable) | ||
| 1894 | { | ||
| 1895 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
| 1896 | |||
| 1897 | if (ov->bridge == BRG_OV511PLUS) | ||
| 1898 | reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0); | ||
| 1899 | else if (ov->bclass == BCL_OV518) | ||
| 1900 | reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02); | ||
| 1901 | |||
| 1902 | return; | ||
| 1903 | } | ||
| 1904 | |||
| 1905 | /* Matches the sensor's internal frame rate to the lighting frequency. | ||
| 1906 | * Valid frequencies are: | ||
| 1907 | * 50 - 50Hz, for European and Asian lighting | ||
| 1908 | * 60 - 60Hz, for American lighting | ||
| 1909 | * | ||
| 1910 | * Tested with: OV7610, OV7620, OV76BE, OV6620 | ||
| 1911 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
| 1912 | * Returns: 0 for success | ||
| 1913 | */ | ||
| 1914 | static int | ||
| 1915 | sensor_set_light_freq(struct usb_ov511 *ov, int freq) | ||
| 1916 | { | ||
| 1917 | int sixty; | ||
| 1918 | |||
| 1919 | PDEBUG(4, "%d Hz", freq); | ||
| 1920 | |||
| 1921 | if (freq == 60) | ||
| 1922 | sixty = 1; | ||
| 1923 | else if (freq == 50) | ||
| 1924 | sixty = 0; | ||
| 1925 | else { | ||
| 1926 | err("Invalid light freq (%d Hz)", freq); | ||
| 1927 | return -EINVAL; | ||
| 1928 | } | ||
| 1929 | |||
| 1930 | switch (ov->sensor) { | ||
| 1931 | case SEN_OV7610: | ||
| 1932 | i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); | ||
| 1933 | i2c_w(ov, 0x2b, sixty?0x00:0xac); | ||
| 1934 | i2c_w_mask(ov, 0x13, 0x10, 0x10); | ||
| 1935 | i2c_w_mask(ov, 0x13, 0x00, 0x10); | ||
| 1936 | break; | ||
| 1937 | case SEN_OV7620: | ||
| 1938 | case SEN_OV76BE: | ||
| 1939 | case SEN_OV8600: | ||
| 1940 | i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); | ||
| 1941 | i2c_w(ov, 0x2b, sixty?0x00:0xac); | ||
| 1942 | i2c_w_mask(ov, 0x76, 0x01, 0x01); | ||
| 1943 | break; | ||
| 1944 | case SEN_OV6620: | ||
| 1945 | case SEN_OV6630: | ||
| 1946 | i2c_w(ov, 0x2b, sixty?0xa8:0x28); | ||
| 1947 | i2c_w(ov, 0x2a, sixty?0x84:0xa4); | ||
| 1948 | break; | ||
| 1949 | case SEN_KS0127: | ||
| 1950 | case SEN_KS0127B: | ||
| 1951 | case SEN_SAA7111A: | ||
| 1952 | PDEBUG(5, "Unsupported with this sensor"); | ||
| 1953 | return -EPERM; | ||
| 1954 | default: | ||
| 1955 | err("Sensor not supported for set_light_freq"); | ||
| 1956 | return -EINVAL; | ||
| 1957 | } | ||
| 1958 | |||
| 1959 | ov->lightfreq = freq; | ||
| 1960 | |||
| 1961 | return 0; | ||
| 1962 | } | ||
| 1963 | |||
| 1964 | /* If enable is true, turn on the sensor's banding filter, otherwise turn it | ||
| 1965 | * off. This filter tries to reduce the pattern of horizontal light/dark bands | ||
| 1966 | * caused by some (usually fluorescent) lighting. The light frequency must be | ||
| 1967 | * set either before or after enabling it with ov51x_set_light_freq(). | ||
| 1968 | * | ||
| 1969 | * Tested with: OV7610, OV7620, OV76BE, OV6620. | ||
| 1970 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
| 1971 | * Returns: 0 for success | ||
| 1972 | */ | ||
| 1973 | static int | ||
| 1974 | sensor_set_banding_filter(struct usb_ov511 *ov, int enable) | ||
| 1975 | { | ||
| 1976 | int rc; | ||
| 1977 | |||
| 1978 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
| 1979 | |||
| 1980 | if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B | ||
| 1981 | || ov->sensor == SEN_SAA7111A) { | ||
| 1982 | PDEBUG(5, "Unsupported with this sensor"); | ||
| 1983 | return -EPERM; | ||
| 1984 | } | ||
| 1985 | |||
| 1986 | rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04); | ||
| 1987 | if (rc < 0) | ||
| 1988 | return rc; | ||
| 1989 | |||
| 1990 | ov->bandfilt = enable; | ||
| 1991 | |||
| 1992 | return 0; | ||
| 1993 | } | ||
| 1994 | |||
| 1995 | /* If enable is true, turn on the sensor's auto brightness control, otherwise | ||
| 1996 | * turn it off. | ||
| 1997 | * | ||
| 1998 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
| 1999 | * Returns: 0 for success | ||
| 2000 | */ | ||
| 2001 | static int | ||
| 2002 | sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) | ||
| 2003 | { | ||
| 2004 | int rc; | ||
| 2005 | |||
| 2006 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
| 2007 | |||
| 2008 | if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B | ||
| 2009 | || ov->sensor == SEN_SAA7111A) { | ||
| 2010 | PDEBUG(5, "Unsupported with this sensor"); | ||
| 2011 | return -EPERM; | ||
| 2012 | } | ||
| 2013 | |||
| 2014 | rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10); | ||
| 2015 | if (rc < 0) | ||
| 2016 | return rc; | ||
| 2017 | |||
| 2018 | ov->auto_brt = enable; | ||
| 2019 | |||
| 2020 | return 0; | ||
| 2021 | } | ||
| 2022 | |||
| 2023 | /* If enable is true, turn on the sensor's auto exposure control, otherwise | ||
| 2024 | * turn it off. | ||
| 2025 | * | ||
| 2026 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
| 2027 | * Returns: 0 for success | ||
| 2028 | */ | ||
| 2029 | static int | ||
| 2030 | sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) | ||
| 2031 | { | ||
| 2032 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
| 2033 | |||
| 2034 | switch (ov->sensor) { | ||
| 2035 | case SEN_OV7610: | ||
| 2036 | i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80); | ||
| 2037 | break; | ||
| 2038 | case SEN_OV6620: | ||
| 2039 | case SEN_OV7620: | ||
| 2040 | case SEN_OV76BE: | ||
| 2041 | case SEN_OV8600: | ||
| 2042 | i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01); | ||
| 2043 | break; | ||
| 2044 | case SEN_OV6630: | ||
| 2045 | i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10); | ||
| 2046 | break; | ||
| 2047 | case SEN_KS0127: | ||
| 2048 | case SEN_KS0127B: | ||
| 2049 | case SEN_SAA7111A: | ||
| 2050 | PDEBUG(5, "Unsupported with this sensor"); | ||
| 2051 | return -EPERM; | ||
| 2052 | default: | ||
| 2053 | err("Sensor not supported for set_auto_exposure"); | ||
| 2054 | return -EINVAL; | ||
| 2055 | } | ||
| 2056 | |||
| 2057 | ov->auto_exp = enable; | ||
| 2058 | |||
| 2059 | return 0; | ||
| 2060 | } | ||
| 2061 | |||
| 2062 | /* Modifies the sensor's exposure algorithm to allow proper exposure of objects | ||
| 2063 | * that are illuminated from behind. | ||
| 2064 | * | ||
| 2065 | * Tested with: OV6620, OV7620 | ||
| 2066 | * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A | ||
| 2067 | * Returns: 0 for success | ||
| 2068 | */ | ||
| 2069 | static int | ||
| 2070 | sensor_set_backlight(struct usb_ov511 *ov, int enable) | ||
| 2071 | { | ||
| 2072 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
| 2073 | |||
| 2074 | switch (ov->sensor) { | ||
| 2075 | case SEN_OV7620: | ||
| 2076 | case SEN_OV8600: | ||
| 2077 | i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); | ||
| 2078 | i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); | ||
| 2079 | i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); | ||
| 2080 | break; | ||
| 2081 | case SEN_OV6620: | ||
| 2082 | i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0); | ||
| 2083 | i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); | ||
| 2084 | i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80); | ||
| 2085 | break; | ||
| 2086 | case SEN_OV6630: | ||
| 2087 | i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0); | ||
| 2088 | i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); | ||
| 2089 | i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); | ||
| 2090 | break; | ||
| 2091 | case SEN_OV7610: | ||
| 2092 | case SEN_OV76BE: | ||
| 2093 | case SEN_KS0127: | ||
| 2094 | case SEN_KS0127B: | ||
| 2095 | case SEN_SAA7111A: | ||
| 2096 | PDEBUG(5, "Unsupported with this sensor"); | ||
| 2097 | return -EPERM; | ||
| 2098 | default: | ||
| 2099 | err("Sensor not supported for set_backlight"); | ||
| 2100 | return -EINVAL; | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | ov->backlight = enable; | ||
| 2104 | |||
| 2105 | return 0; | ||
| 2106 | } | ||
| 2107 | |||
| 2108 | static int | ||
| 2109 | sensor_set_mirror(struct usb_ov511 *ov, int enable) | ||
| 2110 | { | ||
| 2111 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
| 2112 | |||
| 2113 | switch (ov->sensor) { | ||
| 2114 | case SEN_OV6620: | ||
| 2115 | case SEN_OV6630: | ||
| 2116 | case SEN_OV7610: | ||
| 2117 | case SEN_OV7620: | ||
| 2118 | case SEN_OV76BE: | ||
| 2119 | case SEN_OV8600: | ||
| 2120 | i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40); | ||
| 2121 | break; | ||
| 2122 | case SEN_KS0127: | ||
| 2123 | case SEN_KS0127B: | ||
| 2124 | case SEN_SAA7111A: | ||
| 2125 | PDEBUG(5, "Unsupported with this sensor"); | ||
| 2126 | return -EPERM; | ||
| 2127 | default: | ||
| 2128 | err("Sensor not supported for set_mirror"); | ||
| 2129 | return -EINVAL; | ||
| 2130 | } | ||
| 2131 | |||
| 2132 | ov->mirror = enable; | ||
| 2133 | |||
| 2134 | return 0; | ||
| 2135 | } | ||
| 2136 | |||
| 2137 | /* Returns number of bits per pixel (regardless of where they are located; | ||
| 2138 | * planar or not), or zero for unsupported format. | ||
| 2139 | */ | ||
| 2140 | static inline int | ||
| 2141 | get_depth(int palette) | ||
| 2142 | { | ||
| 2143 | switch (palette) { | ||
| 2144 | case VIDEO_PALETTE_GREY: return 8; | ||
| 2145 | case VIDEO_PALETTE_YUV420: return 12; | ||
| 2146 | case VIDEO_PALETTE_YUV420P: return 12; /* Planar */ | ||
| 2147 | default: return 0; /* Invalid format */ | ||
| 2148 | } | ||
| 2149 | } | ||
| 2150 | |||
| 2151 | /* Bytes per frame. Used by read(). Return of 0 indicates error */ | ||
| 2152 | static inline long int | ||
| 2153 | get_frame_length(struct ov511_frame *frame) | ||
| 2154 | { | ||
| 2155 | if (!frame) | ||
| 2156 | return 0; | ||
| 2157 | else | ||
| 2158 | return ((frame->width * frame->height | ||
| 2159 | * get_depth(frame->format)) >> 3); | ||
| 2160 | } | ||
| 2161 | |||
| 2162 | static int | ||
| 2163 | mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, | ||
| 2164 | int mode, int sub_flag, int qvga) | ||
| 2165 | { | ||
| 2166 | int clock; | ||
| 2167 | |||
| 2168 | /******** Mode (VGA/QVGA) and sensor specific regs ********/ | ||
| 2169 | |||
| 2170 | switch (ov->sensor) { | ||
| 2171 | case SEN_OV7610: | ||
| 2172 | i2c_w(ov, 0x14, qvga?0x24:0x04); | ||
| 2173 | // FIXME: Does this improve the image quality or frame rate? | ||
| 2174 | #if 0 | ||
| 2175 | i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); | ||
| 2176 | i2c_w(ov, 0x24, 0x10); | ||
| 2177 | i2c_w(ov, 0x25, qvga?0x40:0x8a); | ||
| 2178 | i2c_w(ov, 0x2f, qvga?0x30:0xb0); | ||
| 2179 | i2c_w(ov, 0x35, qvga?0x1c:0x9c); | ||
| 2180 | #endif | ||
| 2181 | break; | ||
| 2182 | case SEN_OV7620: | ||
| 2183 | // i2c_w(ov, 0x2b, 0x00); | ||
| 2184 | i2c_w(ov, 0x14, qvga?0xa4:0x84); | ||
| 2185 | i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); | ||
| 2186 | i2c_w(ov, 0x24, qvga?0x20:0x3a); | ||
| 2187 | i2c_w(ov, 0x25, qvga?0x30:0x60); | ||
| 2188 | i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); | ||
| 2189 | i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0); | ||
| 2190 | i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); | ||
| 2191 | break; | ||
| 2192 | case SEN_OV76BE: | ||
| 2193 | // i2c_w(ov, 0x2b, 0x00); | ||
| 2194 | i2c_w(ov, 0x14, qvga?0xa4:0x84); | ||
| 2195 | // FIXME: Enable this once 7620AE uses 7620 initial settings | ||
| 2196 | #if 0 | ||
| 2197 | i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); | ||
| 2198 | i2c_w(ov, 0x24, qvga?0x20:0x3a); | ||
| 2199 | i2c_w(ov, 0x25, qvga?0x30:0x60); | ||
| 2200 | i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); | ||
| 2201 | i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0); | ||
| 2202 | i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); | ||
| 2203 | #endif | ||
| 2204 | break; | ||
| 2205 | case SEN_OV6620: | ||
| 2206 | i2c_w(ov, 0x14, qvga?0x24:0x04); | ||
| 2207 | break; | ||
| 2208 | case SEN_OV6630: | ||
| 2209 | i2c_w(ov, 0x14, qvga?0xa0:0x80); | ||
| 2210 | break; | ||
| 2211 | default: | ||
| 2212 | err("Invalid sensor"); | ||
| 2213 | return -EINVAL; | ||
| 2214 | } | ||
| 2215 | |||
| 2216 | /******** Palette-specific regs ********/ | ||
| 2217 | |||
| 2218 | if (mode == VIDEO_PALETTE_GREY) { | ||
| 2219 | if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { | ||
| 2220 | /* these aren't valid on the OV6620/OV7620/6630? */ | ||
| 2221 | i2c_w_mask(ov, 0x0e, 0x40, 0x40); | ||
| 2222 | } | ||
| 2223 | |||
| 2224 | if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 | ||
| 2225 | && ov518_color) { | ||
| 2226 | i2c_w_mask(ov, 0x12, 0x00, 0x10); | ||
| 2227 | i2c_w_mask(ov, 0x13, 0x00, 0x20); | ||
| 2228 | } else { | ||
| 2229 | i2c_w_mask(ov, 0x13, 0x20, 0x20); | ||
| 2230 | } | ||
| 2231 | } else { | ||
| 2232 | if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { | ||
| 2233 | /* not valid on the OV6620/OV7620/6630? */ | ||
| 2234 | i2c_w_mask(ov, 0x0e, 0x00, 0x40); | ||
| 2235 | } | ||
| 2236 | |||
| 2237 | /* The OV518 needs special treatment. Although both the OV518 | ||
| 2238 | * and the OV6630 support a 16-bit video bus, only the 8 bit Y | ||
| 2239 | * bus is actually used. The UV bus is tied to ground. | ||
| 2240 | * Therefore, the OV6630 needs to be in 8-bit multiplexed | ||
| 2241 | * output mode */ | ||
| 2242 | |||
| 2243 | if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 | ||
| 2244 | && ov518_color) { | ||
| 2245 | i2c_w_mask(ov, 0x12, 0x10, 0x10); | ||
| 2246 | i2c_w_mask(ov, 0x13, 0x20, 0x20); | ||
| 2247 | } else { | ||
| 2248 | i2c_w_mask(ov, 0x13, 0x00, 0x20); | ||
| 2249 | } | ||
| 2250 | } | ||
| 2251 | |||
| 2252 | /******** Clock programming ********/ | ||
| 2253 | |||
| 2254 | /* The OV6620 needs special handling. This prevents the | ||
| 2255 | * severe banding that normally occurs */ | ||
| 2256 | if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) | ||
| 2257 | { | ||
| 2258 | /* Clock down */ | ||
| 2259 | |||
| 2260 | i2c_w(ov, 0x2a, 0x04); | ||
| 2261 | |||
| 2262 | if (ov->compress) { | ||
| 2263 | // clock = 0; /* This ensures the highest frame rate */ | ||
| 2264 | clock = 3; | ||
| 2265 | } else if (clockdiv == -1) { /* If user didn't override it */ | ||
| 2266 | clock = 3; /* Gives better exposure time */ | ||
| 2267 | } else { | ||
| 2268 | clock = clockdiv; | ||
| 2269 | } | ||
| 2270 | |||
| 2271 | PDEBUG(4, "Setting clock divisor to %d", clock); | ||
| 2272 | |||
| 2273 | i2c_w(ov, 0x11, clock); | ||
| 2274 | |||
| 2275 | i2c_w(ov, 0x2a, 0x84); | ||
| 2276 | /* This next setting is critical. It seems to improve | ||
| 2277 | * the gain or the contrast. The "reserved" bits seem | ||
| 2278 | * to have some effect in this case. */ | ||
| 2279 | i2c_w(ov, 0x2d, 0x85); | ||
| 2280 | } | ||
| 2281 | else | ||
| 2282 | { | ||
| 2283 | if (ov->compress) { | ||
| 2284 | clock = 1; /* This ensures the highest frame rate */ | ||
| 2285 | } else if (clockdiv == -1) { /* If user didn't override it */ | ||
| 2286 | /* Calculate and set the clock divisor */ | ||
| 2287 | clock = ((sub_flag ? ov->subw * ov->subh | ||
| 2288 | : width * height) | ||
| 2289 | * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2) | ||
| 2290 | / 66000; | ||
| 2291 | } else { | ||
| 2292 | clock = clockdiv; | ||
| 2293 | } | ||
| 2294 | |||
| 2295 | PDEBUG(4, "Setting clock divisor to %d", clock); | ||
| 2296 | |||
| 2297 | i2c_w(ov, 0x11, clock); | ||
| 2298 | } | ||
| 2299 | |||
| 2300 | /******** Special Features ********/ | ||
| 2301 | |||
| 2302 | if (framedrop >= 0) | ||
| 2303 | i2c_w(ov, 0x16, framedrop); | ||
| 2304 | |||
| 2305 | /* Test Pattern */ | ||
| 2306 | i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); | ||
| 2307 | |||
| 2308 | /* Enable auto white balance */ | ||
| 2309 | i2c_w_mask(ov, 0x12, 0x04, 0x04); | ||
| 2310 | |||
| 2311 | // This will go away as soon as ov51x_mode_init_sensor_regs() | ||
| 2312 | // is fully tested. | ||
| 2313 | /* 7620/6620/6630? don't have register 0x35, so play it safe */ | ||
| 2314 | if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { | ||
| 2315 | if (width == 640 && height == 480) | ||
| 2316 | i2c_w(ov, 0x35, 0x9e); | ||
| 2317 | else | ||
| 2318 | i2c_w(ov, 0x35, 0x1e); | ||
| 2319 | } | ||
| 2320 | |||
| 2321 | return 0; | ||
| 2322 | } | ||
| 2323 | |||
| 2324 | static int | ||
| 2325 | set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode, | ||
| 2326 | int sub_flag) | ||
| 2327 | { | ||
| 2328 | int ret; | ||
| 2329 | int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; | ||
| 2330 | int hoffset, voffset, hwscale = 0, vwscale = 0; | ||
| 2331 | |||
| 2332 | /* The different sensor ICs handle setting up of window differently. | ||
| 2333 | * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ | ||
| 2334 | switch (ov->sensor) { | ||
| 2335 | case SEN_OV7610: | ||
| 2336 | case SEN_OV76BE: | ||
| 2337 | hwsbase = 0x38; | ||
| 2338 | hwebase = 0x3a; | ||
| 2339 | vwsbase = vwebase = 0x05; | ||
| 2340 | break; | ||
| 2341 | case SEN_OV6620: | ||
| 2342 | case SEN_OV6630: | ||
| 2343 | hwsbase = 0x38; | ||
| 2344 | hwebase = 0x3a; | ||
| 2345 | vwsbase = 0x05; | ||
| 2346 | vwebase = 0x06; | ||
| 2347 | break; | ||
| 2348 | case SEN_OV7620: | ||
| 2349 | hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ | ||
| 2350 | hwebase = 0x2f; | ||
| 2351 | vwsbase = vwebase = 0x05; | ||
| 2352 | break; | ||
| 2353 | default: | ||
| 2354 | err("Invalid sensor"); | ||
| 2355 | return -EINVAL; | ||
| 2356 | } | ||
| 2357 | |||
| 2358 | if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { | ||
| 2359 | /* Note: OV518(+) does downsample on its own) */ | ||
| 2360 | if ((width > 176 && height > 144) | ||
| 2361 | || ov->bclass == BCL_OV518) { /* CIF */ | ||
| 2362 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
| 2363 | mode, sub_flag, 0); | ||
| 2364 | if (ret < 0) | ||
| 2365 | return ret; | ||
| 2366 | hwscale = 1; | ||
| 2367 | vwscale = 1; /* The datasheet says 0; it's wrong */ | ||
| 2368 | hwsize = 352; | ||
| 2369 | vwsize = 288; | ||
| 2370 | } else if (width > 176 || height > 144) { | ||
| 2371 | err("Illegal dimensions"); | ||
| 2372 | return -EINVAL; | ||
| 2373 | } else { /* QCIF */ | ||
| 2374 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
| 2375 | mode, sub_flag, 1); | ||
| 2376 | if (ret < 0) | ||
| 2377 | return ret; | ||
| 2378 | hwsize = 176; | ||
| 2379 | vwsize = 144; | ||
| 2380 | } | ||
| 2381 | } else { | ||
| 2382 | if (width > 320 && height > 240) { /* VGA */ | ||
| 2383 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
| 2384 | mode, sub_flag, 0); | ||
| 2385 | if (ret < 0) | ||
| 2386 | return ret; | ||
| 2387 | hwscale = 2; | ||
| 2388 | vwscale = 1; | ||
| 2389 | hwsize = 640; | ||
| 2390 | vwsize = 480; | ||
| 2391 | } else if (width > 320 || height > 240) { | ||
| 2392 | err("Illegal dimensions"); | ||
| 2393 | return -EINVAL; | ||
| 2394 | } else { /* QVGA */ | ||
| 2395 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
| 2396 | mode, sub_flag, 1); | ||
| 2397 | if (ret < 0) | ||
| 2398 | return ret; | ||
| 2399 | hwscale = 1; | ||
| 2400 | hwsize = 320; | ||
| 2401 | vwsize = 240; | ||
| 2402 | } | ||
| 2403 | } | ||
| 2404 | |||
| 2405 | /* Center the window */ | ||
| 2406 | hoffset = ((hwsize - width) / 2) >> hwscale; | ||
| 2407 | voffset = ((vwsize - height) / 2) >> vwscale; | ||
| 2408 | |||
| 2409 | /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ | ||
| 2410 | if (sub_flag) { | ||
| 2411 | i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale)); | ||
| 2412 | i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale)); | ||
| 2413 | i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale)); | ||
| 2414 | i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale)); | ||
| 2415 | } else { | ||
| 2416 | i2c_w(ov, 0x17, hwsbase + hoffset); | ||
| 2417 | i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale)); | ||
| 2418 | i2c_w(ov, 0x19, vwsbase + voffset); | ||
| 2419 | i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale)); | ||
| 2420 | } | ||
| 2421 | |||
| 2422 | #ifdef OV511_DEBUG | ||
| 2423 | if (dump_sensor) | ||
| 2424 | dump_i2c_regs(ov); | ||
| 2425 | #endif | ||
| 2426 | |||
| 2427 | return 0; | ||
| 2428 | } | ||
| 2429 | |||
| 2430 | /* Set up the OV511/OV511+ with the given image parameters. | ||
| 2431 | * | ||
| 2432 | * Do not put any sensor-specific code in here (including I2C I/O functions) | ||
| 2433 | */ | ||
| 2434 | static int | ||
| 2435 | ov511_mode_init_regs(struct usb_ov511 *ov, | ||
| 2436 | int width, int height, int mode, int sub_flag) | ||
| 2437 | { | ||
| 2438 | int hsegs, vsegs; | ||
| 2439 | |||
| 2440 | if (sub_flag) { | ||
| 2441 | width = ov->subw; | ||
| 2442 | height = ov->subh; | ||
| 2443 | } | ||
| 2444 | |||
| 2445 | PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", | ||
| 2446 | width, height, mode, sub_flag); | ||
| 2447 | |||
| 2448 | // FIXME: This should be moved to a 7111a-specific function once | ||
| 2449 | // subcapture is dealt with properly | ||
| 2450 | if (ov->sensor == SEN_SAA7111A) { | ||
| 2451 | if (width == 320 && height == 240) { | ||
| 2452 | /* No need to do anything special */ | ||
| 2453 | } else if (width == 640 && height == 480) { | ||
| 2454 | /* Set the OV511 up as 320x480, but keep the | ||
| 2455 | * V4L resolution as 640x480 */ | ||
| 2456 | width = 320; | ||
| 2457 | } else { | ||
| 2458 | err("SAA7111A only allows 320x240 or 640x480"); | ||
| 2459 | return -EINVAL; | ||
| 2460 | } | ||
| 2461 | } | ||
| 2462 | |||
| 2463 | /* Make sure width and height are a multiple of 8 */ | ||
| 2464 | if (width % 8 || height % 8) { | ||
| 2465 | err("Invalid size (%d, %d) (mode = %d)", width, height, mode); | ||
| 2466 | return -EINVAL; | ||
| 2467 | } | ||
| 2468 | |||
| 2469 | if (width < ov->minwidth || height < ov->minheight) { | ||
| 2470 | err("Requested dimensions are too small"); | ||
| 2471 | return -EINVAL; | ||
| 2472 | } | ||
| 2473 | |||
| 2474 | if (ov51x_stop(ov) < 0) | ||
| 2475 | return -EIO; | ||
| 2476 | |||
| 2477 | if (mode == VIDEO_PALETTE_GREY) { | ||
| 2478 | reg_w(ov, R511_CAM_UV_EN, 0x00); | ||
| 2479 | reg_w(ov, R511_SNAP_UV_EN, 0x00); | ||
| 2480 | reg_w(ov, R511_SNAP_OPTS, 0x01); | ||
| 2481 | } else { | ||
| 2482 | reg_w(ov, R511_CAM_UV_EN, 0x01); | ||
| 2483 | reg_w(ov, R511_SNAP_UV_EN, 0x01); | ||
| 2484 | reg_w(ov, R511_SNAP_OPTS, 0x03); | ||
| 2485 | } | ||
| 2486 | |||
| 2487 | /* Here I'm assuming that snapshot size == image size. | ||
| 2488 | * I hope that's always true. --claudio | ||
| 2489 | */ | ||
| 2490 | hsegs = (width >> 3) - 1; | ||
| 2491 | vsegs = (height >> 3) - 1; | ||
| 2492 | |||
| 2493 | reg_w(ov, R511_CAM_PXCNT, hsegs); | ||
| 2494 | reg_w(ov, R511_CAM_LNCNT, vsegs); | ||
| 2495 | reg_w(ov, R511_CAM_PXDIV, 0x00); | ||
| 2496 | reg_w(ov, R511_CAM_LNDIV, 0x00); | ||
| 2497 | |||
| 2498 | /* YUV420, low pass filter on */ | ||
| 2499 | reg_w(ov, R511_CAM_OPTS, 0x03); | ||
| 2500 | |||
| 2501 | /* Snapshot additions */ | ||
| 2502 | reg_w(ov, R511_SNAP_PXCNT, hsegs); | ||
| 2503 | reg_w(ov, R511_SNAP_LNCNT, vsegs); | ||
| 2504 | reg_w(ov, R511_SNAP_PXDIV, 0x00); | ||
| 2505 | reg_w(ov, R511_SNAP_LNDIV, 0x00); | ||
| 2506 | |||
| 2507 | if (ov->compress) { | ||
| 2508 | /* Enable Y and UV quantization and compression */ | ||
| 2509 | reg_w(ov, R511_COMP_EN, 0x07); | ||
| 2510 | reg_w(ov, R511_COMP_LUT_EN, 0x03); | ||
| 2511 | ov51x_reset(ov, OV511_RESET_OMNICE); | ||
| 2512 | } | ||
| 2513 | |||
| 2514 | if (ov51x_restart(ov) < 0) | ||
| 2515 | return -EIO; | ||
| 2516 | |||
| 2517 | return 0; | ||
| 2518 | } | ||
| 2519 | |||
| 2520 | /* Sets up the OV518/OV518+ with the given image parameters | ||
| 2521 | * | ||
| 2522 | * OV518 needs a completely different approach, until we can figure out what | ||
| 2523 | * the individual registers do. Also, only 15 FPS is supported now. | ||
| 2524 | * | ||
| 2525 | * Do not put any sensor-specific code in here (including I2C I/O functions) | ||
| 2526 | */ | ||
| 2527 | static int | ||
| 2528 | ov518_mode_init_regs(struct usb_ov511 *ov, | ||
| 2529 | int width, int height, int mode, int sub_flag) | ||
| 2530 | { | ||
| 2531 | int hsegs, vsegs, hi_res; | ||
| 2532 | |||
| 2533 | if (sub_flag) { | ||
| 2534 | width = ov->subw; | ||
| 2535 | height = ov->subh; | ||
| 2536 | } | ||
| 2537 | |||
| 2538 | PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", | ||
| 2539 | width, height, mode, sub_flag); | ||
| 2540 | |||
| 2541 | if (width % 16 || height % 8) { | ||
| 2542 | err("Invalid size (%d, %d)", width, height); | ||
| 2543 | return -EINVAL; | ||
| 2544 | } | ||
| 2545 | |||
| 2546 | if (width < ov->minwidth || height < ov->minheight) { | ||
| 2547 | err("Requested dimensions are too small"); | ||
| 2548 | return -EINVAL; | ||
| 2549 | } | ||
| 2550 | |||
| 2551 | if (width >= 320 && height >= 240) { | ||
| 2552 | hi_res = 1; | ||
| 2553 | } else if (width >= 320 || height >= 240) { | ||
| 2554 | err("Invalid width/height combination (%d, %d)", width, height); | ||
| 2555 | return -EINVAL; | ||
| 2556 | } else { | ||
| 2557 | hi_res = 0; | ||
| 2558 | } | ||
| 2559 | |||
| 2560 | if (ov51x_stop(ov) < 0) | ||
| 2561 | return -EIO; | ||
| 2562 | |||
| 2563 | /******** Set the mode ********/ | ||
| 2564 | |||
| 2565 | reg_w(ov, 0x2b, 0); | ||
| 2566 | reg_w(ov, 0x2c, 0); | ||
| 2567 | reg_w(ov, 0x2d, 0); | ||
| 2568 | reg_w(ov, 0x2e, 0); | ||
| 2569 | reg_w(ov, 0x3b, 0); | ||
| 2570 | reg_w(ov, 0x3c, 0); | ||
| 2571 | reg_w(ov, 0x3d, 0); | ||
| 2572 | reg_w(ov, 0x3e, 0); | ||
| 2573 | |||
| 2574 | if (ov->bridge == BRG_OV518 && ov518_color) { | ||
| 2575 | /* OV518 needs U and V swapped */ | ||
| 2576 | i2c_w_mask(ov, 0x15, 0x00, 0x01); | ||
| 2577 | |||
| 2578 | if (mode == VIDEO_PALETTE_GREY) { | ||
| 2579 | /* Set 16-bit input format (UV data are ignored) */ | ||
| 2580 | reg_w_mask(ov, 0x20, 0x00, 0x08); | ||
| 2581 | |||
| 2582 | /* Set 8-bit (4:0:0) output format */ | ||
| 2583 | reg_w_mask(ov, 0x28, 0x00, 0xf0); | ||
| 2584 | reg_w_mask(ov, 0x38, 0x00, 0xf0); | ||
| 2585 | } else { | ||
| 2586 | /* Set 8-bit (YVYU) input format */ | ||
| 2587 | reg_w_mask(ov, 0x20, 0x08, 0x08); | ||
| 2588 | |||
| 2589 | /* Set 12-bit (4:2:0) output format */ | ||
| 2590 | reg_w_mask(ov, 0x28, 0x80, 0xf0); | ||
| 2591 | reg_w_mask(ov, 0x38, 0x80, 0xf0); | ||
| 2592 | } | ||
| 2593 | } else { | ||
| 2594 | reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); | ||
| 2595 | reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); | ||
| 2596 | } | ||
| 2597 | |||
| 2598 | hsegs = width / 16; | ||
| 2599 | vsegs = height / 4; | ||
| 2600 | |||
| 2601 | reg_w(ov, 0x29, hsegs); | ||
| 2602 | reg_w(ov, 0x2a, vsegs); | ||
| 2603 | |||
| 2604 | reg_w(ov, 0x39, hsegs); | ||
| 2605 | reg_w(ov, 0x3a, vsegs); | ||
| 2606 | |||
| 2607 | /* Windows driver does this here; who knows why */ | ||
| 2608 | reg_w(ov, 0x2f, 0x80); | ||
| 2609 | |||
| 2610 | /******** Set the framerate (to 15 FPS) ********/ | ||
| 2611 | |||
| 2612 | /* Mode independent, but framerate dependent, regs */ | ||
| 2613 | reg_w(ov, 0x51, 0x02); /* Clock divider; lower==faster */ | ||
| 2614 | reg_w(ov, 0x22, 0x18); | ||
| 2615 | reg_w(ov, 0x23, 0xff); | ||
| 2616 | |||
| 2617 | if (ov->bridge == BRG_OV518PLUS) | ||
| 2618 | reg_w(ov, 0x21, 0x19); | ||
| 2619 | else | ||
| 2620 | reg_w(ov, 0x71, 0x19); /* Compression-related? */ | ||
| 2621 | |||
| 2622 | // FIXME: Sensor-specific | ||
| 2623 | /* Bit 5 is what matters here. Of course, it is "reserved" */ | ||
| 2624 | i2c_w(ov, 0x54, 0x23); | ||
| 2625 | |||
| 2626 | reg_w(ov, 0x2f, 0x80); | ||
| 2627 | |||
| 2628 | if (ov->bridge == BRG_OV518PLUS) { | ||
| 2629 | reg_w(ov, 0x24, 0x94); | ||
| 2630 | reg_w(ov, 0x25, 0x90); | ||
| 2631 | ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ | ||
| 2632 | ov518_reg_w32(ov, 0xc6, 540, 2); /* 21ch */ | ||
| 2633 | ov518_reg_w32(ov, 0xc7, 540, 2); /* 21ch */ | ||
| 2634 | ov518_reg_w32(ov, 0xc8, 108, 2); /* 6ch */ | ||
| 2635 | ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ | ||
| 2636 | ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ | ||
| 2637 | ov518_reg_w32(ov, 0xcc, 2400, 2); /* 960h */ | ||
| 2638 | ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ | ||
| 2639 | ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ | ||
| 2640 | } else { | ||
| 2641 | reg_w(ov, 0x24, 0x9f); | ||
| 2642 | reg_w(ov, 0x25, 0x90); | ||
| 2643 | ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ | ||
| 2644 | ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */ | ||
| 2645 | ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */ | ||
| 2646 | ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */ | ||
| 2647 | ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ | ||
| 2648 | ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ | ||
| 2649 | ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */ | ||
| 2650 | ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ | ||
| 2651 | ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ | ||
| 2652 | } | ||
| 2653 | |||
| 2654 | reg_w(ov, 0x2f, 0x80); | ||
| 2655 | |||
| 2656 | if (ov51x_restart(ov) < 0) | ||
| 2657 | return -EIO; | ||
| 2658 | |||
| 2659 | /* Reset it just for good measure */ | ||
| 2660 | if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) | ||
| 2661 | return -EIO; | ||
| 2662 | |||
| 2663 | return 0; | ||
| 2664 | } | ||
| 2665 | |||
| 2666 | /* This is a wrapper around the OV511, OV518, and sensor specific functions */ | ||
| 2667 | static int | ||
| 2668 | mode_init_regs(struct usb_ov511 *ov, | ||
| 2669 | int width, int height, int mode, int sub_flag) | ||
| 2670 | { | ||
| 2671 | int rc = 0; | ||
| 2672 | |||
| 2673 | if (!ov || !ov->dev) | ||
| 2674 | return -EFAULT; | ||
| 2675 | |||
| 2676 | if (ov->bclass == BCL_OV518) { | ||
| 2677 | rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag); | ||
| 2678 | } else { | ||
| 2679 | rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag); | ||
| 2680 | } | ||
| 2681 | |||
| 2682 | if (FATAL_ERROR(rc)) | ||
| 2683 | return rc; | ||
| 2684 | |||
| 2685 | switch (ov->sensor) { | ||
| 2686 | case SEN_OV7610: | ||
| 2687 | case SEN_OV7620: | ||
| 2688 | case SEN_OV76BE: | ||
| 2689 | case SEN_OV8600: | ||
| 2690 | case SEN_OV6620: | ||
| 2691 | case SEN_OV6630: | ||
| 2692 | rc = set_ov_sensor_window(ov, width, height, mode, sub_flag); | ||
| 2693 | break; | ||
| 2694 | case SEN_KS0127: | ||
| 2695 | case SEN_KS0127B: | ||
| 2696 | err("KS0127-series decoders not supported yet"); | ||
| 2697 | rc = -EINVAL; | ||
| 2698 | break; | ||
| 2699 | case SEN_SAA7111A: | ||
| 2700 | // rc = mode_init_saa_sensor_regs(ov, width, height, mode, | ||
| 2701 | // sub_flag); | ||
| 2702 | |||
| 2703 | PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f)); | ||
| 2704 | break; | ||
| 2705 | default: | ||
| 2706 | err("Unknown sensor"); | ||
| 2707 | rc = -EINVAL; | ||
| 2708 | } | ||
| 2709 | |||
| 2710 | if (FATAL_ERROR(rc)) | ||
| 2711 | return rc; | ||
| 2712 | |||
| 2713 | /* Sensor-independent settings */ | ||
| 2714 | rc = sensor_set_auto_brightness(ov, ov->auto_brt); | ||
| 2715 | if (FATAL_ERROR(rc)) | ||
| 2716 | return rc; | ||
| 2717 | |||
| 2718 | rc = sensor_set_auto_exposure(ov, ov->auto_exp); | ||
| 2719 | if (FATAL_ERROR(rc)) | ||
| 2720 | return rc; | ||
| 2721 | |||
| 2722 | rc = sensor_set_banding_filter(ov, bandingfilter); | ||
| 2723 | if (FATAL_ERROR(rc)) | ||
| 2724 | return rc; | ||
| 2725 | |||
| 2726 | if (ov->lightfreq) { | ||
| 2727 | rc = sensor_set_light_freq(ov, lightfreq); | ||
| 2728 | if (FATAL_ERROR(rc)) | ||
| 2729 | return rc; | ||
| 2730 | } | ||
| 2731 | |||
| 2732 | rc = sensor_set_backlight(ov, ov->backlight); | ||
| 2733 | if (FATAL_ERROR(rc)) | ||
| 2734 | return rc; | ||
| 2735 | |||
| 2736 | rc = sensor_set_mirror(ov, ov->mirror); | ||
| 2737 | if (FATAL_ERROR(rc)) | ||
| 2738 | return rc; | ||
| 2739 | |||
| 2740 | return 0; | ||
| 2741 | } | ||
| 2742 | |||
| 2743 | /* This sets the default image parameters. This is useful for apps that use | ||
| 2744 | * read() and do not set these. | ||
| 2745 | */ | ||
| 2746 | static int | ||
| 2747 | ov51x_set_default_params(struct usb_ov511 *ov) | ||
| 2748 | { | ||
| 2749 | int i; | ||
| 2750 | |||
| 2751 | /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used | ||
| 2752 | * (using read() instead). */ | ||
| 2753 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
| 2754 | ov->frame[i].width = ov->maxwidth; | ||
| 2755 | ov->frame[i].height = ov->maxheight; | ||
| 2756 | ov->frame[i].bytes_read = 0; | ||
| 2757 | if (force_palette) | ||
| 2758 | ov->frame[i].format = force_palette; | ||
| 2759 | else | ||
| 2760 | ov->frame[i].format = VIDEO_PALETTE_YUV420; | ||
| 2761 | |||
| 2762 | ov->frame[i].depth = get_depth(ov->frame[i].format); | ||
| 2763 | } | ||
| 2764 | |||
| 2765 | PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight, | ||
| 2766 | symbolic(v4l1_plist, ov->frame[0].format)); | ||
| 2767 | |||
| 2768 | /* Initialize to max width/height, YUV420 or RGB24 (if supported) */ | ||
| 2769 | if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, | ||
| 2770 | ov->frame[0].format, 0) < 0) | ||
| 2771 | return -EINVAL; | ||
| 2772 | |||
| 2773 | return 0; | ||
| 2774 | } | ||
| 2775 | |||
| 2776 | /********************************************************************** | ||
| 2777 | * | ||
| 2778 | * Video decoder stuff | ||
| 2779 | * | ||
| 2780 | **********************************************************************/ | ||
| 2781 | |||
| 2782 | /* Set analog input port of decoder */ | ||
| 2783 | static int | ||
| 2784 | decoder_set_input(struct usb_ov511 *ov, int input) | ||
| 2785 | { | ||
| 2786 | PDEBUG(4, "port %d", input); | ||
| 2787 | |||
| 2788 | switch (ov->sensor) { | ||
| 2789 | case SEN_SAA7111A: | ||
| 2790 | { | ||
| 2791 | /* Select mode */ | ||
| 2792 | i2c_w_mask(ov, 0x02, input, 0x07); | ||
| 2793 | /* Bypass chrominance trap for modes 4..7 */ | ||
| 2794 | i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80); | ||
| 2795 | break; | ||
| 2796 | } | ||
| 2797 | default: | ||
| 2798 | return -EINVAL; | ||
| 2799 | } | ||
| 2800 | |||
| 2801 | return 0; | ||
| 2802 | } | ||
| 2803 | |||
| 2804 | /* Get ASCII name of video input */ | ||
| 2805 | static int | ||
| 2806 | decoder_get_input_name(struct usb_ov511 *ov, int input, char *name) | ||
| 2807 | { | ||
| 2808 | switch (ov->sensor) { | ||
| 2809 | case SEN_SAA7111A: | ||
| 2810 | { | ||
| 2811 | if (input < 0 || input > 7) | ||
| 2812 | return -EINVAL; | ||
| 2813 | else if (input < 4) | ||
| 2814 | sprintf(name, "CVBS-%d", input); | ||
| 2815 | else // if (input < 8) | ||
| 2816 | sprintf(name, "S-Video-%d", input - 4); | ||
| 2817 | break; | ||
| 2818 | } | ||
| 2819 | default: | ||
| 2820 | sprintf(name, "%s", "Camera"); | ||
| 2821 | } | ||
| 2822 | |||
| 2823 | return 0; | ||
| 2824 | } | ||
| 2825 | |||
| 2826 | /* Set norm (NTSC, PAL, SECAM, AUTO) */ | ||
| 2827 | static int | ||
| 2828 | decoder_set_norm(struct usb_ov511 *ov, int norm) | ||
| 2829 | { | ||
| 2830 | PDEBUG(4, "%d", norm); | ||
| 2831 | |||
| 2832 | switch (ov->sensor) { | ||
| 2833 | case SEN_SAA7111A: | ||
| 2834 | { | ||
| 2835 | int reg_8, reg_e; | ||
| 2836 | |||
| 2837 | if (norm == VIDEO_MODE_NTSC) { | ||
| 2838 | reg_8 = 0x40; /* 60 Hz */ | ||
| 2839 | reg_e = 0x00; /* NTSC M / PAL BGHI */ | ||
| 2840 | } else if (norm == VIDEO_MODE_PAL) { | ||
| 2841 | reg_8 = 0x00; /* 50 Hz */ | ||
| 2842 | reg_e = 0x00; /* NTSC M / PAL BGHI */ | ||
| 2843 | } else if (norm == VIDEO_MODE_AUTO) { | ||
| 2844 | reg_8 = 0x80; /* Auto field detect */ | ||
| 2845 | reg_e = 0x00; /* NTSC M / PAL BGHI */ | ||
| 2846 | } else if (norm == VIDEO_MODE_SECAM) { | ||
| 2847 | reg_8 = 0x00; /* 50 Hz */ | ||
| 2848 | reg_e = 0x50; /* SECAM / PAL 4.43 */ | ||
| 2849 | } else { | ||
| 2850 | return -EINVAL; | ||
| 2851 | } | ||
| 2852 | |||
| 2853 | i2c_w_mask(ov, 0x08, reg_8, 0xc0); | ||
| 2854 | i2c_w_mask(ov, 0x0e, reg_e, 0x70); | ||
| 2855 | break; | ||
| 2856 | } | ||
| 2857 | default: | ||
| 2858 | return -EINVAL; | ||
| 2859 | } | ||
| 2860 | |||
| 2861 | return 0; | ||
| 2862 | } | ||
| 2863 | |||
| 2864 | /********************************************************************** | ||
| 2865 | * | ||
| 2866 | * Raw data parsing | ||
| 2867 | * | ||
| 2868 | **********************************************************************/ | ||
| 2869 | |||
| 2870 | /* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the | ||
| 2871 | * image at pOut is specified by w. | ||
| 2872 | */ | ||
| 2873 | static inline void | ||
| 2874 | make_8x8(unsigned char *pIn, unsigned char *pOut, int w) | ||
| 2875 | { | ||
| 2876 | unsigned char *pOut1 = pOut; | ||
| 2877 | int x, y; | ||
| 2878 | |||
| 2879 | for (y = 0; y < 8; y++) { | ||
| 2880 | pOut1 = pOut; | ||
| 2881 | for (x = 0; x < 8; x++) { | ||
| 2882 | *pOut1++ = *pIn++; | ||
| 2883 | } | ||
| 2884 | pOut += w; | ||
| 2885 | } | ||
| 2886 | } | ||
| 2887 | |||
| 2888 | /* | ||
| 2889 | * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments. | ||
| 2890 | * The segments represent 4 squares of 8x8 pixels as follows: | ||
| 2891 | * | ||
| 2892 | * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 | ||
| 2893 | * 8 9 ... 15 72 73 ... 79 200 201 ... 207 | ||
| 2894 | * ... ... ... | ||
| 2895 | * 56 57 ... 63 120 121 ... 127 248 249 ... 255 | ||
| 2896 | * | ||
| 2897 | */ | ||
| 2898 | static void | ||
| 2899 | yuv400raw_to_yuv400p(struct ov511_frame *frame, | ||
| 2900 | unsigned char *pIn0, unsigned char *pOut0) | ||
| 2901 | { | ||
| 2902 | int x, y; | ||
| 2903 | unsigned char *pIn, *pOut, *pOutLine; | ||
| 2904 | |||
| 2905 | /* Copy Y */ | ||
| 2906 | pIn = pIn0; | ||
| 2907 | pOutLine = pOut0; | ||
| 2908 | for (y = 0; y < frame->rawheight - 1; y += 8) { | ||
| 2909 | pOut = pOutLine; | ||
| 2910 | for (x = 0; x < frame->rawwidth - 1; x += 8) { | ||
| 2911 | make_8x8(pIn, pOut, frame->rawwidth); | ||
| 2912 | pIn += 64; | ||
| 2913 | pOut += 8; | ||
| 2914 | } | ||
| 2915 | pOutLine += 8 * frame->rawwidth; | ||
| 2916 | } | ||
| 2917 | } | ||
| 2918 | |||
| 2919 | /* | ||
| 2920 | * For YUV 4:2:0 images, the data show up in 384 byte segments. | ||
| 2921 | * The first 64 bytes of each segment are U, the next 64 are V. The U and | ||
| 2922 | * V are arranged as follows: | ||
| 2923 | * | ||
| 2924 | * 0 1 ... 7 | ||
| 2925 | * 8 9 ... 15 | ||
| 2926 | * ... | ||
| 2927 | * 56 57 ... 63 | ||
| 2928 | * | ||
| 2929 | * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block). | ||
| 2930 | * | ||
| 2931 | * The next 256 bytes are full resolution Y data and represent 4 squares | ||
| 2932 | * of 8x8 pixels as follows: | ||
| 2933 | * | ||
| 2934 | * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 | ||
| 2935 | * 8 9 ... 15 72 73 ... 79 200 201 ... 207 | ||
| 2936 | * ... ... ... | ||
| 2937 | * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 | ||
| 2938 | * | ||
| 2939 | * Note that the U and V data in one segment represent a 16 x 16 pixel | ||
| 2940 | * area, but the Y data represent a 32 x 8 pixel area. If the width is not an | ||
| 2941 | * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the | ||
| 2942 | * next horizontal stripe. | ||
| 2943 | * | ||
| 2944 | * If dumppix module param is set, _parse_data just dumps the incoming segments, | ||
| 2945 | * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 | ||
| 2946 | * this puts the data on the standard output and can be analyzed with the | ||
| 2947 | * parseppm.c utility I wrote. That's a much faster way for figuring out how | ||
| 2948 | * these data are scrambled. | ||
| 2949 | */ | ||
| 2950 | |||
| 2951 | /* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. | ||
| 2952 | * | ||
| 2953 | * FIXME: Currently only handles width and height that are multiples of 16 | ||
| 2954 | */ | ||
| 2955 | static void | ||
| 2956 | yuv420raw_to_yuv420p(struct ov511_frame *frame, | ||
| 2957 | unsigned char *pIn0, unsigned char *pOut0) | ||
| 2958 | { | ||
| 2959 | int k, x, y; | ||
| 2960 | unsigned char *pIn, *pOut, *pOutLine; | ||
| 2961 | const unsigned int a = frame->rawwidth * frame->rawheight; | ||
| 2962 | const unsigned int w = frame->rawwidth / 2; | ||
| 2963 | |||
| 2964 | /* Copy U and V */ | ||
| 2965 | pIn = pIn0; | ||
| 2966 | pOutLine = pOut0 + a; | ||
| 2967 | for (y = 0; y < frame->rawheight - 1; y += 16) { | ||
| 2968 | pOut = pOutLine; | ||
| 2969 | for (x = 0; x < frame->rawwidth - 1; x += 16) { | ||
| 2970 | make_8x8(pIn, pOut, w); | ||
| 2971 | make_8x8(pIn + 64, pOut + a/4, w); | ||
| 2972 | pIn += 384; | ||
| 2973 | pOut += 8; | ||
| 2974 | } | ||
| 2975 | pOutLine += 8 * w; | ||
| 2976 | } | ||
| 2977 | |||
| 2978 | /* Copy Y */ | ||
| 2979 | pIn = pIn0 + 128; | ||
| 2980 | pOutLine = pOut0; | ||
| 2981 | k = 0; | ||
| 2982 | for (y = 0; y < frame->rawheight - 1; y += 8) { | ||
| 2983 | pOut = pOutLine; | ||
| 2984 | for (x = 0; x < frame->rawwidth - 1; x += 8) { | ||
| 2985 | make_8x8(pIn, pOut, frame->rawwidth); | ||
| 2986 | pIn += 64; | ||
| 2987 | pOut += 8; | ||
| 2988 | if ((++k) > 3) { | ||
| 2989 | k = 0; | ||
| 2990 | pIn += 128; | ||
| 2991 | } | ||
| 2992 | } | ||
| 2993 | pOutLine += 8 * frame->rawwidth; | ||
| 2994 | } | ||
| 2995 | } | ||
| 2996 | |||
| 2997 | /********************************************************************** | ||
| 2998 | * | ||
| 2999 | * Decompression | ||
| 3000 | * | ||
| 3001 | **********************************************************************/ | ||
| 3002 | |||
| 3003 | static int | ||
| 3004 | request_decompressor(struct usb_ov511 *ov) | ||
| 3005 | { | ||
| 3006 | if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) { | ||
| 3007 | err("No decompressor available"); | ||
| 3008 | } else { | ||
| 3009 | err("Unknown bridge"); | ||
| 3010 | } | ||
| 3011 | |||
| 3012 | return -ENOSYS; | ||
| 3013 | } | ||
| 3014 | |||
| 3015 | static void | ||
| 3016 | decompress(struct usb_ov511 *ov, struct ov511_frame *frame, | ||
| 3017 | unsigned char *pIn0, unsigned char *pOut0) | ||
| 3018 | { | ||
| 3019 | if (!ov->decomp_ops) | ||
| 3020 | if (request_decompressor(ov)) | ||
| 3021 | return; | ||
| 3022 | |||
| 3023 | } | ||
| 3024 | |||
| 3025 | /********************************************************************** | ||
| 3026 | * | ||
| 3027 | * Format conversion | ||
| 3028 | * | ||
| 3029 | **********************************************************************/ | ||
| 3030 | |||
| 3031 | /* Fuses even and odd fields together, and doubles width. | ||
| 3032 | * INPUT: an odd field followed by an even field at pIn0, in YUV planar format | ||
| 3033 | * OUTPUT: a normal YUV planar image, with correct aspect ratio | ||
| 3034 | */ | ||
| 3035 | static void | ||
| 3036 | deinterlace(struct ov511_frame *frame, int rawformat, | ||
| 3037 | unsigned char *pIn0, unsigned char *pOut0) | ||
| 3038 | { | ||
| 3039 | const int fieldheight = frame->rawheight / 2; | ||
| 3040 | const int fieldpix = fieldheight * frame->rawwidth; | ||
| 3041 | const int w = frame->width; | ||
| 3042 | int x, y; | ||
| 3043 | unsigned char *pInEven, *pInOdd, *pOut; | ||
| 3044 | |||
| 3045 | PDEBUG(5, "fieldheight=%d", fieldheight); | ||
| 3046 | |||
| 3047 | if (frame->rawheight != frame->height) { | ||
| 3048 | err("invalid height"); | ||
| 3049 | return; | ||
| 3050 | } | ||
| 3051 | |||
| 3052 | if ((frame->rawwidth * 2) != frame->width) { | ||
| 3053 | err("invalid width"); | ||
| 3054 | return; | ||
| 3055 | } | ||
| 3056 | |||
| 3057 | /* Y */ | ||
| 3058 | pInOdd = pIn0; | ||
| 3059 | pInEven = pInOdd + fieldpix; | ||
| 3060 | pOut = pOut0; | ||
| 3061 | for (y = 0; y < fieldheight; y++) { | ||
| 3062 | for (x = 0; x < frame->rawwidth; x++) { | ||
| 3063 | *pOut = *pInEven; | ||
| 3064 | *(pOut+1) = *pInEven++; | ||
| 3065 | *(pOut+w) = *pInOdd; | ||
| 3066 | *(pOut+w+1) = *pInOdd++; | ||
| 3067 | pOut += 2; | ||
| 3068 | } | ||
| 3069 | pOut += w; | ||
| 3070 | } | ||
| 3071 | |||
| 3072 | if (rawformat == RAWFMT_YUV420) { | ||
| 3073 | /* U */ | ||
| 3074 | pInOdd = pIn0 + fieldpix * 2; | ||
| 3075 | pInEven = pInOdd + fieldpix / 4; | ||
| 3076 | for (y = 0; y < fieldheight / 2; y++) { | ||
| 3077 | for (x = 0; x < frame->rawwidth / 2; x++) { | ||
| 3078 | *pOut = *pInEven; | ||
| 3079 | *(pOut+1) = *pInEven++; | ||
| 3080 | *(pOut+w/2) = *pInOdd; | ||
| 3081 | *(pOut+w/2+1) = *pInOdd++; | ||
| 3082 | pOut += 2; | ||
| 3083 | } | ||
| 3084 | pOut += w/2; | ||
| 3085 | } | ||
| 3086 | /* V */ | ||
| 3087 | pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2; | ||
| 3088 | pInEven = pInOdd + fieldpix / 4; | ||
| 3089 | for (y = 0; y < fieldheight / 2; y++) { | ||
| 3090 | for (x = 0; x < frame->rawwidth / 2; x++) { | ||
| 3091 | *pOut = *pInEven; | ||
| 3092 | *(pOut+1) = *pInEven++; | ||
| 3093 | *(pOut+w/2) = *pInOdd; | ||
| 3094 | *(pOut+w/2+1) = *pInOdd++; | ||
| 3095 | pOut += 2; | ||
| 3096 | } | ||
| 3097 | pOut += w/2; | ||
| 3098 | } | ||
| 3099 | } | ||
| 3100 | } | ||
| 3101 | |||
| 3102 | static void | ||
| 3103 | ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame) | ||
| 3104 | { | ||
| 3105 | /* Deinterlace frame, if necessary */ | ||
| 3106 | if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { | ||
| 3107 | if (frame->compressed) | ||
| 3108 | decompress(ov, frame, frame->rawdata, | ||
| 3109 | frame->tempdata); | ||
| 3110 | else | ||
| 3111 | yuv400raw_to_yuv400p(frame, frame->rawdata, | ||
| 3112 | frame->tempdata); | ||
| 3113 | |||
| 3114 | deinterlace(frame, RAWFMT_YUV400, frame->tempdata, | ||
| 3115 | frame->data); | ||
| 3116 | } else { | ||
| 3117 | if (frame->compressed) | ||
| 3118 | decompress(ov, frame, frame->rawdata, | ||
| 3119 | frame->data); | ||
| 3120 | else | ||
| 3121 | yuv400raw_to_yuv400p(frame, frame->rawdata, | ||
| 3122 | frame->data); | ||
| 3123 | } | ||
| 3124 | } | ||
| 3125 | |||
| 3126 | /* Process raw YUV420 data into standard YUV420P */ | ||
| 3127 | static void | ||
| 3128 | ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame) | ||
| 3129 | { | ||
| 3130 | /* Deinterlace frame, if necessary */ | ||
| 3131 | if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { | ||
| 3132 | if (frame->compressed) | ||
| 3133 | decompress(ov, frame, frame->rawdata, frame->tempdata); | ||
| 3134 | else | ||
| 3135 | yuv420raw_to_yuv420p(frame, frame->rawdata, | ||
| 3136 | frame->tempdata); | ||
| 3137 | |||
| 3138 | deinterlace(frame, RAWFMT_YUV420, frame->tempdata, | ||
| 3139 | frame->data); | ||
| 3140 | } else { | ||
| 3141 | if (frame->compressed) | ||
| 3142 | decompress(ov, frame, frame->rawdata, frame->data); | ||
| 3143 | else | ||
| 3144 | yuv420raw_to_yuv420p(frame, frame->rawdata, | ||
| 3145 | frame->data); | ||
| 3146 | } | ||
| 3147 | } | ||
| 3148 | |||
| 3149 | /* Post-processes the specified frame. This consists of: | ||
| 3150 | * 1. Decompress frame, if necessary | ||
| 3151 | * 2. Deinterlace frame and scale to proper size, if necessary | ||
| 3152 | * 3. Convert from YUV planar to destination format, if necessary | ||
| 3153 | * 4. Fix the RGB offset, if necessary | ||
| 3154 | */ | ||
| 3155 | static void | ||
| 3156 | ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) | ||
| 3157 | { | ||
| 3158 | if (dumppix) { | ||
| 3159 | memset(frame->data, 0, | ||
| 3160 | MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); | ||
| 3161 | PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); | ||
| 3162 | memcpy(frame->data, frame->rawdata, frame->bytes_recvd); | ||
| 3163 | } else { | ||
| 3164 | switch (frame->format) { | ||
| 3165 | case VIDEO_PALETTE_GREY: | ||
| 3166 | ov51x_postprocess_grey(ov, frame); | ||
| 3167 | break; | ||
| 3168 | case VIDEO_PALETTE_YUV420: | ||
| 3169 | case VIDEO_PALETTE_YUV420P: | ||
| 3170 | ov51x_postprocess_yuv420(ov, frame); | ||
| 3171 | break; | ||
| 3172 | default: | ||
| 3173 | err("Cannot convert data to %s", | ||
| 3174 | symbolic(v4l1_plist, frame->format)); | ||
| 3175 | } | ||
| 3176 | } | ||
| 3177 | } | ||
| 3178 | |||
| 3179 | /********************************************************************** | ||
| 3180 | * | ||
| 3181 | * OV51x data transfer, IRQ handler | ||
| 3182 | * | ||
| 3183 | **********************************************************************/ | ||
| 3184 | |||
| 3185 | static inline void | ||
| 3186 | ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n) | ||
| 3187 | { | ||
| 3188 | int num, offset; | ||
| 3189 | int pnum = in[ov->packet_size - 1]; /* Get packet number */ | ||
| 3190 | int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
| 3191 | struct ov511_frame *frame = &ov->frame[ov->curframe]; | ||
| 3192 | struct timeval *ts; | ||
| 3193 | |||
| 3194 | /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th | ||
| 3195 | * byte non-zero. The EOF packet has image width/height in the | ||
| 3196 | * 10th and 11th bytes. The 9th byte is given as follows: | ||
| 3197 | * | ||
| 3198 | * bit 7: EOF | ||
| 3199 | * 6: compression enabled | ||
| 3200 | * 5: 422/420/400 modes | ||
| 3201 | * 4: 422/420/400 modes | ||
| 3202 | * 3: 1 | ||
| 3203 | * 2: snapshot button on | ||
| 3204 | * 1: snapshot frame | ||
| 3205 | * 0: even/odd field | ||
| 3206 | */ | ||
| 3207 | |||
| 3208 | if (printph) { | ||
| 3209 | info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", | ||
| 3210 | pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6], | ||
| 3211 | in[7], in[8], in[9], in[10], in[11]); | ||
| 3212 | } | ||
| 3213 | |||
| 3214 | /* Check for SOF/EOF packet */ | ||
| 3215 | if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) || | ||
| 3216 | (~in[8] & 0x08)) | ||
| 3217 | goto check_middle; | ||
| 3218 | |||
| 3219 | /* Frame end */ | ||
| 3220 | if (in[8] & 0x80) { | ||
| 3221 | ts = (struct timeval *)(frame->data | ||
| 3222 | + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); | ||
| 3223 | do_gettimeofday(ts); | ||
| 3224 | |||
| 3225 | /* Get the actual frame size from the EOF header */ | ||
| 3226 | frame->rawwidth = ((int)(in[9]) + 1) * 8; | ||
| 3227 | frame->rawheight = ((int)(in[10]) + 1) * 8; | ||
| 3228 | |||
| 3229 | PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d", | ||
| 3230 | ov->curframe, pnum, frame->rawwidth, frame->rawheight, | ||
| 3231 | frame->bytes_recvd); | ||
| 3232 | |||
| 3233 | /* Validate the header data */ | ||
| 3234 | RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); | ||
| 3235 | RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, | ||
| 3236 | ov->maxheight); | ||
| 3237 | |||
| 3238 | /* Don't allow byte count to exceed buffer size */ | ||
| 3239 | RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); | ||
| 3240 | |||
| 3241 | if (frame->scanstate == STATE_LINES) { | ||
| 3242 | int nextf; | ||
| 3243 | |||
| 3244 | frame->grabstate = FRAME_DONE; | ||
| 3245 | wake_up_interruptible(&frame->wq); | ||
| 3246 | |||
| 3247 | /* If next frame is ready or grabbing, | ||
| 3248 | * point to it */ | ||
| 3249 | nextf = (ov->curframe + 1) % OV511_NUMFRAMES; | ||
| 3250 | if (ov->frame[nextf].grabstate == FRAME_READY | ||
| 3251 | || ov->frame[nextf].grabstate == FRAME_GRABBING) { | ||
| 3252 | ov->curframe = nextf; | ||
| 3253 | ov->frame[nextf].scanstate = STATE_SCANNING; | ||
| 3254 | } else { | ||
| 3255 | if (frame->grabstate == FRAME_DONE) { | ||
| 3256 | PDEBUG(4, "** Frame done **"); | ||
| 3257 | } else { | ||
| 3258 | PDEBUG(4, "Frame not ready? state = %d", | ||
| 3259 | ov->frame[nextf].grabstate); | ||
| 3260 | } | ||
| 3261 | |||
| 3262 | ov->curframe = -1; | ||
| 3263 | } | ||
| 3264 | } else { | ||
| 3265 | PDEBUG(5, "Frame done, but not scanning"); | ||
| 3266 | } | ||
| 3267 | /* Image corruption caused by misplaced frame->segment = 0 | ||
| 3268 | * fixed by carlosf@conectiva.com.br | ||
| 3269 | */ | ||
| 3270 | } else { | ||
| 3271 | /* Frame start */ | ||
| 3272 | PDEBUG(4, "Frame start, framenum = %d", ov->curframe); | ||
| 3273 | |||
| 3274 | /* Check to see if it's a snapshot frame */ | ||
| 3275 | /* FIXME?? Should the snapshot reset go here? Performance? */ | ||
| 3276 | if (in[8] & 0x02) { | ||
| 3277 | frame->snapshot = 1; | ||
| 3278 | PDEBUG(3, "snapshot detected"); | ||
| 3279 | } | ||
| 3280 | |||
| 3281 | frame->scanstate = STATE_LINES; | ||
| 3282 | frame->bytes_recvd = 0; | ||
| 3283 | frame->compressed = in[8] & 0x40; | ||
| 3284 | } | ||
| 3285 | |||
| 3286 | check_middle: | ||
| 3287 | /* Are we in a frame? */ | ||
| 3288 | if (frame->scanstate != STATE_LINES) { | ||
| 3289 | PDEBUG(5, "Not in a frame; packet skipped"); | ||
| 3290 | return; | ||
| 3291 | } | ||
| 3292 | |||
| 3293 | /* If frame start, skip header */ | ||
| 3294 | if (frame->bytes_recvd == 0) | ||
| 3295 | offset = 9; | ||
| 3296 | else | ||
| 3297 | offset = 0; | ||
| 3298 | |||
| 3299 | num = n - offset - 1; | ||
| 3300 | |||
| 3301 | /* Dump all data exactly as received */ | ||
| 3302 | if (dumppix == 2) { | ||
| 3303 | frame->bytes_recvd += n - 1; | ||
| 3304 | if (frame->bytes_recvd <= max_raw) | ||
| 3305 | memcpy(frame->rawdata + frame->bytes_recvd - (n - 1), | ||
| 3306 | in, n - 1); | ||
| 3307 | else | ||
| 3308 | PDEBUG(3, "Raw data buffer overrun!! (%d)", | ||
| 3309 | frame->bytes_recvd - max_raw); | ||
| 3310 | } else if (!frame->compressed && !remove_zeros) { | ||
| 3311 | frame->bytes_recvd += num; | ||
| 3312 | if (frame->bytes_recvd <= max_raw) | ||
| 3313 | memcpy(frame->rawdata + frame->bytes_recvd - num, | ||
| 3314 | in + offset, num); | ||
| 3315 | else | ||
| 3316 | PDEBUG(3, "Raw data buffer overrun!! (%d)", | ||
| 3317 | frame->bytes_recvd - max_raw); | ||
| 3318 | } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ | ||
| 3319 | int b, read = 0, allzero, copied = 0; | ||
| 3320 | if (offset) { | ||
| 3321 | frame->bytes_recvd += 32 - offset; // Bytes out | ||
| 3322 | memcpy(frame->rawdata, in + offset, 32 - offset); | ||
| 3323 | read += 32; | ||
| 3324 | } | ||
| 3325 | |||
| 3326 | while (read < n - 1) { | ||
| 3327 | allzero = 1; | ||
| 3328 | for (b = 0; b < 32; b++) { | ||
| 3329 | if (in[read + b]) { | ||
| 3330 | allzero = 0; | ||
| 3331 | break; | ||
| 3332 | } | ||
| 3333 | } | ||
| 3334 | |||
| 3335 | if (allzero) { | ||
| 3336 | /* Don't copy it */ | ||
| 3337 | } else { | ||
| 3338 | if (frame->bytes_recvd + copied + 32 <= max_raw) | ||
| 3339 | { | ||
| 3340 | memcpy(frame->rawdata | ||
| 3341 | + frame->bytes_recvd + copied, | ||
| 3342 | in + read, 32); | ||
| 3343 | copied += 32; | ||
| 3344 | } else { | ||
| 3345 | PDEBUG(3, "Raw data buffer overrun!!"); | ||
| 3346 | } | ||
| 3347 | } | ||
| 3348 | read += 32; | ||
| 3349 | } | ||
| 3350 | |||
| 3351 | frame->bytes_recvd += copied; | ||
| 3352 | } | ||
| 3353 | } | ||
| 3354 | |||
| 3355 | static inline void | ||
| 3356 | ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n) | ||
| 3357 | { | ||
| 3358 | int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
| 3359 | struct ov511_frame *frame = &ov->frame[ov->curframe]; | ||
| 3360 | struct timeval *ts; | ||
| 3361 | |||
| 3362 | /* Don't copy the packet number byte */ | ||
| 3363 | if (ov->packet_numbering) | ||
| 3364 | --n; | ||
| 3365 | |||
| 3366 | /* A false positive here is likely, until OVT gives me | ||
| 3367 | * the definitive SOF/EOF format */ | ||
| 3368 | if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) { | ||
| 3369 | if (printph) { | ||
| 3370 | info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0], | ||
| 3371 | in[1], in[2], in[3], in[4], in[5], in[6], in[7]); | ||
| 3372 | } | ||
| 3373 | |||
| 3374 | if (frame->scanstate == STATE_LINES) { | ||
| 3375 | PDEBUG(4, "Detected frame end/start"); | ||
| 3376 | goto eof; | ||
| 3377 | } else { //scanstate == STATE_SCANNING | ||
| 3378 | /* Frame start */ | ||
| 3379 | PDEBUG(4, "Frame start, framenum = %d", ov->curframe); | ||
| 3380 | goto sof; | ||
| 3381 | } | ||
| 3382 | } else { | ||
| 3383 | goto check_middle; | ||
| 3384 | } | ||
| 3385 | |||
| 3386 | eof: | ||
| 3387 | ts = (struct timeval *)(frame->data | ||
| 3388 | + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); | ||
| 3389 | do_gettimeofday(ts); | ||
| 3390 | |||
| 3391 | PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", | ||
| 3392 | ov->curframe, | ||
| 3393 | (int)(in[9]), (int)(in[10]), frame->bytes_recvd); | ||
| 3394 | |||
| 3395 | // FIXME: Since we don't know the header formats yet, | ||
| 3396 | // there is no way to know what the actual image size is | ||
| 3397 | frame->rawwidth = frame->width; | ||
| 3398 | frame->rawheight = frame->height; | ||
| 3399 | |||
| 3400 | /* Validate the header data */ | ||
| 3401 | RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); | ||
| 3402 | RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); | ||
| 3403 | |||
| 3404 | /* Don't allow byte count to exceed buffer size */ | ||
| 3405 | RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); | ||
| 3406 | |||
| 3407 | if (frame->scanstate == STATE_LINES) { | ||
| 3408 | int nextf; | ||
| 3409 | |||
| 3410 | frame->grabstate = FRAME_DONE; | ||
| 3411 | wake_up_interruptible(&frame->wq); | ||
| 3412 | |||
| 3413 | /* If next frame is ready or grabbing, | ||
| 3414 | * point to it */ | ||
| 3415 | nextf = (ov->curframe + 1) % OV511_NUMFRAMES; | ||
| 3416 | if (ov->frame[nextf].grabstate == FRAME_READY | ||
| 3417 | || ov->frame[nextf].grabstate == FRAME_GRABBING) { | ||
| 3418 | ov->curframe = nextf; | ||
| 3419 | ov->frame[nextf].scanstate = STATE_SCANNING; | ||
| 3420 | frame = &ov->frame[nextf]; | ||
| 3421 | } else { | ||
| 3422 | if (frame->grabstate == FRAME_DONE) { | ||
| 3423 | PDEBUG(4, "** Frame done **"); | ||
| 3424 | } else { | ||
| 3425 | PDEBUG(4, "Frame not ready? state = %d", | ||
| 3426 | ov->frame[nextf].grabstate); | ||
| 3427 | } | ||
| 3428 | |||
| 3429 | ov->curframe = -1; | ||
| 3430 | PDEBUG(4, "SOF dropped (no active frame)"); | ||
| 3431 | return; /* Nowhere to store this frame */ | ||
| 3432 | } | ||
| 3433 | } | ||
| 3434 | sof: | ||
| 3435 | PDEBUG(4, "Starting capture on frame %d", frame->framenum); | ||
| 3436 | |||
| 3437 | // Snapshot not reverse-engineered yet. | ||
| 3438 | #if 0 | ||
| 3439 | /* Check to see if it's a snapshot frame */ | ||
| 3440 | /* FIXME?? Should the snapshot reset go here? Performance? */ | ||
| 3441 | if (in[8] & 0x02) { | ||
| 3442 | frame->snapshot = 1; | ||
| 3443 | PDEBUG(3, "snapshot detected"); | ||
| 3444 | } | ||
| 3445 | #endif | ||
| 3446 | frame->scanstate = STATE_LINES; | ||
| 3447 | frame->bytes_recvd = 0; | ||
| 3448 | frame->compressed = 1; | ||
| 3449 | |||
| 3450 | check_middle: | ||
| 3451 | /* Are we in a frame? */ | ||
| 3452 | if (frame->scanstate != STATE_LINES) { | ||
| 3453 | PDEBUG(4, "scanstate: no SOF yet"); | ||
| 3454 | return; | ||
| 3455 | } | ||
| 3456 | |||
| 3457 | /* Dump all data exactly as received */ | ||
| 3458 | if (dumppix == 2) { | ||
| 3459 | frame->bytes_recvd += n; | ||
| 3460 | if (frame->bytes_recvd <= max_raw) | ||
| 3461 | memcpy(frame->rawdata + frame->bytes_recvd - n, in, n); | ||
| 3462 | else | ||
| 3463 | PDEBUG(3, "Raw data buffer overrun!! (%d)", | ||
| 3464 | frame->bytes_recvd - max_raw); | ||
| 3465 | } else { | ||
| 3466 | /* All incoming data are divided into 8-byte segments. If the | ||
| 3467 | * segment contains all zero bytes, it must be skipped. These | ||
| 3468 | * zero-segments allow the OV518 to mainain a constant data rate | ||
| 3469 | * regardless of the effectiveness of the compression. Segments | ||
| 3470 | * are aligned relative to the beginning of each isochronous | ||
| 3471 | * packet. The first segment in each image is a header (the | ||
| 3472 | * decompressor skips it later). | ||
| 3473 | */ | ||
| 3474 | |||
| 3475 | int b, read = 0, allzero, copied = 0; | ||
| 3476 | |||
| 3477 | while (read < n) { | ||
| 3478 | allzero = 1; | ||
| 3479 | for (b = 0; b < 8; b++) { | ||
| 3480 | if (in[read + b]) { | ||
| 3481 | allzero = 0; | ||
| 3482 | break; | ||
| 3483 | } | ||
| 3484 | } | ||
| 3485 | |||
| 3486 | if (allzero) { | ||
| 3487 | /* Don't copy it */ | ||
| 3488 | } else { | ||
| 3489 | if (frame->bytes_recvd + copied + 8 <= max_raw) | ||
| 3490 | { | ||
| 3491 | memcpy(frame->rawdata | ||
| 3492 | + frame->bytes_recvd + copied, | ||
| 3493 | in + read, 8); | ||
| 3494 | copied += 8; | ||
| 3495 | } else { | ||
| 3496 | PDEBUG(3, "Raw data buffer overrun!!"); | ||
| 3497 | } | ||
| 3498 | } | ||
| 3499 | read += 8; | ||
| 3500 | } | ||
| 3501 | frame->bytes_recvd += copied; | ||
| 3502 | } | ||
| 3503 | } | ||
| 3504 | |||
| 3505 | static void | ||
| 3506 | ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs) | ||
| 3507 | { | ||
| 3508 | int i; | ||
| 3509 | struct usb_ov511 *ov; | ||
| 3510 | struct ov511_sbuf *sbuf; | ||
| 3511 | |||
| 3512 | if (!urb->context) { | ||
| 3513 | PDEBUG(4, "no context"); | ||
| 3514 | return; | ||
| 3515 | } | ||
| 3516 | |||
| 3517 | sbuf = urb->context; | ||
| 3518 | ov = sbuf->ov; | ||
| 3519 | |||
| 3520 | if (!ov || !ov->dev || !ov->user) { | ||
| 3521 | PDEBUG(4, "no device, or not open"); | ||
| 3522 | return; | ||
| 3523 | } | ||
| 3524 | |||
| 3525 | if (!ov->streaming) { | ||
| 3526 | PDEBUG(4, "hmmm... not streaming, but got interrupt"); | ||
| 3527 | return; | ||
| 3528 | } | ||
| 3529 | |||
| 3530 | if (urb->status == -ENOENT || urb->status == -ECONNRESET) { | ||
| 3531 | PDEBUG(4, "URB unlinked"); | ||
| 3532 | return; | ||
| 3533 | } | ||
| 3534 | |||
| 3535 | if (urb->status != -EINPROGRESS && urb->status != 0) { | ||
| 3536 | err("ERROR: urb->status=%d: %s", urb->status, | ||
| 3537 | symbolic(urb_errlist, urb->status)); | ||
| 3538 | } | ||
| 3539 | |||
| 3540 | /* Copy the data received into our frame buffer */ | ||
| 3541 | PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n, | ||
| 3542 | urb->number_of_packets); | ||
| 3543 | for (i = 0; i < urb->number_of_packets; i++) { | ||
| 3544 | /* Warning: Don't call *_move_data() if no frame active! */ | ||
| 3545 | if (ov->curframe >= 0) { | ||
| 3546 | int n = urb->iso_frame_desc[i].actual_length; | ||
| 3547 | int st = urb->iso_frame_desc[i].status; | ||
| 3548 | unsigned char *cdata; | ||
| 3549 | |||
| 3550 | urb->iso_frame_desc[i].actual_length = 0; | ||
| 3551 | urb->iso_frame_desc[i].status = 0; | ||
| 3552 | |||
| 3553 | cdata = urb->transfer_buffer | ||
| 3554 | + urb->iso_frame_desc[i].offset; | ||
| 3555 | |||
| 3556 | if (!n) { | ||
| 3557 | PDEBUG(4, "Zero-length packet"); | ||
| 3558 | continue; | ||
| 3559 | } | ||
| 3560 | |||
| 3561 | if (st) | ||
| 3562 | PDEBUG(2, "data error: [%d] len=%d, status=%d", | ||
| 3563 | i, n, st); | ||
| 3564 | |||
| 3565 | if (ov->bclass == BCL_OV511) | ||
| 3566 | ov511_move_data(ov, cdata, n); | ||
| 3567 | else if (ov->bclass == BCL_OV518) | ||
| 3568 | ov518_move_data(ov, cdata, n); | ||
| 3569 | else | ||
| 3570 | err("Unknown bridge device (%d)", ov->bridge); | ||
| 3571 | |||
| 3572 | } else if (waitqueue_active(&ov->wq)) { | ||
| 3573 | wake_up_interruptible(&ov->wq); | ||
| 3574 | } | ||
| 3575 | } | ||
| 3576 | |||
| 3577 | /* Resubmit this URB */ | ||
| 3578 | urb->dev = ov->dev; | ||
| 3579 | if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) | ||
| 3580 | err("usb_submit_urb() ret %d", i); | ||
| 3581 | |||
| 3582 | return; | ||
| 3583 | } | ||
| 3584 | |||
| 3585 | /**************************************************************************** | ||
| 3586 | * | ||
| 3587 | * Stream initialization and termination | ||
| 3588 | * | ||
| 3589 | ***************************************************************************/ | ||
| 3590 | |||
| 3591 | static int | ||
| 3592 | ov51x_init_isoc(struct usb_ov511 *ov) | ||
| 3593 | { | ||
| 3594 | struct urb *urb; | ||
| 3595 | int fx, err, n, size; | ||
| 3596 | |||
| 3597 | PDEBUG(3, "*** Initializing capture ***"); | ||
| 3598 | |||
| 3599 | ov->curframe = -1; | ||
| 3600 | |||
| 3601 | if (ov->bridge == BRG_OV511) { | ||
| 3602 | if (cams == 1) | ||
| 3603 | size = 993; | ||
| 3604 | else if (cams == 2) | ||
| 3605 | size = 513; | ||
| 3606 | else if (cams == 3 || cams == 4) | ||
| 3607 | size = 257; | ||
| 3608 | else { | ||
| 3609 | err("\"cams\" parameter too high!"); | ||
| 3610 | return -1; | ||
| 3611 | } | ||
| 3612 | } else if (ov->bridge == BRG_OV511PLUS) { | ||
| 3613 | if (cams == 1) | ||
| 3614 | size = 961; | ||
| 3615 | else if (cams == 2) | ||
| 3616 | size = 513; | ||
| 3617 | else if (cams == 3 || cams == 4) | ||
| 3618 | size = 257; | ||
| 3619 | else if (cams >= 5 && cams <= 8) | ||
| 3620 | size = 129; | ||
| 3621 | else if (cams >= 9 && cams <= 31) | ||
| 3622 | size = 33; | ||
| 3623 | else { | ||
| 3624 | err("\"cams\" parameter too high!"); | ||
| 3625 | return -1; | ||
| 3626 | } | ||
| 3627 | } else if (ov->bclass == BCL_OV518) { | ||
| 3628 | if (cams == 1) | ||
| 3629 | size = 896; | ||
| 3630 | else if (cams == 2) | ||
| 3631 | size = 512; | ||
| 3632 | else if (cams == 3 || cams == 4) | ||
| 3633 | size = 256; | ||
| 3634 | else if (cams >= 5 && cams <= 8) | ||
| 3635 | size = 128; | ||
| 3636 | else { | ||
| 3637 | err("\"cams\" parameter too high!"); | ||
| 3638 | return -1; | ||
| 3639 | } | ||
| 3640 | } else { | ||
| 3641 | err("invalid bridge type"); | ||
| 3642 | return -1; | ||
| 3643 | } | ||
| 3644 | |||
| 3645 | // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now | ||
| 3646 | if (ov->bclass == BCL_OV518) { | ||
| 3647 | if (packetsize == -1) { | ||
| 3648 | ov518_set_packet_size(ov, 640); | ||
| 3649 | } else { | ||
| 3650 | info("Forcing packet size to %d", packetsize); | ||
| 3651 | ov518_set_packet_size(ov, packetsize); | ||
| 3652 | } | ||
| 3653 | } else { | ||
| 3654 | if (packetsize == -1) { | ||
| 3655 | ov511_set_packet_size(ov, size); | ||
| 3656 | } else { | ||
| 3657 | info("Forcing packet size to %d", packetsize); | ||
| 3658 | ov511_set_packet_size(ov, packetsize); | ||
| 3659 | } | ||
| 3660 | } | ||
| 3661 | |||
| 3662 | for (n = 0; n < OV511_NUMSBUF; n++) { | ||
| 3663 | urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); | ||
| 3664 | if (!urb) { | ||
| 3665 | err("init isoc: usb_alloc_urb ret. NULL"); | ||
| 3666 | return -ENOMEM; | ||
| 3667 | } | ||
| 3668 | ov->sbuf[n].urb = urb; | ||
| 3669 | urb->dev = ov->dev; | ||
| 3670 | urb->context = &ov->sbuf[n]; | ||
| 3671 | urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); | ||
| 3672 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 3673 | urb->transfer_buffer = ov->sbuf[n].data; | ||
| 3674 | urb->complete = ov51x_isoc_irq; | ||
| 3675 | urb->number_of_packets = FRAMES_PER_DESC; | ||
| 3676 | urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; | ||
| 3677 | urb->interval = 1; | ||
| 3678 | for (fx = 0; fx < FRAMES_PER_DESC; fx++) { | ||
| 3679 | urb->iso_frame_desc[fx].offset = ov->packet_size * fx; | ||
| 3680 | urb->iso_frame_desc[fx].length = ov->packet_size; | ||
| 3681 | } | ||
| 3682 | } | ||
| 3683 | |||
| 3684 | ov->streaming = 1; | ||
| 3685 | |||
| 3686 | for (n = 0; n < OV511_NUMSBUF; n++) { | ||
| 3687 | ov->sbuf[n].urb->dev = ov->dev; | ||
| 3688 | err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL); | ||
| 3689 | if (err) { | ||
| 3690 | err("init isoc: usb_submit_urb(%d) ret %d", n, err); | ||
| 3691 | return err; | ||
| 3692 | } | ||
| 3693 | } | ||
| 3694 | |||
| 3695 | return 0; | ||
| 3696 | } | ||
| 3697 | |||
| 3698 | static void | ||
| 3699 | ov51x_unlink_isoc(struct usb_ov511 *ov) | ||
| 3700 | { | ||
| 3701 | int n; | ||
| 3702 | |||
| 3703 | /* Unschedule all of the iso td's */ | ||
| 3704 | for (n = OV511_NUMSBUF - 1; n >= 0; n--) { | ||
| 3705 | if (ov->sbuf[n].urb) { | ||
| 3706 | usb_kill_urb(ov->sbuf[n].urb); | ||
| 3707 | usb_free_urb(ov->sbuf[n].urb); | ||
| 3708 | ov->sbuf[n].urb = NULL; | ||
| 3709 | } | ||
| 3710 | } | ||
| 3711 | } | ||
| 3712 | |||
| 3713 | static void | ||
| 3714 | ov51x_stop_isoc(struct usb_ov511 *ov) | ||
| 3715 | { | ||
| 3716 | if (!ov->streaming || !ov->dev) | ||
| 3717 | return; | ||
| 3718 | |||
| 3719 | PDEBUG(3, "*** Stopping capture ***"); | ||
| 3720 | |||
| 3721 | if (ov->bclass == BCL_OV518) | ||
| 3722 | ov518_set_packet_size(ov, 0); | ||
| 3723 | else | ||
| 3724 | ov511_set_packet_size(ov, 0); | ||
| 3725 | |||
| 3726 | ov->streaming = 0; | ||
| 3727 | |||
| 3728 | ov51x_unlink_isoc(ov); | ||
| 3729 | } | ||
| 3730 | |||
| 3731 | static int | ||
| 3732 | ov51x_new_frame(struct usb_ov511 *ov, int framenum) | ||
| 3733 | { | ||
| 3734 | struct ov511_frame *frame; | ||
| 3735 | int newnum; | ||
| 3736 | |||
| 3737 | PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); | ||
| 3738 | |||
| 3739 | if (!ov->dev) | ||
| 3740 | return -1; | ||
| 3741 | |||
| 3742 | /* If we're not grabbing a frame right now and the other frame is */ | ||
| 3743 | /* ready to be grabbed into, then use it instead */ | ||
| 3744 | if (ov->curframe == -1) { | ||
| 3745 | newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; | ||
| 3746 | if (ov->frame[newnum].grabstate == FRAME_READY) | ||
| 3747 | framenum = newnum; | ||
| 3748 | } else | ||
| 3749 | return 0; | ||
| 3750 | |||
| 3751 | frame = &ov->frame[framenum]; | ||
| 3752 | |||
| 3753 | PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, | ||
| 3754 | frame->width, frame->height); | ||
| 3755 | |||
| 3756 | frame->grabstate = FRAME_GRABBING; | ||
| 3757 | frame->scanstate = STATE_SCANNING; | ||
| 3758 | frame->snapshot = 0; | ||
| 3759 | |||
| 3760 | ov->curframe = framenum; | ||
| 3761 | |||
| 3762 | /* Make sure it's not too big */ | ||
| 3763 | if (frame->width > ov->maxwidth) | ||
| 3764 | frame->width = ov->maxwidth; | ||
| 3765 | |||
| 3766 | frame->width &= ~7L; /* Multiple of 8 */ | ||
| 3767 | |||
| 3768 | if (frame->height > ov->maxheight) | ||
| 3769 | frame->height = ov->maxheight; | ||
| 3770 | |||
| 3771 | frame->height &= ~3L; /* Multiple of 4 */ | ||
| 3772 | |||
| 3773 | return 0; | ||
| 3774 | } | ||
| 3775 | |||
| 3776 | /**************************************************************************** | ||
| 3777 | * | ||
| 3778 | * Buffer management | ||
| 3779 | * | ||
| 3780 | ***************************************************************************/ | ||
| 3781 | |||
| 3782 | /* | ||
| 3783 | * - You must acquire buf_lock before entering this function. | ||
| 3784 | * - Because this code will free any non-null pointer, you must be sure to null | ||
| 3785 | * them if you explicitly free them somewhere else! | ||
| 3786 | */ | ||
| 3787 | static void | ||
| 3788 | ov51x_do_dealloc(struct usb_ov511 *ov) | ||
| 3789 | { | ||
| 3790 | int i; | ||
| 3791 | PDEBUG(4, "entered"); | ||
| 3792 | |||
| 3793 | if (ov->fbuf) { | ||
| 3794 | rvfree(ov->fbuf, OV511_NUMFRAMES | ||
| 3795 | * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); | ||
| 3796 | ov->fbuf = NULL; | ||
| 3797 | } | ||
| 3798 | |||
| 3799 | vfree(ov->rawfbuf); | ||
| 3800 | ov->rawfbuf = NULL; | ||
| 3801 | |||
| 3802 | vfree(ov->tempfbuf); | ||
| 3803 | ov->tempfbuf = NULL; | ||
| 3804 | |||
| 3805 | for (i = 0; i < OV511_NUMSBUF; i++) { | ||
| 3806 | kfree(ov->sbuf[i].data); | ||
| 3807 | ov->sbuf[i].data = NULL; | ||
| 3808 | } | ||
| 3809 | |||
| 3810 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
| 3811 | ov->frame[i].data = NULL; | ||
| 3812 | ov->frame[i].rawdata = NULL; | ||
| 3813 | ov->frame[i].tempdata = NULL; | ||
| 3814 | if (ov->frame[i].compbuf) { | ||
| 3815 | free_page((unsigned long) ov->frame[i].compbuf); | ||
| 3816 | ov->frame[i].compbuf = NULL; | ||
| 3817 | } | ||
| 3818 | } | ||
| 3819 | |||
| 3820 | PDEBUG(4, "buffer memory deallocated"); | ||
| 3821 | ov->buf_state = BUF_NOT_ALLOCATED; | ||
| 3822 | PDEBUG(4, "leaving"); | ||
| 3823 | } | ||
| 3824 | |||
| 3825 | static int | ||
| 3826 | ov51x_alloc(struct usb_ov511 *ov) | ||
| 3827 | { | ||
| 3828 | int i; | ||
| 3829 | const int w = ov->maxwidth; | ||
| 3830 | const int h = ov->maxheight; | ||
| 3831 | const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h); | ||
| 3832 | const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); | ||
| 3833 | |||
| 3834 | PDEBUG(4, "entered"); | ||
| 3835 | mutex_lock(&ov->buf_lock); | ||
| 3836 | |||
| 3837 | if (ov->buf_state == BUF_ALLOCATED) | ||
| 3838 | goto out; | ||
| 3839 | |||
| 3840 | ov->fbuf = rvmalloc(data_bufsize); | ||
| 3841 | if (!ov->fbuf) | ||
| 3842 | goto error; | ||
| 3843 | |||
| 3844 | ov->rawfbuf = vmalloc(raw_bufsize); | ||
| 3845 | if (!ov->rawfbuf) | ||
| 3846 | goto error; | ||
| 3847 | |||
| 3848 | memset(ov->rawfbuf, 0, raw_bufsize); | ||
| 3849 | |||
| 3850 | ov->tempfbuf = vmalloc(raw_bufsize); | ||
| 3851 | if (!ov->tempfbuf) | ||
| 3852 | goto error; | ||
| 3853 | |||
| 3854 | memset(ov->tempfbuf, 0, raw_bufsize); | ||
| 3855 | |||
| 3856 | for (i = 0; i < OV511_NUMSBUF; i++) { | ||
| 3857 | ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * | ||
| 3858 | MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); | ||
| 3859 | if (!ov->sbuf[i].data) | ||
| 3860 | goto error; | ||
| 3861 | |||
| 3862 | PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); | ||
| 3863 | } | ||
| 3864 | |||
| 3865 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
| 3866 | ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); | ||
| 3867 | ov->frame[i].rawdata = ov->rawfbuf | ||
| 3868 | + i * MAX_RAW_DATA_SIZE(w, h); | ||
| 3869 | ov->frame[i].tempdata = ov->tempfbuf | ||
| 3870 | + i * MAX_RAW_DATA_SIZE(w, h); | ||
| 3871 | |||
| 3872 | ov->frame[i].compbuf = | ||
| 3873 | (unsigned char *) __get_free_page(GFP_KERNEL); | ||
| 3874 | if (!ov->frame[i].compbuf) | ||
| 3875 | goto error; | ||
| 3876 | |||
| 3877 | PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); | ||
| 3878 | } | ||
| 3879 | |||
| 3880 | ov->buf_state = BUF_ALLOCATED; | ||
| 3881 | out: | ||
| 3882 | mutex_unlock(&ov->buf_lock); | ||
| 3883 | PDEBUG(4, "leaving"); | ||
| 3884 | return 0; | ||
| 3885 | error: | ||
| 3886 | ov51x_do_dealloc(ov); | ||
| 3887 | mutex_unlock(&ov->buf_lock); | ||
| 3888 | PDEBUG(4, "errored"); | ||
| 3889 | return -ENOMEM; | ||
| 3890 | } | ||
| 3891 | |||
| 3892 | static void | ||
| 3893 | ov51x_dealloc(struct usb_ov511 *ov) | ||
| 3894 | { | ||
| 3895 | PDEBUG(4, "entered"); | ||
| 3896 | mutex_lock(&ov->buf_lock); | ||
| 3897 | ov51x_do_dealloc(ov); | ||
| 3898 | mutex_unlock(&ov->buf_lock); | ||
| 3899 | PDEBUG(4, "leaving"); | ||
| 3900 | } | ||
| 3901 | |||
| 3902 | /**************************************************************************** | ||
| 3903 | * | ||
| 3904 | * V4L 1 API | ||
| 3905 | * | ||
| 3906 | ***************************************************************************/ | ||
| 3907 | |||
| 3908 | static int | ||
| 3909 | ov51x_v4l1_open(struct inode *inode, struct file *file) | ||
| 3910 | { | ||
| 3911 | struct video_device *vdev = video_devdata(file); | ||
| 3912 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
| 3913 | int err, i; | ||
| 3914 | |||
| 3915 | PDEBUG(4, "opening"); | ||
| 3916 | |||
| 3917 | mutex_lock(&ov->lock); | ||
| 3918 | |||
| 3919 | err = -EBUSY; | ||
| 3920 | if (ov->user) | ||
| 3921 | goto out; | ||
| 3922 | |||
| 3923 | ov->sub_flag = 0; | ||
| 3924 | |||
| 3925 | /* In case app doesn't set them... */ | ||
| 3926 | err = ov51x_set_default_params(ov); | ||
| 3927 | if (err < 0) | ||
| 3928 | goto out; | ||
| 3929 | |||
| 3930 | /* Make sure frames are reset */ | ||
| 3931 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
| 3932 | ov->frame[i].grabstate = FRAME_UNUSED; | ||
| 3933 | ov->frame[i].bytes_read = 0; | ||
| 3934 | } | ||
| 3935 | |||
| 3936 | /* If compression is on, make sure now that a | ||
| 3937 | * decompressor can be loaded */ | ||
| 3938 | if (ov->compress && !ov->decomp_ops) { | ||
| 3939 | err = request_decompressor(ov); | ||
| 3940 | if (err && !dumppix) | ||
| 3941 | goto out; | ||
| 3942 | } | ||
| 3943 | |||
| 3944 | err = ov51x_alloc(ov); | ||
| 3945 | if (err < 0) | ||
| 3946 | goto out; | ||
| 3947 | |||
| 3948 | err = ov51x_init_isoc(ov); | ||
| 3949 | if (err) { | ||
| 3950 | ov51x_dealloc(ov); | ||
| 3951 | goto out; | ||
| 3952 | } | ||
| 3953 | |||
| 3954 | ov->user++; | ||
| 3955 | file->private_data = vdev; | ||
| 3956 | |||
| 3957 | if (ov->led_policy == LED_AUTO) | ||
| 3958 | ov51x_led_control(ov, 1); | ||
| 3959 | |||
| 3960 | out: | ||
| 3961 | mutex_unlock(&ov->lock); | ||
| 3962 | return err; | ||
| 3963 | } | ||
| 3964 | |||
| 3965 | static int | ||
| 3966 | ov51x_v4l1_close(struct inode *inode, struct file *file) | ||
| 3967 | { | ||
| 3968 | struct video_device *vdev = file->private_data; | ||
| 3969 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
| 3970 | |||
| 3971 | PDEBUG(4, "ov511_close"); | ||
| 3972 | |||
| 3973 | mutex_lock(&ov->lock); | ||
| 3974 | |||
| 3975 | ov->user--; | ||
| 3976 | ov51x_stop_isoc(ov); | ||
| 3977 | |||
| 3978 | if (ov->led_policy == LED_AUTO) | ||
| 3979 | ov51x_led_control(ov, 0); | ||
| 3980 | |||
| 3981 | if (ov->dev) | ||
| 3982 | ov51x_dealloc(ov); | ||
| 3983 | |||
| 3984 | mutex_unlock(&ov->lock); | ||
| 3985 | |||
| 3986 | /* Device unplugged while open. Only a minimum of unregistration is done | ||
| 3987 | * here; the disconnect callback already did the rest. */ | ||
| 3988 | if (!ov->dev) { | ||
| 3989 | mutex_lock(&ov->cbuf_lock); | ||
| 3990 | kfree(ov->cbuf); | ||
| 3991 | ov->cbuf = NULL; | ||
| 3992 | mutex_unlock(&ov->cbuf_lock); | ||
| 3993 | |||
| 3994 | ov51x_dealloc(ov); | ||
| 3995 | kfree(ov); | ||
| 3996 | ov = NULL; | ||
| 3997 | } | ||
| 3998 | |||
| 3999 | file->private_data = NULL; | ||
| 4000 | return 0; | ||
| 4001 | } | ||
| 4002 | |||
| 4003 | /* Do not call this function directly! */ | ||
| 4004 | static int | ||
| 4005 | ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, | ||
| 4006 | unsigned int cmd, void *arg) | ||
| 4007 | { | ||
| 4008 | struct video_device *vdev = file->private_data; | ||
| 4009 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
| 4010 | PDEBUG(5, "IOCtl: 0x%X", cmd); | ||
| 4011 | |||
| 4012 | if (!ov->dev) | ||
| 4013 | return -EIO; | ||
| 4014 | |||
| 4015 | switch (cmd) { | ||
| 4016 | case VIDIOCGCAP: | ||
| 4017 | { | ||
| 4018 | struct video_capability *b = arg; | ||
| 4019 | |||
| 4020 | PDEBUG(4, "VIDIOCGCAP"); | ||
| 4021 | |||
| 4022 | memset(b, 0, sizeof(struct video_capability)); | ||
| 4023 | sprintf(b->name, "%s USB Camera", | ||
| 4024 | symbolic(brglist, ov->bridge)); | ||
| 4025 | b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; | ||
| 4026 | b->channels = ov->num_inputs; | ||
| 4027 | b->audios = 0; | ||
| 4028 | b->maxwidth = ov->maxwidth; | ||
| 4029 | b->maxheight = ov->maxheight; | ||
| 4030 | b->minwidth = ov->minwidth; | ||
| 4031 | b->minheight = ov->minheight; | ||
| 4032 | |||
| 4033 | return 0; | ||
| 4034 | } | ||
| 4035 | case VIDIOCGCHAN: | ||
| 4036 | { | ||
| 4037 | struct video_channel *v = arg; | ||
| 4038 | |||
| 4039 | PDEBUG(4, "VIDIOCGCHAN"); | ||
| 4040 | |||
| 4041 | if ((unsigned)(v->channel) >= ov->num_inputs) { | ||
| 4042 | err("Invalid channel (%d)", v->channel); | ||
| 4043 | return -EINVAL; | ||
| 4044 | } | ||
| 4045 | |||
| 4046 | v->norm = ov->norm; | ||
| 4047 | v->type = VIDEO_TYPE_CAMERA; | ||
| 4048 | v->flags = 0; | ||
| 4049 | // v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; | ||
| 4050 | v->tuners = 0; | ||
| 4051 | decoder_get_input_name(ov, v->channel, v->name); | ||
| 4052 | |||
| 4053 | return 0; | ||
| 4054 | } | ||
| 4055 | case VIDIOCSCHAN: | ||
| 4056 | { | ||
| 4057 | struct video_channel *v = arg; | ||
| 4058 | int err; | ||
| 4059 | |||
| 4060 | PDEBUG(4, "VIDIOCSCHAN"); | ||
| 4061 | |||
| 4062 | /* Make sure it's not a camera */ | ||
| 4063 | if (!ov->has_decoder) { | ||
| 4064 | if (v->channel == 0) | ||
| 4065 | return 0; | ||
| 4066 | else | ||
| 4067 | return -EINVAL; | ||
| 4068 | } | ||
| 4069 | |||
| 4070 | if (v->norm != VIDEO_MODE_PAL && | ||
| 4071 | v->norm != VIDEO_MODE_NTSC && | ||
| 4072 | v->norm != VIDEO_MODE_SECAM && | ||
| 4073 | v->norm != VIDEO_MODE_AUTO) { | ||
| 4074 | err("Invalid norm (%d)", v->norm); | ||
| 4075 | return -EINVAL; | ||
| 4076 | } | ||
| 4077 | |||
| 4078 | if ((unsigned)(v->channel) >= ov->num_inputs) { | ||
| 4079 | err("Invalid channel (%d)", v->channel); | ||
| 4080 | return -EINVAL; | ||
| 4081 | } | ||
| 4082 | |||
| 4083 | err = decoder_set_input(ov, v->channel); | ||
| 4084 | if (err) | ||
| 4085 | return err; | ||
| 4086 | |||
| 4087 | err = decoder_set_norm(ov, v->norm); | ||
| 4088 | if (err) | ||
| 4089 | return err; | ||
| 4090 | |||
| 4091 | return 0; | ||
| 4092 | } | ||
| 4093 | case VIDIOCGPICT: | ||
| 4094 | { | ||
| 4095 | struct video_picture *p = arg; | ||
| 4096 | |||
| 4097 | PDEBUG(4, "VIDIOCGPICT"); | ||
| 4098 | |||
| 4099 | memset(p, 0, sizeof(struct video_picture)); | ||
| 4100 | if (sensor_get_picture(ov, p)) | ||
| 4101 | return -EIO; | ||
| 4102 | |||
| 4103 | /* Can we get these from frame[0]? -claudio? */ | ||
| 4104 | p->depth = ov->frame[0].depth; | ||
| 4105 | p->palette = ov->frame[0].format; | ||
| 4106 | |||
| 4107 | return 0; | ||
| 4108 | } | ||
| 4109 | case VIDIOCSPICT: | ||
| 4110 | { | ||
| 4111 | struct video_picture *p = arg; | ||
| 4112 | int i, rc; | ||
| 4113 | |||
| 4114 | PDEBUG(4, "VIDIOCSPICT"); | ||
| 4115 | |||
| 4116 | if (!get_depth(p->palette)) | ||
| 4117 | return -EINVAL; | ||
| 4118 | |||
| 4119 | if (sensor_set_picture(ov, p)) | ||
| 4120 | return -EIO; | ||
| 4121 | |||
| 4122 | if (force_palette && p->palette != force_palette) { | ||
| 4123 | info("Palette rejected (%s)", | ||
| 4124 | symbolic(v4l1_plist, p->palette)); | ||
| 4125 | return -EINVAL; | ||
| 4126 | } | ||
| 4127 | |||
| 4128 | // FIXME: Format should be independent of frames | ||
| 4129 | if (p->palette != ov->frame[0].format) { | ||
| 4130 | PDEBUG(4, "Detected format change"); | ||
| 4131 | |||
| 4132 | rc = ov51x_wait_frames_inactive(ov); | ||
| 4133 | if (rc) | ||
| 4134 | return rc; | ||
| 4135 | |||
| 4136 | mode_init_regs(ov, ov->frame[0].width, | ||
| 4137 | ov->frame[0].height, p->palette, ov->sub_flag); | ||
| 4138 | } | ||
| 4139 | |||
| 4140 | PDEBUG(4, "Setting depth=%d, palette=%s", | ||
| 4141 | p->depth, symbolic(v4l1_plist, p->palette)); | ||
| 4142 | |||
| 4143 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
| 4144 | ov->frame[i].depth = p->depth; | ||
| 4145 | ov->frame[i].format = p->palette; | ||
| 4146 | } | ||
| 4147 | |||
| 4148 | return 0; | ||
| 4149 | } | ||
| 4150 | case VIDIOCGCAPTURE: | ||
| 4151 | { | ||
| 4152 | int *vf = arg; | ||
| 4153 | |||
| 4154 | PDEBUG(4, "VIDIOCGCAPTURE"); | ||
| 4155 | |||
| 4156 | ov->sub_flag = *vf; | ||
| 4157 | return 0; | ||
| 4158 | } | ||
| 4159 | case VIDIOCSCAPTURE: | ||
| 4160 | { | ||
| 4161 | struct video_capture *vc = arg; | ||
| 4162 | |||
| 4163 | PDEBUG(4, "VIDIOCSCAPTURE"); | ||
| 4164 | |||
| 4165 | if (vc->flags) | ||
| 4166 | return -EINVAL; | ||
| 4167 | if (vc->decimation) | ||
| 4168 | return -EINVAL; | ||
| 4169 | |||
| 4170 | vc->x &= ~3L; | ||
| 4171 | vc->y &= ~1L; | ||
| 4172 | vc->y &= ~31L; | ||
| 4173 | |||
| 4174 | if (vc->width == 0) | ||
| 4175 | vc->width = 32; | ||
| 4176 | |||
| 4177 | vc->height /= 16; | ||
| 4178 | vc->height *= 16; | ||
| 4179 | if (vc->height == 0) | ||
| 4180 | vc->height = 16; | ||
| 4181 | |||
| 4182 | ov->subx = vc->x; | ||
| 4183 | ov->suby = vc->y; | ||
| 4184 | ov->subw = vc->width; | ||
| 4185 | ov->subh = vc->height; | ||
| 4186 | |||
| 4187 | return 0; | ||
| 4188 | } | ||
| 4189 | case VIDIOCSWIN: | ||
| 4190 | { | ||
| 4191 | struct video_window *vw = arg; | ||
| 4192 | int i, rc; | ||
| 4193 | |||
| 4194 | PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height); | ||
| 4195 | |||
| 4196 | #if 0 | ||
| 4197 | if (vw->flags) | ||
| 4198 | return -EINVAL; | ||
| 4199 | if (vw->clipcount) | ||
| 4200 | return -EINVAL; | ||
| 4201 | if (vw->height != ov->maxheight) | ||
| 4202 | return -EINVAL; | ||
| 4203 | if (vw->width != ov->maxwidth) | ||
| 4204 | return -EINVAL; | ||
| 4205 | #endif | ||
| 4206 | |||
| 4207 | rc = ov51x_wait_frames_inactive(ov); | ||
| 4208 | if (rc) | ||
| 4209 | return rc; | ||
| 4210 | |||
| 4211 | rc = mode_init_regs(ov, vw->width, vw->height, | ||
| 4212 | ov->frame[0].format, ov->sub_flag); | ||
| 4213 | if (rc < 0) | ||
| 4214 | return rc; | ||
| 4215 | |||
| 4216 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
| 4217 | ov->frame[i].width = vw->width; | ||
| 4218 | ov->frame[i].height = vw->height; | ||
| 4219 | } | ||
| 4220 | |||
| 4221 | return 0; | ||
| 4222 | } | ||
| 4223 | case VIDIOCGWIN: | ||
| 4224 | { | ||
| 4225 | struct video_window *vw = arg; | ||
| 4226 | |||
| 4227 | memset(vw, 0, sizeof(struct video_window)); | ||
| 4228 | vw->x = 0; /* FIXME */ | ||
| 4229 | vw->y = 0; | ||
| 4230 | vw->width = ov->frame[0].width; | ||
| 4231 | vw->height = ov->frame[0].height; | ||
| 4232 | vw->flags = 30; | ||
| 4233 | |||
| 4234 | PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height); | ||
| 4235 | |||
| 4236 | return 0; | ||
| 4237 | } | ||
| 4238 | case VIDIOCGMBUF: | ||
| 4239 | { | ||
| 4240 | struct video_mbuf *vm = arg; | ||
| 4241 | int i; | ||
| 4242 | |||
| 4243 | PDEBUG(4, "VIDIOCGMBUF"); | ||
| 4244 | |||
| 4245 | memset(vm, 0, sizeof(struct video_mbuf)); | ||
| 4246 | vm->size = OV511_NUMFRAMES | ||
| 4247 | * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
| 4248 | vm->frames = OV511_NUMFRAMES; | ||
| 4249 | |||
| 4250 | vm->offsets[0] = 0; | ||
| 4251 | for (i = 1; i < OV511_NUMFRAMES; i++) { | ||
| 4252 | vm->offsets[i] = vm->offsets[i-1] | ||
| 4253 | + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
| 4254 | } | ||
| 4255 | |||
| 4256 | return 0; | ||
| 4257 | } | ||
| 4258 | case VIDIOCMCAPTURE: | ||
| 4259 | { | ||
| 4260 | struct video_mmap *vm = arg; | ||
| 4261 | int rc, depth; | ||
| 4262 | unsigned int f = vm->frame; | ||
| 4263 | |||
| 4264 | PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width, | ||
| 4265 | vm->height, symbolic(v4l1_plist, vm->format)); | ||
| 4266 | |||
| 4267 | depth = get_depth(vm->format); | ||
| 4268 | if (!depth) { | ||
| 4269 | PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)", | ||
| 4270 | symbolic(v4l1_plist, vm->format)); | ||
| 4271 | return -EINVAL; | ||
| 4272 | } | ||
| 4273 | |||
| 4274 | if (f >= OV511_NUMFRAMES) { | ||
| 4275 | err("VIDIOCMCAPTURE: invalid frame (%d)", f); | ||
| 4276 | return -EINVAL; | ||
| 4277 | } | ||
| 4278 | |||
| 4279 | if (vm->width > ov->maxwidth | ||
| 4280 | || vm->height > ov->maxheight) { | ||
| 4281 | err("VIDIOCMCAPTURE: requested dimensions too big"); | ||
| 4282 | return -EINVAL; | ||
| 4283 | } | ||
| 4284 | |||
| 4285 | if (ov->frame[f].grabstate == FRAME_GRABBING) { | ||
| 4286 | PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); | ||
| 4287 | return -EBUSY; | ||
| 4288 | } | ||
| 4289 | |||
| 4290 | if (force_palette && (vm->format != force_palette)) { | ||
| 4291 | PDEBUG(2, "palette rejected (%s)", | ||
| 4292 | symbolic(v4l1_plist, vm->format)); | ||
| 4293 | return -EINVAL; | ||
| 4294 | } | ||
| 4295 | |||
| 4296 | if ((ov->frame[f].width != vm->width) || | ||
| 4297 | (ov->frame[f].height != vm->height) || | ||
| 4298 | (ov->frame[f].format != vm->format) || | ||
| 4299 | (ov->frame[f].sub_flag != ov->sub_flag) || | ||
| 4300 | (ov->frame[f].depth != depth)) { | ||
| 4301 | PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); | ||
| 4302 | |||
| 4303 | rc = ov51x_wait_frames_inactive(ov); | ||
| 4304 | if (rc) | ||
| 4305 | return rc; | ||
| 4306 | |||
| 4307 | rc = mode_init_regs(ov, vm->width, vm->height, | ||
| 4308 | vm->format, ov->sub_flag); | ||
| 4309 | #if 0 | ||
| 4310 | if (rc < 0) { | ||
| 4311 | PDEBUG(1, "Got error while initializing regs "); | ||
| 4312 | return ret; | ||
| 4313 | } | ||
| 4314 | #endif | ||
| 4315 | ov->frame[f].width = vm->width; | ||
| 4316 | ov->frame[f].height = vm->height; | ||
| 4317 | ov->frame[f].format = vm->format; | ||
| 4318 | ov->frame[f].sub_flag = ov->sub_flag; | ||
| 4319 | ov->frame[f].depth = depth; | ||
| 4320 | } | ||
| 4321 | |||
| 4322 | /* Mark it as ready */ | ||
| 4323 | ov->frame[f].grabstate = FRAME_READY; | ||
| 4324 | |||
| 4325 | PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f); | ||
| 4326 | |||
| 4327 | return ov51x_new_frame(ov, f); | ||
| 4328 | } | ||
| 4329 | case VIDIOCSYNC: | ||
| 4330 | { | ||
| 4331 | unsigned int fnum = *((unsigned int *) arg); | ||
| 4332 | struct ov511_frame *frame; | ||
| 4333 | int rc; | ||
| 4334 | |||
| 4335 | if (fnum >= OV511_NUMFRAMES) { | ||
| 4336 | err("VIDIOCSYNC: invalid frame (%d)", fnum); | ||
| 4337 | return -EINVAL; | ||
| 4338 | } | ||
| 4339 | |||
| 4340 | frame = &ov->frame[fnum]; | ||
| 4341 | |||
| 4342 | PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, | ||
| 4343 | frame->grabstate); | ||
| 4344 | |||
| 4345 | switch (frame->grabstate) { | ||
| 4346 | case FRAME_UNUSED: | ||
| 4347 | return -EINVAL; | ||
| 4348 | case FRAME_READY: | ||
| 4349 | case FRAME_GRABBING: | ||
| 4350 | case FRAME_ERROR: | ||
| 4351 | redo: | ||
| 4352 | if (!ov->dev) | ||
| 4353 | return -EIO; | ||
| 4354 | |||
| 4355 | rc = wait_event_interruptible(frame->wq, | ||
| 4356 | (frame->grabstate == FRAME_DONE) | ||
| 4357 | || (frame->grabstate == FRAME_ERROR)); | ||
| 4358 | |||
| 4359 | if (rc) | ||
| 4360 | return rc; | ||
| 4361 | |||
| 4362 | if (frame->grabstate == FRAME_ERROR) { | ||
| 4363 | if ((rc = ov51x_new_frame(ov, fnum)) < 0) | ||
| 4364 | return rc; | ||
| 4365 | goto redo; | ||
| 4366 | } | ||
| 4367 | /* Fall through */ | ||
| 4368 | case FRAME_DONE: | ||
| 4369 | if (ov->snap_enabled && !frame->snapshot) { | ||
| 4370 | if ((rc = ov51x_new_frame(ov, fnum)) < 0) | ||
| 4371 | return rc; | ||
| 4372 | goto redo; | ||
| 4373 | } | ||
| 4374 | |||
| 4375 | frame->grabstate = FRAME_UNUSED; | ||
| 4376 | |||
| 4377 | /* Reset the hardware snapshot button */ | ||
| 4378 | /* FIXME - Is this the best place for this? */ | ||
| 4379 | if ((ov->snap_enabled) && (frame->snapshot)) { | ||
| 4380 | frame->snapshot = 0; | ||
| 4381 | ov51x_clear_snapshot(ov); | ||
| 4382 | } | ||
| 4383 | |||
| 4384 | /* Decompression, format conversion, etc... */ | ||
| 4385 | ov51x_postprocess(ov, frame); | ||
| 4386 | |||
| 4387 | break; | ||
| 4388 | } /* end switch */ | ||
| 4389 | |||
| 4390 | return 0; | ||
| 4391 | } | ||
| 4392 | case VIDIOCGFBUF: | ||
| 4393 | { | ||
| 4394 | struct video_buffer *vb = arg; | ||
| 4395 | |||
| 4396 | PDEBUG(4, "VIDIOCGFBUF"); | ||
| 4397 | |||
| 4398 | memset(vb, 0, sizeof(struct video_buffer)); | ||
| 4399 | |||
| 4400 | return 0; | ||
| 4401 | } | ||
| 4402 | case VIDIOCGUNIT: | ||
| 4403 | { | ||
| 4404 | struct video_unit *vu = arg; | ||
| 4405 | |||
| 4406 | PDEBUG(4, "VIDIOCGUNIT"); | ||
| 4407 | |||
| 4408 | memset(vu, 0, sizeof(struct video_unit)); | ||
| 4409 | |||
| 4410 | vu->video = ov->vdev->minor; | ||
| 4411 | vu->vbi = VIDEO_NO_UNIT; | ||
| 4412 | vu->radio = VIDEO_NO_UNIT; | ||
| 4413 | vu->audio = VIDEO_NO_UNIT; | ||
| 4414 | vu->teletext = VIDEO_NO_UNIT; | ||
| 4415 | |||
| 4416 | return 0; | ||
| 4417 | } | ||
| 4418 | case OV511IOC_WI2C: | ||
| 4419 | { | ||
| 4420 | struct ov511_i2c_struct *w = arg; | ||
| 4421 | |||
| 4422 | return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask); | ||
| 4423 | } | ||
| 4424 | case OV511IOC_RI2C: | ||
| 4425 | { | ||
| 4426 | struct ov511_i2c_struct *r = arg; | ||
| 4427 | int rc; | ||
| 4428 | |||
| 4429 | rc = i2c_r_slave(ov, r->slave, r->reg); | ||
| 4430 | if (rc < 0) | ||
| 4431 | return rc; | ||
| 4432 | |||
| 4433 | r->value = rc; | ||
| 4434 | return 0; | ||
| 4435 | } | ||
| 4436 | default: | ||
| 4437 | PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd); | ||
| 4438 | return -ENOIOCTLCMD; | ||
| 4439 | } /* end switch */ | ||
| 4440 | |||
| 4441 | return 0; | ||
| 4442 | } | ||
| 4443 | |||
| 4444 | static int | ||
| 4445 | ov51x_v4l1_ioctl(struct inode *inode, struct file *file, | ||
| 4446 | unsigned int cmd, unsigned long arg) | ||
| 4447 | { | ||
| 4448 | struct video_device *vdev = file->private_data; | ||
| 4449 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
| 4450 | int rc; | ||
| 4451 | |||
| 4452 | if (mutex_lock_interruptible(&ov->lock)) | ||
| 4453 | return -EINTR; | ||
| 4454 | |||
| 4455 | rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal); | ||
| 4456 | |||
| 4457 | mutex_unlock(&ov->lock); | ||
| 4458 | return rc; | ||
| 4459 | } | ||
| 4460 | |||
| 4461 | static ssize_t | ||
| 4462 | ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos) | ||
| 4463 | { | ||
| 4464 | struct video_device *vdev = file->private_data; | ||
| 4465 | int noblock = file->f_flags&O_NONBLOCK; | ||
| 4466 | unsigned long count = cnt; | ||
| 4467 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
| 4468 | int i, rc = 0, frmx = -1; | ||
| 4469 | struct ov511_frame *frame; | ||
| 4470 | |||
| 4471 | if (mutex_lock_interruptible(&ov->lock)) | ||
| 4472 | return -EINTR; | ||
| 4473 | |||
| 4474 | PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); | ||
| 4475 | |||
| 4476 | if (!vdev || !buf) { | ||
| 4477 | rc = -EFAULT; | ||
| 4478 | goto error; | ||
| 4479 | } | ||
| 4480 | |||
| 4481 | if (!ov->dev) { | ||
| 4482 | rc = -EIO; | ||
| 4483 | goto error; | ||
| 4484 | } | ||
| 4485 | |||
| 4486 | // FIXME: Only supports two frames | ||
| 4487 | /* See if a frame is completed, then use it. */ | ||
| 4488 | if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ | ||
| 4489 | frmx = 0; | ||
| 4490 | else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ | ||
| 4491 | frmx = 1; | ||
| 4492 | |||
| 4493 | /* If nonblocking we return immediately */ | ||
| 4494 | if (noblock && (frmx == -1)) { | ||
| 4495 | rc = -EAGAIN; | ||
| 4496 | goto error; | ||
| 4497 | } | ||
| 4498 | |||
| 4499 | /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ | ||
| 4500 | /* See if a frame is in process (grabbing), then use it. */ | ||
| 4501 | if (frmx == -1) { | ||
| 4502 | if (ov->frame[0].grabstate == FRAME_GRABBING) | ||
| 4503 | frmx = 0; | ||
| 4504 | else if (ov->frame[1].grabstate == FRAME_GRABBING) | ||
| 4505 | frmx = 1; | ||
| 4506 | } | ||
| 4507 | |||
| 4508 | /* If no frame is active, start one. */ | ||
| 4509 | if (frmx == -1) { | ||
| 4510 | if ((rc = ov51x_new_frame(ov, frmx = 0))) { | ||
| 4511 | err("read: ov51x_new_frame error"); | ||
| 4512 | goto error; | ||
| 4513 | } | ||
| 4514 | } | ||
| 4515 | |||
| 4516 | frame = &ov->frame[frmx]; | ||
| 4517 | |||
| 4518 | restart: | ||
| 4519 | if (!ov->dev) { | ||
| 4520 | rc = -EIO; | ||
| 4521 | goto error; | ||
| 4522 | } | ||
| 4523 | |||
| 4524 | /* Wait while we're grabbing the image */ | ||
| 4525 | PDEBUG(4, "Waiting image grabbing"); | ||
| 4526 | rc = wait_event_interruptible(frame->wq, | ||
| 4527 | (frame->grabstate == FRAME_DONE) | ||
| 4528 | || (frame->grabstate == FRAME_ERROR)); | ||
| 4529 | |||
| 4530 | if (rc) | ||
| 4531 | goto error; | ||
| 4532 | |||
| 4533 | PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate); | ||
| 4534 | PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd); | ||
| 4535 | |||
| 4536 | if (frame->grabstate == FRAME_ERROR) { | ||
| 4537 | frame->bytes_read = 0; | ||
| 4538 | err("** ick! ** Errored frame %d", ov->curframe); | ||
| 4539 | if (ov51x_new_frame(ov, frmx)) { | ||
| 4540 | err("read: ov51x_new_frame error"); | ||
| 4541 | goto error; | ||
| 4542 | } | ||
| 4543 | goto restart; | ||
| 4544 | } | ||
| 4545 | |||
| 4546 | |||
| 4547 | /* Repeat until we get a snapshot frame */ | ||
| 4548 | if (ov->snap_enabled) | ||
| 4549 | PDEBUG(4, "Waiting snapshot frame"); | ||
| 4550 | if (ov->snap_enabled && !frame->snapshot) { | ||
| 4551 | frame->bytes_read = 0; | ||
| 4552 | if ((rc = ov51x_new_frame(ov, frmx))) { | ||
| 4553 | err("read: ov51x_new_frame error"); | ||
| 4554 | goto error; | ||
| 4555 | } | ||
| 4556 | goto restart; | ||
| 4557 | } | ||
| 4558 | |||
| 4559 | /* Clear the snapshot */ | ||
| 4560 | if (ov->snap_enabled && frame->snapshot) { | ||
| 4561 | frame->snapshot = 0; | ||
| 4562 | ov51x_clear_snapshot(ov); | ||
| 4563 | } | ||
| 4564 | |||
| 4565 | /* Decompression, format conversion, etc... */ | ||
| 4566 | ov51x_postprocess(ov, frame); | ||
| 4567 | |||
| 4568 | PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, | ||
| 4569 | frame->bytes_read, | ||
| 4570 | get_frame_length(frame)); | ||
| 4571 | |||
| 4572 | /* copy bytes to user space; we allow for partials reads */ | ||
| 4573 | // if ((count + frame->bytes_read) | ||
| 4574 | // > get_frame_length((struct ov511_frame *)frame)) | ||
| 4575 | // count = frame->scanlength - frame->bytes_read; | ||
| 4576 | |||
| 4577 | /* FIXME - count hardwired to be one frame... */ | ||
| 4578 | count = get_frame_length(frame); | ||
| 4579 | |||
| 4580 | PDEBUG(4, "Copy to user space: %ld bytes", count); | ||
| 4581 | if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) { | ||
| 4582 | PDEBUG(4, "Copy failed! %d bytes not copied", i); | ||
| 4583 | rc = -EFAULT; | ||
| 4584 | goto error; | ||
| 4585 | } | ||
| 4586 | |||
| 4587 | frame->bytes_read += count; | ||
| 4588 | PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld", | ||
| 4589 | count, frame->bytes_read); | ||
| 4590 | |||
| 4591 | /* If all data have been read... */ | ||
| 4592 | if (frame->bytes_read | ||
| 4593 | >= get_frame_length(frame)) { | ||
| 4594 | frame->bytes_read = 0; | ||
| 4595 | |||
| 4596 | // FIXME: Only supports two frames | ||
| 4597 | /* Mark it as available to be used again. */ | ||
| 4598 | ov->frame[frmx].grabstate = FRAME_UNUSED; | ||
| 4599 | if ((rc = ov51x_new_frame(ov, !frmx))) { | ||
| 4600 | err("ov51x_new_frame returned error"); | ||
| 4601 | goto error; | ||
| 4602 | } | ||
| 4603 | } | ||
| 4604 | |||
| 4605 | PDEBUG(4, "read finished, returning %ld (sweet)", count); | ||
| 4606 | |||
| 4607 | mutex_unlock(&ov->lock); | ||
| 4608 | return count; | ||
| 4609 | |||
| 4610 | error: | ||
| 4611 | mutex_unlock(&ov->lock); | ||
| 4612 | return rc; | ||
| 4613 | } | ||
| 4614 | |||
| 4615 | static int | ||
| 4616 | ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 4617 | { | ||
| 4618 | struct video_device *vdev = file->private_data; | ||
| 4619 | unsigned long start = vma->vm_start; | ||
| 4620 | unsigned long size = vma->vm_end - vma->vm_start; | ||
| 4621 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
| 4622 | unsigned long page, pos; | ||
| 4623 | |||
| 4624 | if (ov->dev == NULL) | ||
| 4625 | return -EIO; | ||
| 4626 | |||
| 4627 | PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); | ||
| 4628 | |||
| 4629 | if (size > (((OV511_NUMFRAMES | ||
| 4630 | * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight) | ||
| 4631 | + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) | ||
| 4632 | return -EINVAL; | ||
| 4633 | |||
| 4634 | if (mutex_lock_interruptible(&ov->lock)) | ||
| 4635 | return -EINTR; | ||
| 4636 | |||
| 4637 | pos = (unsigned long)ov->fbuf; | ||
| 4638 | while (size > 0) { | ||
| 4639 | page = vmalloc_to_pfn((void *)pos); | ||
| 4640 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | ||
| 4641 | mutex_unlock(&ov->lock); | ||
| 4642 | return -EAGAIN; | ||
| 4643 | } | ||
| 4644 | start += PAGE_SIZE; | ||
| 4645 | pos += PAGE_SIZE; | ||
| 4646 | if (size > PAGE_SIZE) | ||
| 4647 | size -= PAGE_SIZE; | ||
| 4648 | else | ||
| 4649 | size = 0; | ||
| 4650 | } | ||
| 4651 | |||
| 4652 | mutex_unlock(&ov->lock); | ||
| 4653 | return 0; | ||
| 4654 | } | ||
| 4655 | |||
| 4656 | static struct file_operations ov511_fops = { | ||
| 4657 | .owner = THIS_MODULE, | ||
| 4658 | .open = ov51x_v4l1_open, | ||
| 4659 | .release = ov51x_v4l1_close, | ||
| 4660 | .read = ov51x_v4l1_read, | ||
| 4661 | .mmap = ov51x_v4l1_mmap, | ||
| 4662 | .ioctl = ov51x_v4l1_ioctl, | ||
| 4663 | .compat_ioctl = v4l_compat_ioctl32, | ||
| 4664 | .llseek = no_llseek, | ||
| 4665 | }; | ||
| 4666 | |||
| 4667 | static struct video_device vdev_template = { | ||
| 4668 | .owner = THIS_MODULE, | ||
| 4669 | .name = "OV511 USB Camera", | ||
| 4670 | .type = VID_TYPE_CAPTURE, | ||
| 4671 | .hardware = VID_HARDWARE_OV511, | ||
| 4672 | .fops = &ov511_fops, | ||
| 4673 | .release = video_device_release, | ||
| 4674 | .minor = -1, | ||
| 4675 | }; | ||
| 4676 | |||
| 4677 | /**************************************************************************** | ||
| 4678 | * | ||
| 4679 | * OV511 and sensor configuration | ||
| 4680 | * | ||
| 4681 | ***************************************************************************/ | ||
| 4682 | |||
| 4683 | /* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses | ||
| 4684 | * the same register settings as the OV7610, since they are very similar. | ||
| 4685 | */ | ||
| 4686 | static int | ||
| 4687 | ov7xx0_configure(struct usb_ov511 *ov) | ||
| 4688 | { | ||
| 4689 | int i, success; | ||
| 4690 | int rc; | ||
| 4691 | |||
| 4692 | /* Lawrence Glaister <lg@jfm.bc.ca> reports: | ||
| 4693 | * | ||
| 4694 | * Register 0x0f in the 7610 has the following effects: | ||
| 4695 | * | ||
| 4696 | * 0x85 (AEC method 1): Best overall, good contrast range | ||
| 4697 | * 0x45 (AEC method 2): Very overexposed | ||
| 4698 | * 0xa5 (spec sheet default): Ok, but the black level is | ||
| 4699 | * shifted resulting in loss of contrast | ||
| 4700 | * 0x05 (old driver setting): very overexposed, too much | ||
| 4701 | * contrast | ||
| 4702 | */ | ||
| 4703 | static struct ov511_regvals aRegvalsNorm7610[] = { | ||
| 4704 | { OV511_I2C_BUS, 0x10, 0xff }, | ||
| 4705 | { OV511_I2C_BUS, 0x16, 0x06 }, | ||
| 4706 | { OV511_I2C_BUS, 0x28, 0x24 }, | ||
| 4707 | { OV511_I2C_BUS, 0x2b, 0xac }, | ||
| 4708 | { OV511_I2C_BUS, 0x12, 0x00 }, | ||
| 4709 | { OV511_I2C_BUS, 0x38, 0x81 }, | ||
| 4710 | { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */ | ||
| 4711 | { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ | ||
| 4712 | { OV511_I2C_BUS, 0x15, 0x01 }, | ||
| 4713 | { OV511_I2C_BUS, 0x20, 0x1c }, | ||
| 4714 | { OV511_I2C_BUS, 0x23, 0x2a }, | ||
| 4715 | { OV511_I2C_BUS, 0x24, 0x10 }, | ||
| 4716 | { OV511_I2C_BUS, 0x25, 0x8a }, | ||
| 4717 | { OV511_I2C_BUS, 0x26, 0xa2 }, | ||
| 4718 | { OV511_I2C_BUS, 0x27, 0xc2 }, | ||
| 4719 | { OV511_I2C_BUS, 0x2a, 0x04 }, | ||
| 4720 | { OV511_I2C_BUS, 0x2c, 0xfe }, | ||
| 4721 | { OV511_I2C_BUS, 0x2d, 0x93 }, | ||
| 4722 | { OV511_I2C_BUS, 0x30, 0x71 }, | ||
| 4723 | { OV511_I2C_BUS, 0x31, 0x60 }, | ||
| 4724 | { OV511_I2C_BUS, 0x32, 0x26 }, | ||
| 4725 | { OV511_I2C_BUS, 0x33, 0x20 }, | ||
| 4726 | { OV511_I2C_BUS, 0x34, 0x48 }, | ||
| 4727 | { OV511_I2C_BUS, 0x12, 0x24 }, | ||
| 4728 | { OV511_I2C_BUS, 0x11, 0x01 }, | ||
| 4729 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
| 4730 | { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
| 4731 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
| 4732 | }; | ||
| 4733 | |||
| 4734 | static struct ov511_regvals aRegvalsNorm7620[] = { | ||
| 4735 | { OV511_I2C_BUS, 0x00, 0x00 }, | ||
| 4736 | { OV511_I2C_BUS, 0x01, 0x80 }, | ||
| 4737 | { OV511_I2C_BUS, 0x02, 0x80 }, | ||
| 4738 | { OV511_I2C_BUS, 0x03, 0xc0 }, | ||
| 4739 | { OV511_I2C_BUS, 0x06, 0x60 }, | ||
| 4740 | { OV511_I2C_BUS, 0x07, 0x00 }, | ||
| 4741 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
| 4742 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
| 4743 | { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
| 4744 | { OV511_I2C_BUS, 0x11, 0x01 }, | ||
| 4745 | { OV511_I2C_BUS, 0x12, 0x24 }, | ||
| 4746 | { OV511_I2C_BUS, 0x13, 0x01 }, | ||
| 4747 | { OV511_I2C_BUS, 0x14, 0x84 }, | ||
| 4748 | { OV511_I2C_BUS, 0x15, 0x01 }, | ||
| 4749 | { OV511_I2C_BUS, 0x16, 0x03 }, | ||
| 4750 | { OV511_I2C_BUS, 0x17, 0x2f }, | ||
| 4751 | { OV511_I2C_BUS, 0x18, 0xcf }, | ||
| 4752 | { OV511_I2C_BUS, 0x19, 0x06 }, | ||
| 4753 | { OV511_I2C_BUS, 0x1a, 0xf5 }, | ||
| 4754 | { OV511_I2C_BUS, 0x1b, 0x00 }, | ||
| 4755 | { OV511_I2C_BUS, 0x20, 0x18 }, | ||
| 4756 | { OV511_I2C_BUS, 0x21, 0x80 }, | ||
| 4757 | { OV511_I2C_BUS, 0x22, 0x80 }, | ||
| 4758 | { OV511_I2C_BUS, 0x23, 0x00 }, | ||
| 4759 | { OV511_I2C_BUS, 0x26, 0xa2 }, | ||
| 4760 | { OV511_I2C_BUS, 0x27, 0xea }, | ||
| 4761 | { OV511_I2C_BUS, 0x28, 0x20 }, | ||
| 4762 | { OV511_I2C_BUS, 0x29, 0x00 }, | ||
| 4763 | { OV511_I2C_BUS, 0x2a, 0x10 }, | ||
| 4764 | { OV511_I2C_BUS, 0x2b, 0x00 }, | ||
| 4765 | { OV511_I2C_BUS, 0x2c, 0x88 }, | ||
| 4766 | { OV511_I2C_BUS, 0x2d, 0x91 }, | ||
| 4767 | { OV511_I2C_BUS, 0x2e, 0x80 }, | ||
| 4768 | { OV511_I2C_BUS, 0x2f, 0x44 }, | ||
| 4769 | { OV511_I2C_BUS, 0x60, 0x27 }, | ||
| 4770 | { OV511_I2C_BUS, 0x61, 0x02 }, | ||
| 4771 | { OV511_I2C_BUS, 0x62, 0x5f }, | ||
| 4772 | { OV511_I2C_BUS, 0x63, 0xd5 }, | ||
| 4773 | { OV511_I2C_BUS, 0x64, 0x57 }, | ||
| 4774 | { OV511_I2C_BUS, 0x65, 0x83 }, | ||
| 4775 | { OV511_I2C_BUS, 0x66, 0x55 }, | ||
| 4776 | { OV511_I2C_BUS, 0x67, 0x92 }, | ||
| 4777 | { OV511_I2C_BUS, 0x68, 0xcf }, | ||
| 4778 | { OV511_I2C_BUS, 0x69, 0x76 }, | ||
| 4779 | { OV511_I2C_BUS, 0x6a, 0x22 }, | ||
| 4780 | { OV511_I2C_BUS, 0x6b, 0x00 }, | ||
| 4781 | { OV511_I2C_BUS, 0x6c, 0x02 }, | ||
| 4782 | { OV511_I2C_BUS, 0x6d, 0x44 }, | ||
| 4783 | { OV511_I2C_BUS, 0x6e, 0x80 }, | ||
| 4784 | { OV511_I2C_BUS, 0x6f, 0x1d }, | ||
| 4785 | { OV511_I2C_BUS, 0x70, 0x8b }, | ||
| 4786 | { OV511_I2C_BUS, 0x71, 0x00 }, | ||
| 4787 | { OV511_I2C_BUS, 0x72, 0x14 }, | ||
| 4788 | { OV511_I2C_BUS, 0x73, 0x54 }, | ||
| 4789 | { OV511_I2C_BUS, 0x74, 0x00 }, | ||
| 4790 | { OV511_I2C_BUS, 0x75, 0x8e }, | ||
| 4791 | { OV511_I2C_BUS, 0x76, 0x00 }, | ||
| 4792 | { OV511_I2C_BUS, 0x77, 0xff }, | ||
| 4793 | { OV511_I2C_BUS, 0x78, 0x80 }, | ||
| 4794 | { OV511_I2C_BUS, 0x79, 0x80 }, | ||
| 4795 | { OV511_I2C_BUS, 0x7a, 0x80 }, | ||
| 4796 | { OV511_I2C_BUS, 0x7b, 0xe2 }, | ||
| 4797 | { OV511_I2C_BUS, 0x7c, 0x00 }, | ||
| 4798 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
| 4799 | }; | ||
| 4800 | |||
| 4801 | PDEBUG(4, "starting configuration"); | ||
| 4802 | |||
| 4803 | /* This looks redundant, but is necessary for WebCam 3 */ | ||
| 4804 | ov->primary_i2c_slave = OV7xx0_SID; | ||
| 4805 | if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) | ||
| 4806 | return -1; | ||
| 4807 | |||
| 4808 | if (init_ov_sensor(ov) >= 0) { | ||
| 4809 | PDEBUG(1, "OV7xx0 sensor initalized (method 1)"); | ||
| 4810 | } else { | ||
| 4811 | /* Reset the 76xx */ | ||
| 4812 | if (i2c_w(ov, 0x12, 0x80) < 0) | ||
| 4813 | return -1; | ||
| 4814 | |||
| 4815 | /* Wait for it to initialize */ | ||
| 4816 | msleep(150); | ||
| 4817 | |||
| 4818 | i = 0; | ||
| 4819 | success = 0; | ||
| 4820 | while (i <= i2c_detect_tries) { | ||
| 4821 | if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && | ||
| 4822 | (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { | ||
| 4823 | success = 1; | ||
| 4824 | break; | ||
| 4825 | } else { | ||
| 4826 | i++; | ||
| 4827 | } | ||
| 4828 | } | ||
| 4829 | |||
| 4830 | // Was (i == i2c_detect_tries) previously. This obviously used to always report | ||
| 4831 | // success. Whether anyone actually depended on that bug is unknown | ||
| 4832 | if ((i >= i2c_detect_tries) && (success == 0)) { | ||
| 4833 | err("Failed to read sensor ID. You might not have an"); | ||
| 4834 | err("OV7610/20, or it may be not responding. Report"); | ||
| 4835 | err("this to " EMAIL); | ||
| 4836 | err("This is only a warning. You can attempt to use"); | ||
| 4837 | err("your camera anyway"); | ||
| 4838 | // Only issue a warning for now | ||
| 4839 | // return -1; | ||
| 4840 | } else { | ||
| 4841 | PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1); | ||
| 4842 | } | ||
| 4843 | } | ||
| 4844 | |||
| 4845 | /* Detect sensor (sub)type */ | ||
| 4846 | rc = i2c_r(ov, OV7610_REG_COM_I); | ||
| 4847 | |||
| 4848 | if (rc < 0) { | ||
| 4849 | err("Error detecting sensor type"); | ||
| 4850 | return -1; | ||
| 4851 | } else if ((rc & 3) == 3) { | ||
| 4852 | info("Sensor is an OV7610"); | ||
| 4853 | ov->sensor = SEN_OV7610; | ||
| 4854 | } else if ((rc & 3) == 1) { | ||
| 4855 | /* I don't know what's different about the 76BE yet. */ | ||
| 4856 | if (i2c_r(ov, 0x15) & 1) | ||
| 4857 | info("Sensor is an OV7620AE"); | ||
| 4858 | else | ||
| 4859 | info("Sensor is an OV76BE"); | ||
| 4860 | |||
| 4861 | /* OV511+ will return all zero isoc data unless we | ||
| 4862 | * configure the sensor as a 7620. Someone needs to | ||
| 4863 | * find the exact reg. setting that causes this. */ | ||
| 4864 | if (ov->bridge == BRG_OV511PLUS) { | ||
| 4865 | info("Enabling 511+/7620AE workaround"); | ||
| 4866 | ov->sensor = SEN_OV7620; | ||
| 4867 | } else { | ||
| 4868 | ov->sensor = SEN_OV76BE; | ||
| 4869 | } | ||
| 4870 | } else if ((rc & 3) == 0) { | ||
| 4871 | info("Sensor is an OV7620"); | ||
| 4872 | ov->sensor = SEN_OV7620; | ||
| 4873 | } else { | ||
| 4874 | err("Unknown image sensor version: %d", rc & 3); | ||
| 4875 | return -1; | ||
| 4876 | } | ||
| 4877 | |||
| 4878 | if (ov->sensor == SEN_OV7620) { | ||
| 4879 | PDEBUG(4, "Writing 7620 registers"); | ||
| 4880 | if (write_regvals(ov, aRegvalsNorm7620)) | ||
| 4881 | return -1; | ||
| 4882 | } else { | ||
| 4883 | PDEBUG(4, "Writing 7610 registers"); | ||
| 4884 | if (write_regvals(ov, aRegvalsNorm7610)) | ||
| 4885 | return -1; | ||
| 4886 | } | ||
| 4887 | |||
| 4888 | /* Set sensor-specific vars */ | ||
| 4889 | ov->maxwidth = 640; | ||
| 4890 | ov->maxheight = 480; | ||
| 4891 | ov->minwidth = 64; | ||
| 4892 | ov->minheight = 48; | ||
| 4893 | |||
| 4894 | // FIXME: These do not match the actual settings yet | ||
| 4895 | ov->brightness = 0x80 << 8; | ||
| 4896 | ov->contrast = 0x80 << 8; | ||
| 4897 | ov->colour = 0x80 << 8; | ||
| 4898 | ov->hue = 0x80 << 8; | ||
| 4899 | |||
| 4900 | return 0; | ||
| 4901 | } | ||
| 4902 | |||
| 4903 | /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ | ||
| 4904 | static int | ||
| 4905 | ov6xx0_configure(struct usb_ov511 *ov) | ||
| 4906 | { | ||
| 4907 | int rc; | ||
| 4908 | |||
| 4909 | static struct ov511_regvals aRegvalsNorm6x20[] = { | ||
| 4910 | { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ | ||
| 4911 | { OV511_I2C_BUS, 0x11, 0x01 }, | ||
| 4912 | { OV511_I2C_BUS, 0x03, 0x60 }, | ||
| 4913 | { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ | ||
| 4914 | { OV511_I2C_BUS, 0x07, 0xa8 }, | ||
| 4915 | /* The ratio of 0x0c and 0x0d controls the white point */ | ||
| 4916 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
| 4917 | { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
| 4918 | { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */ | ||
| 4919 | { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */ | ||
| 4920 | { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ | ||
| 4921 | { OV511_I2C_BUS, 0x14, 0x04 }, | ||
| 4922 | /* 0x16: 0x06 helps frame stability with moving objects */ | ||
| 4923 | { OV511_I2C_BUS, 0x16, 0x06 }, | ||
| 4924 | // { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ | ||
| 4925 | { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ | ||
| 4926 | /* 0x28: 0x05 Selects RGB format if RGB on */ | ||
| 4927 | { OV511_I2C_BUS, 0x28, 0x05 }, | ||
| 4928 | { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ | ||
| 4929 | // { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ | ||
| 4930 | { OV511_I2C_BUS, 0x2d, 0x99 }, | ||
| 4931 | { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */ | ||
| 4932 | { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */ | ||
| 4933 | { OV511_I2C_BUS, 0x38, 0x8b }, | ||
| 4934 | { OV511_I2C_BUS, 0x39, 0x40 }, | ||
| 4935 | |||
| 4936 | { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ | ||
| 4937 | { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ | ||
| 4938 | { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ | ||
| 4939 | |||
| 4940 | { OV511_I2C_BUS, 0x3d, 0x80 }, | ||
| 4941 | /* These next two registers (0x4a, 0x4b) are undocumented. They | ||
| 4942 | * control the color balance */ | ||
| 4943 | { OV511_I2C_BUS, 0x4a, 0x80 }, | ||
| 4944 | { OV511_I2C_BUS, 0x4b, 0x80 }, | ||
| 4945 | { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */ | ||
| 4946 | { OV511_I2C_BUS, 0x4e, 0xc1 }, | ||
| 4947 | { OV511_I2C_BUS, 0x4f, 0x04 }, | ||
| 4948 | // Do 50-53 have any effect? | ||
| 4949 | // Toggle 0x12[2] off and on here? | ||
| 4950 | { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ | ||
| 4951 | }; | ||
| 4952 | |||
| 4953 | static struct ov511_regvals aRegvalsNorm6x30[] = { | ||
| 4954 | /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ | ||
| 4955 | { OV511_I2C_BUS, 0x11, 0x00 }, | ||
| 4956 | /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 }, | ||
| 4957 | /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ | ||
| 4958 | { OV511_I2C_BUS, 0x07, 0xa8 }, | ||
| 4959 | /* The ratio of 0x0c and 0x0d controls the white point */ | ||
| 4960 | /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
| 4961 | /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
| 4962 | /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 }, | ||
| 4963 | // /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 }, | ||
| 4964 | { OV511_I2C_BUS, 0x16, 0x03 }, | ||
| 4965 | // /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ | ||
| 4966 | // 21 & 22? The suggested values look wrong. Go with default | ||
| 4967 | /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 }, | ||
| 4968 | /*A*/ { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default | ||
| 4969 | // /*OK*/ { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ | ||
| 4970 | |||
| 4971 | /* 0x28: 0x05 Selects RGB format if RGB on */ | ||
| 4972 | // /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 }, | ||
| 4973 | // /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus | ||
| 4974 | |||
| 4975 | /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ | ||
| 4976 | // /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ | ||
| 4977 | { OV511_I2C_BUS, 0x2d, 0x99 }, | ||
| 4978 | // /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 | ||
| 4979 | // /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */ | ||
| 4980 | // /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 }, | ||
| 4981 | // /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7 | ||
| 4982 | // { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ | ||
| 4983 | // { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ | ||
| 4984 | // { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ | ||
| 4985 | { OV511_I2C_BUS, 0x3d, 0x80 }, | ||
| 4986 | // /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e }, | ||
| 4987 | |||
| 4988 | /* These next two registers (0x4a, 0x4b) are undocumented. They | ||
| 4989 | * control the color balance */ | ||
| 4990 | // /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these | ||
| 4991 | // /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 }, | ||
| 4992 | { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ | ||
| 4993 | /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 }, | ||
| 4994 | |||
| 4995 | /* UV average mode, color killer: strongest */ | ||
| 4996 | { OV511_I2C_BUS, 0x4f, 0x07 }, | ||
| 4997 | |||
| 4998 | { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */ | ||
| 4999 | { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */ | ||
| 5000 | { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */ | ||
| 5001 | { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */ | ||
| 5002 | { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */ | ||
| 5003 | // { OV511_I2C_BUS, 0x5c, 0x10 }, | ||
| 5004 | { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ | ||
| 5005 | }; | ||
| 5006 | |||
| 5007 | PDEBUG(4, "starting sensor configuration"); | ||
| 5008 | |||
| 5009 | if (init_ov_sensor(ov) < 0) { | ||
| 5010 | err("Failed to read sensor ID. You might not have an OV6xx0,"); | ||
| 5011 | err("or it may be not responding. Report this to " EMAIL); | ||
| 5012 | return -1; | ||
| 5013 | } else { | ||
| 5014 | PDEBUG(1, "OV6xx0 sensor detected"); | ||
| 5015 | } | ||
| 5016 | |||
| 5017 | /* Detect sensor (sub)type */ | ||
| 5018 | rc = i2c_r(ov, OV7610_REG_COM_I); | ||
| 5019 | |||
| 5020 | if (rc < 0) { | ||
| 5021 | err("Error detecting sensor type"); | ||
| 5022 | return -1; | ||
| 5023 | } | ||
| 5024 | |||
| 5025 | if ((rc & 3) == 0) { | ||
| 5026 | ov->sensor = SEN_OV6630; | ||
| 5027 | info("Sensor is an OV6630"); | ||
| 5028 | } else if ((rc & 3) == 1) { | ||
| 5029 | ov->sensor = SEN_OV6620; | ||
| 5030 | info("Sensor is an OV6620"); | ||
| 5031 | } else if ((rc & 3) == 2) { | ||
| 5032 | ov->sensor = SEN_OV6630; | ||
| 5033 | info("Sensor is an OV6630AE"); | ||
| 5034 | } else if ((rc & 3) == 3) { | ||
| 5035 | ov->sensor = SEN_OV6630; | ||
| 5036 | info("Sensor is an OV6630AF"); | ||
| 5037 | } | ||
| 5038 | |||
| 5039 | /* Set sensor-specific vars */ | ||
| 5040 | ov->maxwidth = 352; | ||
| 5041 | ov->maxheight = 288; | ||
| 5042 | ov->minwidth = 64; | ||
| 5043 | ov->minheight = 48; | ||
| 5044 | |||
| 5045 | // FIXME: These do not match the actual settings yet | ||
| 5046 | ov->brightness = 0x80 << 8; | ||
| 5047 | ov->contrast = 0x80 << 8; | ||
| 5048 | ov->colour = 0x80 << 8; | ||
| 5049 | ov->hue = 0x80 << 8; | ||
| 5050 | |||
| 5051 | if (ov->sensor == SEN_OV6620) { | ||
| 5052 | PDEBUG(4, "Writing 6x20 registers"); | ||
| 5053 | if (write_regvals(ov, aRegvalsNorm6x20)) | ||
| 5054 | return -1; | ||
| 5055 | } else { | ||
| 5056 | PDEBUG(4, "Writing 6x30 registers"); | ||
| 5057 | if (write_regvals(ov, aRegvalsNorm6x30)) | ||
| 5058 | return -1; | ||
| 5059 | } | ||
| 5060 | |||
| 5061 | return 0; | ||
| 5062 | } | ||
| 5063 | |||
| 5064 | /* This initializes the KS0127 and KS0127B video decoders. */ | ||
| 5065 | static int | ||
| 5066 | ks0127_configure(struct usb_ov511 *ov) | ||
| 5067 | { | ||
| 5068 | int rc; | ||
| 5069 | |||
| 5070 | // FIXME: I don't know how to sync or reset it yet | ||
| 5071 | #if 0 | ||
| 5072 | if (ov51x_init_ks_sensor(ov) < 0) { | ||
| 5073 | err("Failed to initialize the KS0127"); | ||
| 5074 | return -1; | ||
| 5075 | } else { | ||
| 5076 | PDEBUG(1, "KS012x(B) sensor detected"); | ||
| 5077 | } | ||
| 5078 | #endif | ||
| 5079 | |||
| 5080 | /* Detect decoder subtype */ | ||
| 5081 | rc = i2c_r(ov, 0x00); | ||
| 5082 | if (rc < 0) { | ||
| 5083 | err("Error detecting sensor type"); | ||
| 5084 | return -1; | ||
| 5085 | } else if (rc & 0x08) { | ||
| 5086 | rc = i2c_r(ov, 0x3d); | ||
| 5087 | if (rc < 0) { | ||
| 5088 | err("Error detecting sensor type"); | ||
| 5089 | return -1; | ||
| 5090 | } else if ((rc & 0x0f) == 0) { | ||
| 5091 | info("Sensor is a KS0127"); | ||
| 5092 | ov->sensor = SEN_KS0127; | ||
| 5093 | } else if ((rc & 0x0f) == 9) { | ||
| 5094 | info("Sensor is a KS0127B Rev. A"); | ||
| 5095 | ov->sensor = SEN_KS0127B; | ||
| 5096 | } | ||
| 5097 | } else { | ||
| 5098 | err("Error: Sensor is an unsupported KS0122"); | ||
| 5099 | return -1; | ||
| 5100 | } | ||
| 5101 | |||
| 5102 | /* Set sensor-specific vars */ | ||
| 5103 | ov->maxwidth = 640; | ||
| 5104 | ov->maxheight = 480; | ||
| 5105 | ov->minwidth = 64; | ||
| 5106 | ov->minheight = 48; | ||
| 5107 | |||
| 5108 | // FIXME: These do not match the actual settings yet | ||
| 5109 | ov->brightness = 0x80 << 8; | ||
| 5110 | ov->contrast = 0x80 << 8; | ||
| 5111 | ov->colour = 0x80 << 8; | ||
| 5112 | ov->hue = 0x80 << 8; | ||
| 5113 | |||
| 5114 | /* This device is not supported yet. Bail out now... */ | ||
| 5115 | err("This sensor is not supported yet."); | ||
| 5116 | return -1; | ||
| 5117 | |||
| 5118 | return 0; | ||
| 5119 | } | ||
| 5120 | |||
| 5121 | /* This initializes the SAA7111A video decoder. */ | ||
| 5122 | static int | ||
| 5123 | saa7111a_configure(struct usb_ov511 *ov) | ||
| 5124 | { | ||
| 5125 | int rc; | ||
| 5126 | |||
| 5127 | /* Since there is no register reset command, all registers must be | ||
| 5128 | * written, otherwise gives erratic results */ | ||
| 5129 | static struct ov511_regvals aRegvalsNormSAA7111A[] = { | ||
| 5130 | { OV511_I2C_BUS, 0x06, 0xce }, | ||
| 5131 | { OV511_I2C_BUS, 0x07, 0x00 }, | ||
| 5132 | { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */ | ||
| 5133 | { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */ | ||
| 5134 | { OV511_I2C_BUS, 0x00, 0x00 }, | ||
| 5135 | { OV511_I2C_BUS, 0x01, 0x00 }, | ||
| 5136 | { OV511_I2C_BUS, 0x03, 0x23 }, | ||
| 5137 | { OV511_I2C_BUS, 0x04, 0x00 }, | ||
| 5138 | { OV511_I2C_BUS, 0x05, 0x00 }, | ||
| 5139 | { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */ | ||
| 5140 | { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */ | ||
| 5141 | { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */ | ||
| 5142 | { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */ | ||
| 5143 | { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */ | ||
| 5144 | { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */ | ||
| 5145 | { OV511_I2C_BUS, 0x0f, 0x00 }, | ||
| 5146 | { OV511_I2C_BUS, 0x11, 0x0c }, | ||
| 5147 | { OV511_I2C_BUS, 0x12, 0x00 }, | ||
| 5148 | { OV511_I2C_BUS, 0x13, 0x00 }, | ||
| 5149 | { OV511_I2C_BUS, 0x14, 0x00 }, | ||
| 5150 | { OV511_I2C_BUS, 0x15, 0x00 }, | ||
| 5151 | { OV511_I2C_BUS, 0x16, 0x00 }, | ||
| 5152 | { OV511_I2C_BUS, 0x17, 0x00 }, | ||
| 5153 | { OV511_I2C_BUS, 0x02, 0xc0 }, /* Composite input 0 */ | ||
| 5154 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
| 5155 | }; | ||
| 5156 | |||
| 5157 | // FIXME: I don't know how to sync or reset it yet | ||
| 5158 | #if 0 | ||
| 5159 | if (ov51x_init_saa_sensor(ov) < 0) { | ||
| 5160 | err("Failed to initialize the SAA7111A"); | ||
| 5161 | return -1; | ||
| 5162 | } else { | ||
| 5163 | PDEBUG(1, "SAA7111A sensor detected"); | ||
| 5164 | } | ||
| 5165 | #endif | ||
| 5166 | |||
| 5167 | /* 640x480 not supported with PAL */ | ||
| 5168 | if (ov->pal) { | ||
| 5169 | ov->maxwidth = 320; | ||
| 5170 | ov->maxheight = 240; /* Even field only */ | ||
| 5171 | } else { | ||
| 5172 | ov->maxwidth = 640; | ||
| 5173 | ov->maxheight = 480; /* Even/Odd fields */ | ||
| 5174 | } | ||
| 5175 | |||
| 5176 | ov->minwidth = 320; | ||
| 5177 | ov->minheight = 240; /* Even field only */ | ||
| 5178 | |||
| 5179 | ov->has_decoder = 1; | ||
| 5180 | ov->num_inputs = 8; | ||
| 5181 | ov->norm = VIDEO_MODE_AUTO; | ||
| 5182 | ov->stop_during_set = 0; /* Decoder guarantees stable image */ | ||
| 5183 | |||
| 5184 | /* Decoder doesn't change these values, so we use these instead of | ||
| 5185 | * acutally reading the registers (which doesn't work) */ | ||
| 5186 | ov->brightness = 0x80 << 8; | ||
| 5187 | ov->contrast = 0x40 << 9; | ||
| 5188 | ov->colour = 0x40 << 9; | ||
| 5189 | ov->hue = 32768; | ||
| 5190 | |||
| 5191 | PDEBUG(4, "Writing SAA7111A registers"); | ||
| 5192 | if (write_regvals(ov, aRegvalsNormSAA7111A)) | ||
| 5193 | return -1; | ||
| 5194 | |||
| 5195 | /* Detect version of decoder. This must be done after writing the | ||
| 5196 | * initial regs or the decoder will lock up. */ | ||
| 5197 | rc = i2c_r(ov, 0x00); | ||
| 5198 | |||
| 5199 | if (rc < 0) { | ||
| 5200 | err("Error detecting sensor version"); | ||
| 5201 | return -1; | ||
| 5202 | } else { | ||
| 5203 | info("Sensor is an SAA7111A (version 0x%x)", rc); | ||
| 5204 | ov->sensor = SEN_SAA7111A; | ||
| 5205 | } | ||
| 5206 | |||
| 5207 | // FIXME: Fix this for OV518(+) | ||
| 5208 | /* Latch to negative edge of clock. Otherwise, we get incorrect | ||
| 5209 | * colors and jitter in the digital signal. */ | ||
| 5210 | if (ov->bclass == BCL_OV511) | ||
| 5211 | reg_w(ov, 0x11, 0x00); | ||
| 5212 | else | ||
| 5213 | warn("SAA7111A not yet supported with OV518/OV518+"); | ||
| 5214 | |||
| 5215 | return 0; | ||
| 5216 | } | ||
| 5217 | |||
| 5218 | /* This initializes the OV511/OV511+ and the sensor */ | ||
| 5219 | static int | ||
| 5220 | ov511_configure(struct usb_ov511 *ov) | ||
| 5221 | { | ||
| 5222 | static struct ov511_regvals aRegvalsInit511[] = { | ||
| 5223 | { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, | ||
| 5224 | { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, | ||
| 5225 | { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, | ||
| 5226 | { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, | ||
| 5227 | { OV511_REG_BUS, R51x_SYS_RESET, 0x3f }, | ||
| 5228 | { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, | ||
| 5229 | { OV511_REG_BUS, R51x_SYS_RESET, 0x3d }, | ||
| 5230 | { OV511_DONE_BUS, 0x0, 0x00}, | ||
| 5231 | }; | ||
| 5232 | |||
| 5233 | static struct ov511_regvals aRegvalsNorm511[] = { | ||
| 5234 | { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, | ||
| 5235 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
| 5236 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, | ||
| 5237 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
| 5238 | { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, | ||
| 5239 | { OV511_REG_BUS, R511_COMP_EN, 0x00 }, | ||
| 5240 | { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, | ||
| 5241 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
| 5242 | }; | ||
| 5243 | |||
| 5244 | static struct ov511_regvals aRegvalsNorm511Plus[] = { | ||
| 5245 | { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, | ||
| 5246 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
| 5247 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, | ||
| 5248 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
| 5249 | { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, | ||
| 5250 | { OV511_REG_BUS, R511_COMP_EN, 0x00 }, | ||
| 5251 | { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, | ||
| 5252 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
| 5253 | }; | ||
| 5254 | |||
| 5255 | PDEBUG(4, ""); | ||
| 5256 | |||
| 5257 | ov->customid = reg_r(ov, R511_SYS_CUST_ID); | ||
| 5258 | if (ov->customid < 0) { | ||
| 5259 | err("Unable to read camera bridge registers"); | ||
| 5260 | goto error; | ||
| 5261 | } | ||
| 5262 | |||
| 5263 | PDEBUG (1, "CustomID = %d", ov->customid); | ||
| 5264 | ov->desc = symbolic(camlist, ov->customid); | ||
| 5265 | info("model: %s", ov->desc); | ||
| 5266 | |||
| 5267 | if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) { | ||
| 5268 | err("Camera type (%d) not recognized", ov->customid); | ||
| 5269 | err("Please notify " EMAIL " of the name,"); | ||
| 5270 | err("manufacturer, model, and this number of your camera."); | ||
| 5271 | err("Also include the output of the detection process."); | ||
| 5272 | } | ||
| 5273 | |||
| 5274 | if (ov->customid == 70) /* USB Life TV (PAL/SECAM) */ | ||
| 5275 | ov->pal = 1; | ||
| 5276 | |||
| 5277 | if (write_regvals(ov, aRegvalsInit511)) | ||
| 5278 | goto error; | ||
| 5279 | |||
| 5280 | if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) | ||
| 5281 | ov51x_led_control(ov, 0); | ||
| 5282 | |||
| 5283 | /* The OV511+ has undocumented bits in the flow control register. | ||
| 5284 | * Setting it to 0xff fixes the corruption with moving objects. */ | ||
| 5285 | if (ov->bridge == BRG_OV511) { | ||
| 5286 | if (write_regvals(ov, aRegvalsNorm511)) | ||
| 5287 | goto error; | ||
| 5288 | } else if (ov->bridge == BRG_OV511PLUS) { | ||
| 5289 | if (write_regvals(ov, aRegvalsNorm511Plus)) | ||
| 5290 | goto error; | ||
| 5291 | } else { | ||
| 5292 | err("Invalid bridge"); | ||
| 5293 | } | ||
| 5294 | |||
| 5295 | if (ov511_init_compression(ov)) | ||
| 5296 | goto error; | ||
| 5297 | |||
| 5298 | ov->packet_numbering = 1; | ||
| 5299 | ov511_set_packet_size(ov, 0); | ||
| 5300 | |||
| 5301 | ov->snap_enabled = snapshot; | ||
| 5302 | |||
| 5303 | /* Test for 7xx0 */ | ||
| 5304 | PDEBUG(3, "Testing for 0V7xx0"); | ||
| 5305 | ov->primary_i2c_slave = OV7xx0_SID; | ||
| 5306 | if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) | ||
| 5307 | goto error; | ||
| 5308 | |||
| 5309 | if (i2c_w(ov, 0x12, 0x80) < 0) { | ||
| 5310 | /* Test for 6xx0 */ | ||
| 5311 | PDEBUG(3, "Testing for 0V6xx0"); | ||
| 5312 | ov->primary_i2c_slave = OV6xx0_SID; | ||
| 5313 | if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) | ||
| 5314 | goto error; | ||
| 5315 | |||
| 5316 | if (i2c_w(ov, 0x12, 0x80) < 0) { | ||
| 5317 | /* Test for 8xx0 */ | ||
| 5318 | PDEBUG(3, "Testing for 0V8xx0"); | ||
| 5319 | ov->primary_i2c_slave = OV8xx0_SID; | ||
| 5320 | if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) | ||
| 5321 | goto error; | ||
| 5322 | |||
| 5323 | if (i2c_w(ov, 0x12, 0x80) < 0) { | ||
| 5324 | /* Test for SAA7111A */ | ||
| 5325 | PDEBUG(3, "Testing for SAA7111A"); | ||
| 5326 | ov->primary_i2c_slave = SAA7111A_SID; | ||
| 5327 | if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0) | ||
| 5328 | goto error; | ||
| 5329 | |||
| 5330 | if (i2c_w(ov, 0x0d, 0x00) < 0) { | ||
| 5331 | /* Test for KS0127 */ | ||
| 5332 | PDEBUG(3, "Testing for KS0127"); | ||
| 5333 | ov->primary_i2c_slave = KS0127_SID; | ||
| 5334 | if (ov51x_set_slave_ids(ov, KS0127_SID) < 0) | ||
| 5335 | goto error; | ||
| 5336 | |||
| 5337 | if (i2c_w(ov, 0x10, 0x00) < 0) { | ||
| 5338 | err("Can't determine sensor slave IDs"); | ||
| 5339 | goto error; | ||
| 5340 | } else { | ||
| 5341 | if (ks0127_configure(ov) < 0) { | ||
| 5342 | err("Failed to configure KS0127"); | ||
| 5343 | goto error; | ||
| 5344 | } | ||
| 5345 | } | ||
| 5346 | } else { | ||
| 5347 | if (saa7111a_configure(ov) < 0) { | ||
| 5348 | err("Failed to configure SAA7111A"); | ||
| 5349 | goto error; | ||
| 5350 | } | ||
| 5351 | } | ||
| 5352 | } else { | ||
| 5353 | err("Detected unsupported OV8xx0 sensor"); | ||
| 5354 | goto error; | ||
| 5355 | } | ||
| 5356 | } else { | ||
| 5357 | if (ov6xx0_configure(ov) < 0) { | ||
| 5358 | err("Failed to configure OV6xx0"); | ||
| 5359 | goto error; | ||
| 5360 | } | ||
| 5361 | } | ||
| 5362 | } else { | ||
| 5363 | if (ov7xx0_configure(ov) < 0) { | ||
| 5364 | err("Failed to configure OV7xx0"); | ||
| 5365 | goto error; | ||
| 5366 | } | ||
| 5367 | } | ||
| 5368 | |||
| 5369 | return 0; | ||
| 5370 | |||
| 5371 | error: | ||
| 5372 | err("OV511 Config failed"); | ||
| 5373 | |||
| 5374 | return -EBUSY; | ||
| 5375 | } | ||
| 5376 | |||
| 5377 | /* This initializes the OV518/OV518+ and the sensor */ | ||
| 5378 | static int | ||
| 5379 | ov518_configure(struct usb_ov511 *ov) | ||
| 5380 | { | ||
| 5381 | /* For 518 and 518+ */ | ||
| 5382 | static struct ov511_regvals aRegvalsInit518[] = { | ||
| 5383 | { OV511_REG_BUS, R51x_SYS_RESET, 0x40 }, | ||
| 5384 | { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, | ||
| 5385 | { OV511_REG_BUS, R51x_SYS_RESET, 0x3e }, | ||
| 5386 | { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, | ||
| 5387 | { OV511_REG_BUS, R51x_SYS_RESET, 0x00 }, | ||
| 5388 | { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, | ||
| 5389 | { OV511_REG_BUS, 0x46, 0x00 }, | ||
| 5390 | { OV511_REG_BUS, 0x5d, 0x03 }, | ||
| 5391 | { OV511_DONE_BUS, 0x0, 0x00}, | ||
| 5392 | }; | ||
| 5393 | |||
| 5394 | static struct ov511_regvals aRegvalsNorm518[] = { | ||
| 5395 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ | ||
| 5396 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ | ||
| 5397 | { OV511_REG_BUS, 0x31, 0x0f }, | ||
| 5398 | { OV511_REG_BUS, 0x5d, 0x03 }, | ||
| 5399 | { OV511_REG_BUS, 0x24, 0x9f }, | ||
| 5400 | { OV511_REG_BUS, 0x25, 0x90 }, | ||
| 5401 | { OV511_REG_BUS, 0x20, 0x00 }, | ||
| 5402 | { OV511_REG_BUS, 0x51, 0x04 }, | ||
| 5403 | { OV511_REG_BUS, 0x71, 0x19 }, | ||
| 5404 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
| 5405 | }; | ||
| 5406 | |||
| 5407 | static struct ov511_regvals aRegvalsNorm518Plus[] = { | ||
| 5408 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ | ||
| 5409 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ | ||
| 5410 | { OV511_REG_BUS, 0x31, 0x0f }, | ||
| 5411 | { OV511_REG_BUS, 0x5d, 0x03 }, | ||
| 5412 | { OV511_REG_BUS, 0x24, 0x9f }, | ||
| 5413 | { OV511_REG_BUS, 0x25, 0x90 }, | ||
| 5414 | { OV511_REG_BUS, 0x20, 0x60 }, | ||
| 5415 | { OV511_REG_BUS, 0x51, 0x02 }, | ||
| 5416 | { OV511_REG_BUS, 0x71, 0x19 }, | ||
| 5417 | { OV511_REG_BUS, 0x40, 0xff }, | ||
| 5418 | { OV511_REG_BUS, 0x41, 0x42 }, | ||
| 5419 | { OV511_REG_BUS, 0x46, 0x00 }, | ||
| 5420 | { OV511_REG_BUS, 0x33, 0x04 }, | ||
| 5421 | { OV511_REG_BUS, 0x21, 0x19 }, | ||
| 5422 | { OV511_REG_BUS, 0x3f, 0x10 }, | ||
| 5423 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
| 5424 | }; | ||
| 5425 | |||
| 5426 | PDEBUG(4, ""); | ||
| 5427 | |||
| 5428 | /* First 5 bits of custom ID reg are a revision ID on OV518 */ | ||
| 5429 | info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); | ||
| 5430 | |||
| 5431 | /* Give it the default description */ | ||
| 5432 | ov->desc = symbolic(camlist, 0); | ||
| 5433 | |||
| 5434 | if (write_regvals(ov, aRegvalsInit518)) | ||
| 5435 | goto error; | ||
| 5436 | |||
| 5437 | /* Set LED GPIO pin to output mode */ | ||
| 5438 | if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) | ||
| 5439 | goto error; | ||
| 5440 | |||
| 5441 | /* LED is off by default with OV518; have to explicitly turn it on */ | ||
| 5442 | if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) | ||
| 5443 | ov51x_led_control(ov, 0); | ||
| 5444 | else | ||
| 5445 | ov51x_led_control(ov, 1); | ||
| 5446 | |||
| 5447 | /* Don't require compression if dumppix is enabled; otherwise it's | ||
| 5448 | * required. OV518 has no uncompressed mode, to save RAM. */ | ||
| 5449 | if (!dumppix && !ov->compress) { | ||
| 5450 | ov->compress = 1; | ||
| 5451 | warn("Compression required with OV518...enabling"); | ||
| 5452 | } | ||
| 5453 | |||
| 5454 | if (ov->bridge == BRG_OV518) { | ||
| 5455 | if (write_regvals(ov, aRegvalsNorm518)) | ||
| 5456 | goto error; | ||
| 5457 | } else if (ov->bridge == BRG_OV518PLUS) { | ||
| 5458 | if (write_regvals(ov, aRegvalsNorm518Plus)) | ||
| 5459 | goto error; | ||
| 5460 | } else { | ||
| 5461 | err("Invalid bridge"); | ||
| 5462 | } | ||
| 5463 | |||
| 5464 | if (reg_w(ov, 0x2f, 0x80) < 0) | ||
| 5465 | goto error; | ||
| 5466 | |||
| 5467 | if (ov518_init_compression(ov)) | ||
| 5468 | goto error; | ||
| 5469 | |||
| 5470 | if (ov->bridge == BRG_OV518) | ||
| 5471 | { | ||
| 5472 | struct usb_interface *ifp; | ||
| 5473 | struct usb_host_interface *alt; | ||
| 5474 | __u16 mxps = 0; | ||
| 5475 | |||
| 5476 | ifp = usb_ifnum_to_if(ov->dev, 0); | ||
| 5477 | if (ifp) { | ||
| 5478 | alt = usb_altnum_to_altsetting(ifp, 7); | ||
| 5479 | if (alt) | ||
| 5480 | mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | ||
| 5481 | } | ||
| 5482 | |||
| 5483 | /* Some OV518s have packet numbering by default, some don't */ | ||
| 5484 | if (mxps == 897) | ||
| 5485 | ov->packet_numbering = 1; | ||
| 5486 | else | ||
| 5487 | ov->packet_numbering = 0; | ||
| 5488 | } else { | ||
| 5489 | /* OV518+ has packet numbering turned on by default */ | ||
| 5490 | ov->packet_numbering = 1; | ||
| 5491 | } | ||
| 5492 | |||
| 5493 | ov518_set_packet_size(ov, 0); | ||
| 5494 | |||
| 5495 | ov->snap_enabled = snapshot; | ||
| 5496 | |||
| 5497 | /* Test for 76xx */ | ||
| 5498 | ov->primary_i2c_slave = OV7xx0_SID; | ||
| 5499 | if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) | ||
| 5500 | goto error; | ||
| 5501 | |||
| 5502 | /* The OV518 must be more aggressive about sensor detection since | ||
| 5503 | * I2C write will never fail if the sensor is not present. We have | ||
| 5504 | * to try to initialize the sensor to detect its presence */ | ||
| 5505 | |||
| 5506 | if (init_ov_sensor(ov) < 0) { | ||
| 5507 | /* Test for 6xx0 */ | ||
| 5508 | ov->primary_i2c_slave = OV6xx0_SID; | ||
| 5509 | if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) | ||
| 5510 | goto error; | ||
| 5511 | |||
| 5512 | if (init_ov_sensor(ov) < 0) { | ||
| 5513 | /* Test for 8xx0 */ | ||
| 5514 | ov->primary_i2c_slave = OV8xx0_SID; | ||
| 5515 | if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) | ||
| 5516 | goto error; | ||
| 5517 | |||
| 5518 | if (init_ov_sensor(ov) < 0) { | ||
| 5519 | err("Can't determine sensor slave IDs"); | ||
| 5520 | goto error; | ||
| 5521 | } else { | ||
| 5522 | err("Detected unsupported OV8xx0 sensor"); | ||
| 5523 | goto error; | ||
| 5524 | } | ||
| 5525 | } else { | ||
| 5526 | if (ov6xx0_configure(ov) < 0) { | ||
| 5527 | err("Failed to configure OV6xx0"); | ||
| 5528 | goto error; | ||
| 5529 | } | ||
| 5530 | } | ||
| 5531 | } else { | ||
| 5532 | if (ov7xx0_configure(ov) < 0) { | ||
| 5533 | err("Failed to configure OV7xx0"); | ||
| 5534 | goto error; | ||
| 5535 | } | ||
| 5536 | } | ||
| 5537 | |||
| 5538 | ov->maxwidth = 352; | ||
| 5539 | ov->maxheight = 288; | ||
| 5540 | |||
| 5541 | // The OV518 cannot go as low as the sensor can | ||
| 5542 | ov->minwidth = 160; | ||
| 5543 | ov->minheight = 120; | ||
| 5544 | |||
| 5545 | return 0; | ||
| 5546 | |||
| 5547 | error: | ||
| 5548 | err("OV518 Config failed"); | ||
| 5549 | |||
| 5550 | return -EBUSY; | ||
| 5551 | } | ||
| 5552 | |||
| 5553 | /**************************************************************************** | ||
| 5554 | * sysfs | ||
| 5555 | ***************************************************************************/ | ||
| 5556 | |||
| 5557 | static inline struct usb_ov511 *cd_to_ov(struct class_device *cd) | ||
| 5558 | { | ||
| 5559 | struct video_device *vdev = to_video_device(cd); | ||
| 5560 | return video_get_drvdata(vdev); | ||
| 5561 | } | ||
| 5562 | |||
| 5563 | static ssize_t show_custom_id(struct class_device *cd, char *buf) | ||
| 5564 | { | ||
| 5565 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
| 5566 | return sprintf(buf, "%d\n", ov->customid); | ||
| 5567 | } | ||
| 5568 | static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); | ||
| 5569 | |||
| 5570 | static ssize_t show_model(struct class_device *cd, char *buf) | ||
| 5571 | { | ||
| 5572 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
| 5573 | return sprintf(buf, "%s\n", ov->desc); | ||
| 5574 | } | ||
| 5575 | static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); | ||
| 5576 | |||
| 5577 | static ssize_t show_bridge(struct class_device *cd, char *buf) | ||
| 5578 | { | ||
| 5579 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
| 5580 | return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge)); | ||
| 5581 | } | ||
| 5582 | static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); | ||
| 5583 | |||
| 5584 | static ssize_t show_sensor(struct class_device *cd, char *buf) | ||
| 5585 | { | ||
| 5586 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
| 5587 | return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor)); | ||
| 5588 | } | ||
| 5589 | static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); | ||
| 5590 | |||
| 5591 | static ssize_t show_brightness(struct class_device *cd, char *buf) | ||
| 5592 | { | ||
| 5593 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
| 5594 | unsigned short x; | ||
| 5595 | |||
| 5596 | if (!ov->dev) | ||
| 5597 | return -ENODEV; | ||
| 5598 | sensor_get_brightness(ov, &x); | ||
| 5599 | return sprintf(buf, "%d\n", x >> 8); | ||
| 5600 | } | ||
| 5601 | static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); | ||
| 5602 | |||
| 5603 | static ssize_t show_saturation(struct class_device *cd, char *buf) | ||
| 5604 | { | ||
| 5605 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
| 5606 | unsigned short x; | ||
| 5607 | |||
| 5608 | if (!ov->dev) | ||
| 5609 | return -ENODEV; | ||
| 5610 | sensor_get_saturation(ov, &x); | ||
| 5611 | return sprintf(buf, "%d\n", x >> 8); | ||
| 5612 | } | ||
| 5613 | static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); | ||
| 5614 | |||
| 5615 | static ssize_t show_contrast(struct class_device *cd, char *buf) | ||
| 5616 | { | ||
| 5617 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
| 5618 | unsigned short x; | ||
| 5619 | |||
| 5620 | if (!ov->dev) | ||
| 5621 | return -ENODEV; | ||
| 5622 | sensor_get_contrast(ov, &x); | ||
| 5623 | return sprintf(buf, "%d\n", x >> 8); | ||
| 5624 | } | ||
| 5625 | static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); | ||
| 5626 | |||
| 5627 | static ssize_t show_hue(struct class_device *cd, char *buf) | ||
| 5628 | { | ||
| 5629 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
| 5630 | unsigned short x; | ||
| 5631 | |||
| 5632 | if (!ov->dev) | ||
| 5633 | return -ENODEV; | ||
| 5634 | sensor_get_hue(ov, &x); | ||
| 5635 | return sprintf(buf, "%d\n", x >> 8); | ||
| 5636 | } | ||
| 5637 | static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); | ||
| 5638 | |||
| 5639 | static ssize_t show_exposure(struct class_device *cd, char *buf) | ||
| 5640 | { | ||
| 5641 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
| 5642 | unsigned char exp = 0; | ||
| 5643 | |||
| 5644 | if (!ov->dev) | ||
| 5645 | return -ENODEV; | ||
| 5646 | sensor_get_exposure(ov, &exp); | ||
| 5647 | return sprintf(buf, "%d\n", exp >> 8); | ||
| 5648 | } | ||
| 5649 | static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); | ||
| 5650 | |||
| 5651 | static void ov_create_sysfs(struct video_device *vdev) | ||
| 5652 | { | ||
| 5653 | video_device_create_file(vdev, &class_device_attr_custom_id); | ||
| 5654 | video_device_create_file(vdev, &class_device_attr_model); | ||
| 5655 | video_device_create_file(vdev, &class_device_attr_bridge); | ||
| 5656 | video_device_create_file(vdev, &class_device_attr_sensor); | ||
| 5657 | video_device_create_file(vdev, &class_device_attr_brightness); | ||
| 5658 | video_device_create_file(vdev, &class_device_attr_saturation); | ||
| 5659 | video_device_create_file(vdev, &class_device_attr_contrast); | ||
| 5660 | video_device_create_file(vdev, &class_device_attr_hue); | ||
| 5661 | video_device_create_file(vdev, &class_device_attr_exposure); | ||
| 5662 | } | ||
| 5663 | |||
| 5664 | /**************************************************************************** | ||
| 5665 | * USB routines | ||
| 5666 | ***************************************************************************/ | ||
| 5667 | |||
| 5668 | static int | ||
| 5669 | ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
| 5670 | { | ||
| 5671 | struct usb_device *dev = interface_to_usbdev(intf); | ||
| 5672 | struct usb_interface_descriptor *idesc; | ||
| 5673 | struct usb_ov511 *ov; | ||
| 5674 | int i; | ||
| 5675 | |||
| 5676 | PDEBUG(1, "probing for device..."); | ||
| 5677 | |||
| 5678 | /* We don't handle multi-config cameras */ | ||
| 5679 | if (dev->descriptor.bNumConfigurations != 1) | ||
| 5680 | return -ENODEV; | ||
| 5681 | |||
| 5682 | idesc = &intf->cur_altsetting->desc; | ||
| 5683 | |||
| 5684 | if (idesc->bInterfaceClass != 0xFF) | ||
| 5685 | return -ENODEV; | ||
| 5686 | if (idesc->bInterfaceSubClass != 0x00) | ||
| 5687 | return -ENODEV; | ||
| 5688 | |||
| 5689 | if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { | ||
| 5690 | err("couldn't kmalloc ov struct"); | ||
| 5691 | goto error_out; | ||
| 5692 | } | ||
| 5693 | |||
| 5694 | ov->dev = dev; | ||
| 5695 | ov->iface = idesc->bInterfaceNumber; | ||
| 5696 | ov->led_policy = led; | ||
| 5697 | ov->compress = compress; | ||
| 5698 | ov->lightfreq = lightfreq; | ||
| 5699 | ov->num_inputs = 1; /* Video decoder init functs. change this */ | ||
| 5700 | ov->stop_during_set = !fastset; | ||
| 5701 | ov->backlight = backlight; | ||
| 5702 | ov->mirror = mirror; | ||
| 5703 | ov->auto_brt = autobright; | ||
| 5704 | ov->auto_gain = autogain; | ||
| 5705 | ov->auto_exp = autoexp; | ||
| 5706 | |||
| 5707 | switch (le16_to_cpu(dev->descriptor.idProduct)) { | ||
| 5708 | case PROD_OV511: | ||
| 5709 | ov->bridge = BRG_OV511; | ||
| 5710 | ov->bclass = BCL_OV511; | ||
| 5711 | break; | ||
| 5712 | case PROD_OV511PLUS: | ||
| 5713 | ov->bridge = BRG_OV511PLUS; | ||
| 5714 | ov->bclass = BCL_OV511; | ||
| 5715 | break; | ||
| 5716 | case PROD_OV518: | ||
| 5717 | ov->bridge = BRG_OV518; | ||
| 5718 | ov->bclass = BCL_OV518; | ||
| 5719 | break; | ||
| 5720 | case PROD_OV518PLUS: | ||
| 5721 | ov->bridge = BRG_OV518PLUS; | ||
| 5722 | ov->bclass = BCL_OV518; | ||
| 5723 | break; | ||
| 5724 | case PROD_ME2CAM: | ||
| 5725 | if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL) | ||
| 5726 | goto error; | ||
| 5727 | ov->bridge = BRG_OV511PLUS; | ||
| 5728 | ov->bclass = BCL_OV511; | ||
| 5729 | break; | ||
| 5730 | default: | ||
| 5731 | err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct)); | ||
| 5732 | goto error; | ||
| 5733 | } | ||
| 5734 | |||
| 5735 | info("USB %s video device found", symbolic(brglist, ov->bridge)); | ||
| 5736 | |||
| 5737 | init_waitqueue_head(&ov->wq); | ||
| 5738 | |||
| 5739 | mutex_init(&ov->lock); /* to 1 == available */ | ||
| 5740 | mutex_init(&ov->buf_lock); | ||
| 5741 | mutex_init(&ov->i2c_lock); | ||
| 5742 | mutex_init(&ov->cbuf_lock); | ||
| 5743 | |||
| 5744 | ov->buf_state = BUF_NOT_ALLOCATED; | ||
| 5745 | |||
| 5746 | if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) { | ||
| 5747 | err("usb_make_path error"); | ||
| 5748 | goto error; | ||
| 5749 | } | ||
| 5750 | |||
| 5751 | /* Allocate control transfer buffer. */ | ||
| 5752 | /* Must be kmalloc()'ed, for DMA compatibility */ | ||
| 5753 | ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); | ||
| 5754 | if (!ov->cbuf) | ||
| 5755 | goto error; | ||
| 5756 | |||
| 5757 | if (ov->bclass == BCL_OV518) { | ||
| 5758 | if (ov518_configure(ov) < 0) | ||
| 5759 | goto error; | ||
| 5760 | } else { | ||
| 5761 | if (ov511_configure(ov) < 0) | ||
| 5762 | goto error; | ||
| 5763 | } | ||
| 5764 | |||
| 5765 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
| 5766 | ov->frame[i].framenum = i; | ||
| 5767 | init_waitqueue_head(&ov->frame[i].wq); | ||
| 5768 | } | ||
| 5769 | |||
| 5770 | for (i = 0; i < OV511_NUMSBUF; i++) { | ||
| 5771 | ov->sbuf[i].ov = ov; | ||
| 5772 | spin_lock_init(&ov->sbuf[i].lock); | ||
| 5773 | ov->sbuf[i].n = i; | ||
| 5774 | } | ||
| 5775 | |||
| 5776 | /* Unnecessary? (This is done on open(). Need to make sure variables | ||
| 5777 | * are properly initialized without this before removing it, though). */ | ||
| 5778 | if (ov51x_set_default_params(ov) < 0) | ||
| 5779 | goto error; | ||
| 5780 | |||
| 5781 | #ifdef OV511_DEBUG | ||
| 5782 | if (dump_bridge) { | ||
| 5783 | if (ov->bclass == BCL_OV511) | ||
| 5784 | ov511_dump_regs(ov); | ||
| 5785 | else | ||
| 5786 | ov518_dump_regs(ov); | ||
| 5787 | } | ||
| 5788 | #endif | ||
| 5789 | |||
| 5790 | ov->vdev = video_device_alloc(); | ||
| 5791 | if (!ov->vdev) | ||
| 5792 | goto error; | ||
| 5793 | |||
| 5794 | memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev)); | ||
| 5795 | ov->vdev->dev = &dev->dev; | ||
| 5796 | video_set_drvdata(ov->vdev, ov); | ||
| 5797 | |||
| 5798 | for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { | ||
| 5799 | /* Minor 0 cannot be specified; assume user wants autodetect */ | ||
| 5800 | if (unit_video[i] == 0) | ||
| 5801 | break; | ||
| 5802 | |||
| 5803 | if (video_register_device(ov->vdev, VFL_TYPE_GRABBER, | ||
| 5804 | unit_video[i]) >= 0) { | ||
| 5805 | break; | ||
| 5806 | } | ||
| 5807 | } | ||
| 5808 | |||
| 5809 | /* Use the next available one */ | ||
| 5810 | if ((ov->vdev->minor == -1) && | ||
| 5811 | video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { | ||
| 5812 | err("video_register_device failed"); | ||
| 5813 | goto error; | ||
| 5814 | } | ||
| 5815 | |||
| 5816 | info("Device at %s registered to minor %d", ov->usb_path, | ||
| 5817 | ov->vdev->minor); | ||
| 5818 | |||
| 5819 | usb_set_intfdata(intf, ov); | ||
| 5820 | ov_create_sysfs(ov->vdev); | ||
| 5821 | return 0; | ||
| 5822 | |||
| 5823 | error: | ||
| 5824 | if (ov->vdev) { | ||
| 5825 | if (-1 == ov->vdev->minor) | ||
| 5826 | video_device_release(ov->vdev); | ||
| 5827 | else | ||
| 5828 | video_unregister_device(ov->vdev); | ||
| 5829 | ov->vdev = NULL; | ||
| 5830 | } | ||
| 5831 | |||
| 5832 | if (ov->cbuf) { | ||
| 5833 | mutex_lock(&ov->cbuf_lock); | ||
| 5834 | kfree(ov->cbuf); | ||
| 5835 | ov->cbuf = NULL; | ||
| 5836 | mutex_unlock(&ov->cbuf_lock); | ||
| 5837 | } | ||
| 5838 | |||
| 5839 | kfree(ov); | ||
| 5840 | ov = NULL; | ||
| 5841 | |||
| 5842 | error_out: | ||
| 5843 | err("Camera initialization failed"); | ||
| 5844 | return -EIO; | ||
| 5845 | } | ||
| 5846 | |||
| 5847 | static void | ||
| 5848 | ov51x_disconnect(struct usb_interface *intf) | ||
| 5849 | { | ||
| 5850 | struct usb_ov511 *ov = usb_get_intfdata(intf); | ||
| 5851 | int n; | ||
| 5852 | |||
| 5853 | PDEBUG(3, ""); | ||
| 5854 | |||
| 5855 | usb_set_intfdata (intf, NULL); | ||
| 5856 | |||
| 5857 | if (!ov) | ||
| 5858 | return; | ||
| 5859 | |||
| 5860 | if (ov->vdev) | ||
| 5861 | video_unregister_device(ov->vdev); | ||
| 5862 | |||
| 5863 | for (n = 0; n < OV511_NUMFRAMES; n++) | ||
| 5864 | ov->frame[n].grabstate = FRAME_ERROR; | ||
| 5865 | |||
| 5866 | ov->curframe = -1; | ||
| 5867 | |||
| 5868 | /* This will cause the process to request another frame */ | ||
| 5869 | for (n = 0; n < OV511_NUMFRAMES; n++) | ||
| 5870 | wake_up_interruptible(&ov->frame[n].wq); | ||
| 5871 | |||
| 5872 | wake_up_interruptible(&ov->wq); | ||
| 5873 | |||
| 5874 | ov->streaming = 0; | ||
| 5875 | ov51x_unlink_isoc(ov); | ||
| 5876 | |||
| 5877 | ov->dev = NULL; | ||
| 5878 | |||
| 5879 | /* Free the memory */ | ||
| 5880 | if (ov && !ov->user) { | ||
| 5881 | mutex_lock(&ov->cbuf_lock); | ||
| 5882 | kfree(ov->cbuf); | ||
| 5883 | ov->cbuf = NULL; | ||
| 5884 | mutex_unlock(&ov->cbuf_lock); | ||
| 5885 | |||
| 5886 | ov51x_dealloc(ov); | ||
| 5887 | kfree(ov); | ||
| 5888 | ov = NULL; | ||
| 5889 | } | ||
| 5890 | |||
| 5891 | PDEBUG(3, "Disconnect complete"); | ||
| 5892 | } | ||
| 5893 | |||
| 5894 | static struct usb_driver ov511_driver = { | ||
| 5895 | .name = "ov511", | ||
| 5896 | .id_table = device_table, | ||
| 5897 | .probe = ov51x_probe, | ||
| 5898 | .disconnect = ov51x_disconnect | ||
| 5899 | }; | ||
| 5900 | |||
| 5901 | /**************************************************************************** | ||
| 5902 | * | ||
| 5903 | * Module routines | ||
| 5904 | * | ||
| 5905 | ***************************************************************************/ | ||
| 5906 | |||
| 5907 | static int __init | ||
| 5908 | usb_ov511_init(void) | ||
| 5909 | { | ||
| 5910 | int retval; | ||
| 5911 | |||
| 5912 | retval = usb_register(&ov511_driver); | ||
| 5913 | if (retval) | ||
| 5914 | goto out; | ||
| 5915 | |||
| 5916 | info(DRIVER_VERSION " : " DRIVER_DESC); | ||
| 5917 | |||
| 5918 | out: | ||
| 5919 | return retval; | ||
| 5920 | } | ||
| 5921 | |||
| 5922 | static void __exit | ||
| 5923 | usb_ov511_exit(void) | ||
| 5924 | { | ||
| 5925 | usb_deregister(&ov511_driver); | ||
| 5926 | info("driver deregistered"); | ||
| 5927 | |||
| 5928 | } | ||
| 5929 | |||
| 5930 | module_init(usb_ov511_init); | ||
| 5931 | module_exit(usb_ov511_exit); | ||
| 5932 | |||
diff --git a/drivers/usb/media/ov511.h b/drivers/usb/media/ov511.h deleted file mode 100644 index bce9b3633889..000000000000 --- a/drivers/usb/media/ov511.h +++ /dev/null | |||
| @@ -1,568 +0,0 @@ | |||
| 1 | #ifndef __LINUX_OV511_H | ||
| 2 | #define __LINUX_OV511_H | ||
| 3 | |||
| 4 | #include <asm/uaccess.h> | ||
| 5 | #include <linux/videodev.h> | ||
| 6 | #include <linux/smp_lock.h> | ||
| 7 | #include <linux/usb.h> | ||
| 8 | #include <linux/mutex.h> | ||
| 9 | |||
| 10 | #define OV511_DEBUG /* Turn on debug messages */ | ||
| 11 | |||
| 12 | #ifdef OV511_DEBUG | ||
| 13 | #define PDEBUG(level, fmt, args...) \ | ||
| 14 | if (debug >= (level)) info("[%s:%d] " fmt, \ | ||
| 15 | __FUNCTION__, __LINE__ , ## args) | ||
| 16 | #else | ||
| 17 | #define PDEBUG(level, fmt, args...) do {} while(0) | ||
| 18 | #endif | ||
| 19 | |||
| 20 | /* This macro restricts an int variable to an inclusive range */ | ||
| 21 | #define RESTRICT_TO_RANGE(v,mi,ma) { \ | ||
| 22 | if ((v) < (mi)) (v) = (mi); \ | ||
| 23 | else if ((v) > (ma)) (v) = (ma); \ | ||
| 24 | } | ||
| 25 | |||
| 26 | /* --------------------------------- */ | ||
| 27 | /* DEFINES FOR OV511 AND OTHER CHIPS */ | ||
| 28 | /* --------------------------------- */ | ||
| 29 | |||
| 30 | /* USB IDs */ | ||
| 31 | #define VEND_OMNIVISION 0x05A9 | ||
| 32 | #define PROD_OV511 0x0511 | ||
| 33 | #define PROD_OV511PLUS 0xA511 | ||
| 34 | #define PROD_OV518 0x0518 | ||
| 35 | #define PROD_OV518PLUS 0xA518 | ||
| 36 | |||
| 37 | #define VEND_MATTEL 0x0813 | ||
| 38 | #define PROD_ME2CAM 0x0002 | ||
| 39 | |||
| 40 | /* --------------------------------- */ | ||
| 41 | /* OV51x REGISTER MNEMONICS */ | ||
| 42 | /* --------------------------------- */ | ||
| 43 | |||
| 44 | /* Camera interface register numbers */ | ||
| 45 | #define R511_CAM_DELAY 0x10 | ||
| 46 | #define R511_CAM_EDGE 0x11 | ||
| 47 | #define R511_CAM_PXCNT 0x12 | ||
| 48 | #define R511_CAM_LNCNT 0x13 | ||
| 49 | #define R511_CAM_PXDIV 0x14 | ||
| 50 | #define R511_CAM_LNDIV 0x15 | ||
| 51 | #define R511_CAM_UV_EN 0x16 | ||
| 52 | #define R511_CAM_LINE_MODE 0x17 | ||
| 53 | #define R511_CAM_OPTS 0x18 | ||
| 54 | |||
| 55 | /* Snapshot mode camera interface register numbers */ | ||
| 56 | #define R511_SNAP_FRAME 0x19 | ||
| 57 | #define R511_SNAP_PXCNT 0x1A | ||
| 58 | #define R511_SNAP_LNCNT 0x1B | ||
| 59 | #define R511_SNAP_PXDIV 0x1C | ||
| 60 | #define R511_SNAP_LNDIV 0x1D | ||
| 61 | #define R511_SNAP_UV_EN 0x1E | ||
| 62 | #define R511_SNAP_OPTS 0x1F | ||
| 63 | |||
| 64 | /* DRAM register numbers */ | ||
| 65 | #define R511_DRAM_FLOW_CTL 0x20 | ||
| 66 | #define R511_DRAM_ARCP 0x21 | ||
| 67 | #define R511_DRAM_MRC 0x22 | ||
| 68 | #define R511_DRAM_RFC 0x23 | ||
| 69 | |||
| 70 | /* ISO FIFO register numbers */ | ||
| 71 | #define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ | ||
| 72 | #define R511_FIFO_OPTS 0x31 | ||
| 73 | |||
| 74 | /* Parallel IO register numbers */ | ||
| 75 | #define R511_PIO_OPTS 0x38 | ||
| 76 | #define R511_PIO_DATA 0x39 | ||
| 77 | #define R511_PIO_BIST 0x3E | ||
| 78 | #define R518_GPIO_IN 0x55 /* OV518(+) only */ | ||
| 79 | #define R518_GPIO_OUT 0x56 /* OV518(+) only */ | ||
| 80 | #define R518_GPIO_CTL 0x57 /* OV518(+) only */ | ||
| 81 | #define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */ | ||
| 82 | #define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ | ||
| 83 | #define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */ | ||
| 84 | #define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */ | ||
| 85 | #define R518_GPIO_RESET 0x5c /* OV518(+) only */ | ||
| 86 | |||
| 87 | /* I2C registers */ | ||
| 88 | #define R511_I2C_CTL 0x40 | ||
| 89 | #define R518_I2C_CTL 0x47 /* OV518(+) only */ | ||
| 90 | #define R51x_I2C_W_SID 0x41 | ||
| 91 | #define R51x_I2C_SADDR_3 0x42 | ||
| 92 | #define R51x_I2C_SADDR_2 0x43 | ||
| 93 | #define R51x_I2C_R_SID 0x44 | ||
| 94 | #define R51x_I2C_DATA 0x45 | ||
| 95 | #define R51x_I2C_CLOCK 0x46 | ||
| 96 | #define R51x_I2C_TIMEOUT 0x47 | ||
| 97 | |||
| 98 | /* I2C snapshot registers */ | ||
| 99 | #define R511_SI2C_SADDR_3 0x48 | ||
| 100 | #define R511_SI2C_DATA 0x49 | ||
| 101 | |||
| 102 | /* System control registers */ | ||
| 103 | #define R51x_SYS_RESET 0x50 | ||
| 104 | /* Reset type definitions */ | ||
| 105 | #define OV511_RESET_UDC 0x01 | ||
| 106 | #define OV511_RESET_I2C 0x02 | ||
| 107 | #define OV511_RESET_FIFO 0x04 | ||
| 108 | #define OV511_RESET_OMNICE 0x08 | ||
| 109 | #define OV511_RESET_DRAM 0x10 | ||
| 110 | #define OV511_RESET_CAM_INT 0x20 | ||
| 111 | #define OV511_RESET_OV511 0x40 | ||
| 112 | #define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ | ||
| 113 | #define OV511_RESET_ALL 0x7F | ||
| 114 | |||
| 115 | #define R511_SYS_CLOCK_DIV 0x51 | ||
| 116 | #define R51x_SYS_SNAP 0x52 | ||
| 117 | #define R51x_SYS_INIT 0x53 | ||
| 118 | #define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */ | ||
| 119 | #define R511_SYS_LED_CTL 0x55 /* OV511+ only */ | ||
| 120 | #define R511_SYS_USER 0x5E | ||
| 121 | #define R511_SYS_CUST_ID 0x5F | ||
| 122 | |||
| 123 | /* OmniCE (compression) registers */ | ||
| 124 | #define R511_COMP_PHY 0x70 | ||
| 125 | #define R511_COMP_PHUV 0x71 | ||
| 126 | #define R511_COMP_PVY 0x72 | ||
| 127 | #define R511_COMP_PVUV 0x73 | ||
| 128 | #define R511_COMP_QHY 0x74 | ||
| 129 | #define R511_COMP_QHUV 0x75 | ||
| 130 | #define R511_COMP_QVY 0x76 | ||
| 131 | #define R511_COMP_QVUV 0x77 | ||
| 132 | #define R511_COMP_EN 0x78 | ||
| 133 | #define R511_COMP_LUT_EN 0x79 | ||
| 134 | #define R511_COMP_LUT_BEGIN 0x80 | ||
| 135 | |||
| 136 | /* --------------------------------- */ | ||
| 137 | /* ALTERNATE NUMBERS */ | ||
| 138 | /* --------------------------------- */ | ||
| 139 | |||
| 140 | /* Alternate numbers for various max packet sizes (OV511 only) */ | ||
| 141 | #define OV511_ALT_SIZE_992 0 | ||
| 142 | #define OV511_ALT_SIZE_993 1 | ||
| 143 | #define OV511_ALT_SIZE_768 2 | ||
| 144 | #define OV511_ALT_SIZE_769 3 | ||
| 145 | #define OV511_ALT_SIZE_512 4 | ||
| 146 | #define OV511_ALT_SIZE_513 5 | ||
| 147 | #define OV511_ALT_SIZE_257 6 | ||
| 148 | #define OV511_ALT_SIZE_0 7 | ||
| 149 | |||
| 150 | /* Alternate numbers for various max packet sizes (OV511+ only) */ | ||
| 151 | #define OV511PLUS_ALT_SIZE_0 0 | ||
| 152 | #define OV511PLUS_ALT_SIZE_33 1 | ||
| 153 | #define OV511PLUS_ALT_SIZE_129 2 | ||
| 154 | #define OV511PLUS_ALT_SIZE_257 3 | ||
| 155 | #define OV511PLUS_ALT_SIZE_385 4 | ||
| 156 | #define OV511PLUS_ALT_SIZE_513 5 | ||
| 157 | #define OV511PLUS_ALT_SIZE_769 6 | ||
| 158 | #define OV511PLUS_ALT_SIZE_961 7 | ||
| 159 | |||
| 160 | /* Alternate numbers for various max packet sizes (OV518(+) only) */ | ||
| 161 | #define OV518_ALT_SIZE_0 0 | ||
| 162 | #define OV518_ALT_SIZE_128 1 | ||
| 163 | #define OV518_ALT_SIZE_256 2 | ||
| 164 | #define OV518_ALT_SIZE_384 3 | ||
| 165 | #define OV518_ALT_SIZE_512 4 | ||
| 166 | #define OV518_ALT_SIZE_640 5 | ||
| 167 | #define OV518_ALT_SIZE_768 6 | ||
| 168 | #define OV518_ALT_SIZE_896 7 | ||
| 169 | |||
| 170 | /* --------------------------------- */ | ||
| 171 | /* OV7610 REGISTER MNEMONICS */ | ||
| 172 | /* --------------------------------- */ | ||
| 173 | |||
| 174 | /* OV7610 registers */ | ||
| 175 | #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ | ||
| 176 | #define OV7610_REG_BLUE 0x01 /* blue channel balance */ | ||
| 177 | #define OV7610_REG_RED 0x02 /* red channel balance */ | ||
| 178 | #define OV7610_REG_SAT 0x03 /* saturation */ | ||
| 179 | /* 04 reserved */ | ||
| 180 | #define OV7610_REG_CNT 0x05 /* Y contrast */ | ||
| 181 | #define OV7610_REG_BRT 0x06 /* Y brightness */ | ||
| 182 | /* 08-0b reserved */ | ||
| 183 | #define OV7610_REG_BLUE_BIAS 0x0C /* blue channel bias (5:0) */ | ||
| 184 | #define OV7610_REG_RED_BIAS 0x0D /* read channel bias (5:0) */ | ||
| 185 | #define OV7610_REG_GAMMA_COEFF 0x0E /* gamma settings */ | ||
| 186 | #define OV7610_REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */ | ||
| 187 | #define OV7610_REG_EXP 0x10 /* manual exposure setting */ | ||
| 188 | #define OV7610_REG_CLOCK 0x11 /* polarity/clock prescaler */ | ||
| 189 | #define OV7610_REG_COM_A 0x12 /* misc common regs */ | ||
| 190 | #define OV7610_REG_COM_B 0x13 /* misc common regs */ | ||
| 191 | #define OV7610_REG_COM_C 0x14 /* misc common regs */ | ||
| 192 | #define OV7610_REG_COM_D 0x15 /* misc common regs */ | ||
| 193 | #define OV7610_REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */ | ||
| 194 | #define OV7610_REG_HWIN_START 0x17 /* horizontal window start */ | ||
| 195 | #define OV7610_REG_HWIN_END 0x18 /* horizontal window end */ | ||
| 196 | #define OV7610_REG_VWIN_START 0x19 /* vertical window start */ | ||
| 197 | #define OV7610_REG_VWIN_END 0x1A /* vertical window end */ | ||
| 198 | #define OV7610_REG_PIXEL_SHIFT 0x1B /* pixel shift */ | ||
| 199 | #define OV7610_REG_ID_HIGH 0x1C /* manufacturer ID MSB */ | ||
| 200 | #define OV7610_REG_ID_LOW 0x1D /* manufacturer ID LSB */ | ||
| 201 | /* 0e-0f reserved */ | ||
| 202 | #define OV7610_REG_COM_E 0x20 /* misc common regs */ | ||
| 203 | #define OV7610_REG_YOFFSET 0x21 /* Y channel offset */ | ||
| 204 | #define OV7610_REG_UOFFSET 0x22 /* U channel offset */ | ||
| 205 | /* 23 reserved */ | ||
| 206 | #define OV7610_REG_ECW 0x24 /* Exposure white level for AEC */ | ||
| 207 | #define OV7610_REG_ECB 0x25 /* Exposure black level for AEC */ | ||
| 208 | #define OV7610_REG_COM_F 0x26 /* misc settings */ | ||
| 209 | #define OV7610_REG_COM_G 0x27 /* misc settings */ | ||
| 210 | #define OV7610_REG_COM_H 0x28 /* misc settings */ | ||
| 211 | #define OV7610_REG_COM_I 0x29 /* misc settings */ | ||
| 212 | #define OV7610_REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */ | ||
| 213 | #define OV7610_REG_FRAMERATE_L 0x2B /* frame rate LSB */ | ||
| 214 | #define OV7610_REG_ALC 0x2C /* Auto Level Control settings */ | ||
| 215 | #define OV7610_REG_COM_J 0x2D /* misc settings */ | ||
| 216 | #define OV7610_REG_VOFFSET 0x2E /* V channel offset adjustment */ | ||
| 217 | #define OV7610_REG_ARRAY_BIAS 0x2F /* Array bias -- don't change */ | ||
| 218 | /* 30-32 reserved */ | ||
| 219 | #define OV7610_REG_YGAMMA 0x33 /* misc gamma settings (7:6) */ | ||
| 220 | #define OV7610_REG_BIAS_ADJUST 0x34 /* misc bias settings */ | ||
| 221 | #define OV7610_REG_COM_L 0x35 /* misc settings */ | ||
| 222 | /* 36-37 reserved */ | ||
| 223 | #define OV7610_REG_COM_K 0x38 /* misc registers */ | ||
| 224 | |||
| 225 | /* --------------------------------- */ | ||
| 226 | /* I2C ADDRESSES */ | ||
| 227 | /* --------------------------------- */ | ||
| 228 | |||
| 229 | #define OV7xx0_SID 0x42 | ||
| 230 | #define OV6xx0_SID 0xC0 | ||
| 231 | #define OV8xx0_SID 0xA0 | ||
| 232 | #define KS0127_SID 0xD8 | ||
| 233 | #define SAA7111A_SID 0x48 | ||
| 234 | |||
| 235 | /* --------------------------------- */ | ||
| 236 | /* MISCELLANEOUS DEFINES */ | ||
| 237 | /* --------------------------------- */ | ||
| 238 | |||
| 239 | #define I2C_CLOCK_PRESCALER 0x03 | ||
| 240 | |||
| 241 | #define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ | ||
| 242 | #define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */ | ||
| 243 | #define PIXELS_PER_SEG 256 /* Pixels per segment */ | ||
| 244 | |||
| 245 | #define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ | ||
| 246 | |||
| 247 | #define OV511_NUMFRAMES 2 | ||
| 248 | #if OV511_NUMFRAMES > VIDEO_MAX_FRAME | ||
| 249 | #error "OV511_NUMFRAMES is too high" | ||
| 250 | #endif | ||
| 251 | |||
| 252 | #define OV511_NUMSBUF 2 | ||
| 253 | |||
| 254 | /* Control transfers use up to 4 bytes */ | ||
| 255 | #define OV511_CBUF_SIZE 4 | ||
| 256 | |||
| 257 | /* Size of usb_make_path() buffer */ | ||
| 258 | #define OV511_USB_PATH_LEN 64 | ||
| 259 | |||
| 260 | /* Bridge types */ | ||
| 261 | enum { | ||
| 262 | BRG_UNKNOWN, | ||
| 263 | BRG_OV511, | ||
| 264 | BRG_OV511PLUS, | ||
| 265 | BRG_OV518, | ||
| 266 | BRG_OV518PLUS, | ||
| 267 | }; | ||
| 268 | |||
| 269 | /* Bridge classes */ | ||
| 270 | enum { | ||
| 271 | BCL_UNKNOWN, | ||
| 272 | BCL_OV511, | ||
| 273 | BCL_OV518, | ||
| 274 | }; | ||
| 275 | |||
| 276 | /* Sensor types */ | ||
| 277 | enum { | ||
| 278 | SEN_UNKNOWN, | ||
| 279 | SEN_OV76BE, | ||
| 280 | SEN_OV7610, | ||
| 281 | SEN_OV7620, | ||
| 282 | SEN_OV7620AE, | ||
| 283 | SEN_OV6620, | ||
| 284 | SEN_OV6630, | ||
| 285 | SEN_OV6630AE, | ||
| 286 | SEN_OV6630AF, | ||
| 287 | SEN_OV8600, | ||
| 288 | SEN_KS0127, | ||
| 289 | SEN_KS0127B, | ||
| 290 | SEN_SAA7111A, | ||
| 291 | }; | ||
| 292 | |||
| 293 | enum { | ||
| 294 | STATE_SCANNING, /* Scanning for start */ | ||
| 295 | STATE_HEADER, /* Parsing header */ | ||
| 296 | STATE_LINES, /* Parsing lines */ | ||
| 297 | }; | ||
| 298 | |||
| 299 | /* Buffer states */ | ||
| 300 | enum { | ||
| 301 | BUF_NOT_ALLOCATED, | ||
| 302 | BUF_ALLOCATED, | ||
| 303 | }; | ||
| 304 | |||
| 305 | /* --------- Definition of ioctl interface --------- */ | ||
| 306 | |||
| 307 | #define OV511_INTERFACE_VER 101 | ||
| 308 | |||
| 309 | /* LED options */ | ||
| 310 | enum { | ||
| 311 | LED_OFF, | ||
| 312 | LED_ON, | ||
| 313 | LED_AUTO, | ||
| 314 | }; | ||
| 315 | |||
| 316 | /* Raw frame formats */ | ||
| 317 | enum { | ||
| 318 | RAWFMT_INVALID, | ||
| 319 | RAWFMT_YUV400, | ||
| 320 | RAWFMT_YUV420, | ||
| 321 | RAWFMT_YUV422, | ||
| 322 | RAWFMT_GBR422, | ||
| 323 | }; | ||
| 324 | |||
| 325 | struct ov511_i2c_struct { | ||
| 326 | unsigned char slave; /* Write slave ID (read ID - 1) */ | ||
| 327 | unsigned char reg; /* Index of register */ | ||
| 328 | unsigned char value; /* User sets this w/ write, driver does w/ read */ | ||
| 329 | unsigned char mask; /* Bits to be changed. Not used with read ops */ | ||
| 330 | }; | ||
| 331 | |||
| 332 | /* ioctls */ | ||
| 333 | #define OV511IOC_WI2C _IOW('v', BASE_VIDIOCPRIVATE + 5, \ | ||
| 334 | struct ov511_i2c_struct) | ||
| 335 | #define OV511IOC_RI2C _IOWR('v', BASE_VIDIOCPRIVATE + 6, \ | ||
| 336 | struct ov511_i2c_struct) | ||
| 337 | /* ------------- End IOCTL interface -------------- */ | ||
| 338 | |||
| 339 | struct usb_ov511; /* Forward declaration */ | ||
| 340 | |||
| 341 | struct ov511_sbuf { | ||
| 342 | struct usb_ov511 *ov; | ||
| 343 | unsigned char *data; | ||
| 344 | struct urb *urb; | ||
| 345 | spinlock_t lock; | ||
| 346 | int n; | ||
| 347 | }; | ||
| 348 | |||
| 349 | enum { | ||
| 350 | FRAME_UNUSED, /* Unused (no MCAPTURE) */ | ||
| 351 | FRAME_READY, /* Ready to start grabbing */ | ||
| 352 | FRAME_GRABBING, /* In the process of being grabbed into */ | ||
| 353 | FRAME_DONE, /* Finished grabbing, but not been synced yet */ | ||
| 354 | FRAME_ERROR, /* Something bad happened while processing */ | ||
| 355 | }; | ||
| 356 | |||
| 357 | struct ov511_regvals { | ||
| 358 | enum { | ||
| 359 | OV511_DONE_BUS, | ||
| 360 | OV511_REG_BUS, | ||
| 361 | OV511_I2C_BUS, | ||
| 362 | } bus; | ||
| 363 | unsigned char reg; | ||
| 364 | unsigned char val; | ||
| 365 | }; | ||
| 366 | |||
| 367 | struct ov511_frame { | ||
| 368 | int framenum; /* Index of this frame */ | ||
| 369 | unsigned char *data; /* Frame buffer */ | ||
| 370 | unsigned char *tempdata; /* Temp buffer for multi-stage conversions */ | ||
| 371 | unsigned char *rawdata; /* Raw camera data buffer */ | ||
| 372 | unsigned char *compbuf; /* Temp buffer for decompressor */ | ||
| 373 | |||
| 374 | int depth; /* Bytes per pixel */ | ||
| 375 | int width; /* Width application is expecting */ | ||
| 376 | int height; /* Height application is expecting */ | ||
| 377 | |||
| 378 | int rawwidth; /* Actual width of frame sent from camera */ | ||
| 379 | int rawheight; /* Actual height of frame sent from camera */ | ||
| 380 | |||
| 381 | int sub_flag; /* Sub-capture mode for this frame? */ | ||
| 382 | unsigned int format; /* Format for this frame */ | ||
| 383 | int compressed; /* Is frame compressed? */ | ||
| 384 | |||
| 385 | volatile int grabstate; /* State of grabbing */ | ||
| 386 | int scanstate; /* State of scanning */ | ||
| 387 | |||
| 388 | int bytes_recvd; /* Number of image bytes received from camera */ | ||
| 389 | |||
| 390 | long bytes_read; /* Amount that has been read() */ | ||
| 391 | |||
| 392 | wait_queue_head_t wq; /* Processes waiting */ | ||
| 393 | |||
| 394 | int snapshot; /* True if frame was a snapshot */ | ||
| 395 | }; | ||
| 396 | |||
| 397 | #define DECOMP_INTERFACE_VER 4 | ||
| 398 | |||
| 399 | /* Compression module operations */ | ||
| 400 | struct ov51x_decomp_ops { | ||
| 401 | int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *, | ||
| 402 | int, int, int); | ||
| 403 | int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *, | ||
| 404 | int, int, int); | ||
| 405 | int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *, | ||
| 406 | int, int, int); | ||
| 407 | struct module *owner; | ||
| 408 | }; | ||
| 409 | |||
| 410 | struct usb_ov511 { | ||
| 411 | struct video_device *vdev; | ||
| 412 | struct usb_device *dev; | ||
| 413 | |||
| 414 | int customid; | ||
| 415 | char *desc; | ||
| 416 | unsigned char iface; | ||
| 417 | char usb_path[OV511_USB_PATH_LEN]; | ||
| 418 | |||
| 419 | /* Determined by sensor type */ | ||
| 420 | int maxwidth; | ||
| 421 | int maxheight; | ||
| 422 | int minwidth; | ||
| 423 | int minheight; | ||
| 424 | |||
| 425 | int brightness; | ||
| 426 | int colour; | ||
| 427 | int contrast; | ||
| 428 | int hue; | ||
| 429 | int whiteness; | ||
| 430 | int exposure; | ||
| 431 | int auto_brt; /* Auto brightness enabled flag */ | ||
| 432 | int auto_gain; /* Auto gain control enabled flag */ | ||
| 433 | int auto_exp; /* Auto exposure enabled flag */ | ||
| 434 | int backlight; /* Backlight exposure algorithm flag */ | ||
| 435 | int mirror; /* Image is reversed horizontally */ | ||
| 436 | |||
| 437 | int led_policy; /* LED: off|on|auto; OV511+ only */ | ||
| 438 | |||
| 439 | struct mutex lock; /* Serializes user-accessible operations */ | ||
| 440 | int user; /* user count for exclusive use */ | ||
| 441 | |||
| 442 | int streaming; /* Are we streaming Isochronous? */ | ||
| 443 | int grabbing; /* Are we grabbing? */ | ||
| 444 | |||
| 445 | int compress; /* Should the next frame be compressed? */ | ||
| 446 | int compress_inited; /* Are compression params uploaded? */ | ||
| 447 | |||
| 448 | int lightfreq; /* Power (lighting) frequency */ | ||
| 449 | int bandfilt; /* Banding filter enabled flag */ | ||
| 450 | |||
| 451 | unsigned char *fbuf; /* Videodev buffer area */ | ||
| 452 | unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */ | ||
| 453 | unsigned char *rawfbuf; /* Raw camera data buffer area */ | ||
| 454 | |||
| 455 | int sub_flag; /* Pix Array subcapture on flag */ | ||
| 456 | int subx; /* Pix Array subcapture x offset */ | ||
| 457 | int suby; /* Pix Array subcapture y offset */ | ||
| 458 | int subw; /* Pix Array subcapture width */ | ||
| 459 | int subh; /* Pix Array subcapture height */ | ||
| 460 | |||
| 461 | int curframe; /* Current receiving sbuf */ | ||
| 462 | struct ov511_frame frame[OV511_NUMFRAMES]; | ||
| 463 | |||
| 464 | struct ov511_sbuf sbuf[OV511_NUMSBUF]; | ||
| 465 | |||
| 466 | wait_queue_head_t wq; /* Processes waiting */ | ||
| 467 | |||
| 468 | int snap_enabled; /* Snapshot mode enabled */ | ||
| 469 | |||
| 470 | int bridge; /* Type of bridge (BRG_*) */ | ||
| 471 | int bclass; /* Class of bridge (BCL_*) */ | ||
| 472 | int sensor; /* Type of image sensor chip (SEN_*) */ | ||
| 473 | |||
| 474 | int packet_size; /* Frame size per isoc desc */ | ||
| 475 | int packet_numbering; /* Is ISO frame numbering enabled? */ | ||
| 476 | |||
| 477 | /* Framebuffer/sbuf management */ | ||
| 478 | int buf_state; | ||
| 479 | struct mutex buf_lock; | ||
| 480 | |||
| 481 | struct ov51x_decomp_ops *decomp_ops; | ||
| 482 | |||
| 483 | /* Stop streaming while changing picture settings */ | ||
| 484 | int stop_during_set; | ||
| 485 | |||
| 486 | int stopped; /* Streaming is temporarily paused */ | ||
| 487 | |||
| 488 | /* Video decoder stuff */ | ||
| 489 | int input; /* Composite, S-VIDEO, etc... */ | ||
| 490 | int num_inputs; /* Number of inputs */ | ||
| 491 | int norm; /* NTSC / PAL / SECAM */ | ||
| 492 | int has_decoder; /* Device has a video decoder */ | ||
| 493 | int pal; /* Device is designed for PAL resolution */ | ||
| 494 | |||
| 495 | /* I2C interface */ | ||
| 496 | struct mutex i2c_lock; /* Protect I2C controller regs */ | ||
| 497 | unsigned char primary_i2c_slave; /* I2C write id of sensor */ | ||
| 498 | |||
| 499 | /* Control transaction stuff */ | ||
| 500 | unsigned char *cbuf; /* Buffer for payload */ | ||
| 501 | struct mutex cbuf_lock; | ||
| 502 | }; | ||
| 503 | |||
| 504 | /* Used to represent a list of values and their respective symbolic names */ | ||
| 505 | struct symbolic_list { | ||
| 506 | int num; | ||
| 507 | char *name; | ||
| 508 | }; | ||
| 509 | |||
| 510 | #define NOT_DEFINED_STR "Unknown" | ||
| 511 | |||
| 512 | /* Returns the name of the matching element in the symbolic_list array. The | ||
| 513 | * end of the list must be marked with an element that has a NULL name. | ||
| 514 | */ | ||
| 515 | static inline char * | ||
| 516 | symbolic(struct symbolic_list list[], int num) | ||
| 517 | { | ||
| 518 | int i; | ||
| 519 | |||
| 520 | for (i = 0; list[i].name != NULL; i++) | ||
| 521 | if (list[i].num == num) | ||
| 522 | return (list[i].name); | ||
| 523 | |||
| 524 | return (NOT_DEFINED_STR); | ||
| 525 | } | ||
| 526 | |||
| 527 | /* Compression stuff */ | ||
| 528 | |||
| 529 | #define OV511_QUANTABLESIZE 64 | ||
| 530 | #define OV518_QUANTABLESIZE 32 | ||
| 531 | |||
| 532 | #define OV511_YQUANTABLE { \ | ||
| 533 | 0, 1, 1, 2, 2, 3, 3, 4, \ | ||
| 534 | 1, 1, 1, 2, 2, 3, 4, 4, \ | ||
| 535 | 1, 1, 2, 2, 3, 4, 4, 4, \ | ||
| 536 | 2, 2, 2, 3, 4, 4, 4, 4, \ | ||
| 537 | 2, 2, 3, 4, 4, 5, 5, 5, \ | ||
| 538 | 3, 3, 4, 4, 5, 5, 5, 5, \ | ||
| 539 | 3, 4, 4, 4, 5, 5, 5, 5, \ | ||
| 540 | 4, 4, 4, 4, 5, 5, 5, 5 \ | ||
| 541 | } | ||
| 542 | |||
| 543 | #define OV511_UVQUANTABLE { \ | ||
| 544 | 0, 2, 2, 3, 4, 4, 4, 4, \ | ||
| 545 | 2, 2, 2, 4, 4, 4, 4, 4, \ | ||
| 546 | 2, 2, 3, 4, 4, 4, 4, 4, \ | ||
| 547 | 3, 4, 4, 4, 4, 4, 4, 4, \ | ||
| 548 | 4, 4, 4, 4, 4, 4, 4, 4, \ | ||
| 549 | 4, 4, 4, 4, 4, 4, 4, 4, \ | ||
| 550 | 4, 4, 4, 4, 4, 4, 4, 4, \ | ||
| 551 | 4, 4, 4, 4, 4, 4, 4, 4 \ | ||
| 552 | } | ||
| 553 | |||
| 554 | #define OV518_YQUANTABLE { \ | ||
| 555 | 5, 4, 5, 6, 6, 7, 7, 7, \ | ||
| 556 | 5, 5, 5, 5, 6, 7, 7, 7, \ | ||
| 557 | 6, 6, 6, 6, 7, 7, 7, 8, \ | ||
| 558 | 7, 7, 6, 7, 7, 7, 8, 8 \ | ||
| 559 | } | ||
| 560 | |||
| 561 | #define OV518_UVQUANTABLE { \ | ||
| 562 | 6, 6, 6, 7, 7, 7, 7, 7, \ | ||
| 563 | 6, 6, 6, 7, 7, 7, 7, 7, \ | ||
| 564 | 6, 6, 6, 7, 7, 7, 7, 8, \ | ||
| 565 | 7, 7, 7, 7, 7, 7, 8, 8 \ | ||
| 566 | } | ||
| 567 | |||
| 568 | #endif | ||
diff --git a/drivers/usb/media/pwc/Makefile b/drivers/usb/media/pwc/Makefile deleted file mode 100644 index 2d93a775011a..000000000000 --- a/drivers/usb/media/pwc/Makefile +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | ifneq ($(KERNELRELEASE),) | ||
| 2 | |||
| 3 | pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o | ||
| 4 | |||
| 5 | obj-$(CONFIG_USB_PWC) += pwc.o | ||
| 6 | |||
| 7 | else | ||
| 8 | |||
| 9 | KDIR := /lib/modules/$(shell uname -r)/build | ||
| 10 | PWD := $(shell pwd) | ||
| 11 | |||
| 12 | default: | ||
| 13 | $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules | ||
| 14 | |||
| 15 | endif | ||
| 16 | |||
| 17 | clean: | ||
| 18 | rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c | ||
| 19 | rm -rf .tmp_versions | ||
| 20 | |||
diff --git a/drivers/usb/media/pwc/philips.txt b/drivers/usb/media/pwc/philips.txt deleted file mode 100644 index 04a640d723ed..000000000000 --- a/drivers/usb/media/pwc/philips.txt +++ /dev/null | |||
| @@ -1,236 +0,0 @@ | |||
| 1 | This file contains some additional information for the Philips and OEM webcams. | ||
| 2 | E-mail: webcam@smcc.demon.nl Last updated: 2004-01-19 | ||
| 3 | Site: http://www.smcc.demon.nl/webcam/ | ||
| 4 | |||
| 5 | As of this moment, the following cameras are supported: | ||
| 6 | * Philips PCA645 | ||
| 7 | * Philips PCA646 | ||
| 8 | * Philips PCVC675 | ||
| 9 | * Philips PCVC680 | ||
| 10 | * Philips PCVC690 | ||
| 11 | * Philips PCVC720/40 | ||
| 12 | * Philips PCVC730 | ||
| 13 | * Philips PCVC740 | ||
| 14 | * Philips PCVC750 | ||
| 15 | * Askey VC010 | ||
| 16 | * Creative Labs Webcam 5 | ||
| 17 | * Creative Labs Webcam Pro Ex | ||
| 18 | * Logitech QuickCam 3000 Pro | ||
| 19 | * Logitech QuickCam 4000 Pro | ||
| 20 | * Logitech QuickCam Notebook Pro | ||
| 21 | * Logitech QuickCam Zoom | ||
| 22 | * Logitech QuickCam Orbit | ||
| 23 | * Logitech QuickCam Sphere | ||
| 24 | * Samsung MPC-C10 | ||
| 25 | * Samsung MPC-C30 | ||
| 26 | * Sotec Afina Eye | ||
| 27 | * AME CU-001 | ||
| 28 | * Visionite VCS-UM100 | ||
| 29 | * Visionite VCS-UC300 | ||
| 30 | |||
| 31 | The main webpage for the Philips driver is at the address above. It contains | ||
| 32 | a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin | ||
| 33 | contains decompression routines that allow you to use higher image sizes and | ||
| 34 | framerates; in addition the webcam uses less bandwidth on the USB bus (handy | ||
| 35 | if you want to run more than 1 camera simultaneously). These routines fall | ||
| 36 | under a NDA, and may therefor not be distributed as source; however, its use | ||
| 37 | is completely optional. | ||
| 38 | |||
| 39 | You can build this code either into your kernel, or as a module. I recommend | ||
| 40 | the latter, since it makes troubleshooting a lot easier. The built-in | ||
| 41 | microphone is supported through the USB Audio class. | ||
| 42 | |||
| 43 | When you load the module you can set some default settings for the | ||
| 44 | camera; some programs depend on a particular image-size or -format and | ||
| 45 | don't know how to set it properly in the driver. The options are: | ||
| 46 | |||
| 47 | size | ||
| 48 | Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or | ||
| 49 | 'vga', for an image size of resp. 128x96, 160x120, 176x144, | ||
| 50 | 320x240, 352x288 and 640x480 (of course, only for those cameras that | ||
| 51 | support these resolutions). | ||
| 52 | |||
| 53 | fps | ||
| 54 | Specifies the desired framerate. Is an integer in the range of 4-30. | ||
| 55 | |||
| 56 | fbufs | ||
| 57 | This paramter specifies the number of internal buffers to use for storing | ||
| 58 | frames from the cam. This will help if the process that reads images from | ||
| 59 | the cam is a bit slow or momentarely busy. However, on slow machines it | ||
| 60 | only introduces lag, so choose carefully. The default is 3, which is | ||
| 61 | reasonable. You can set it between 2 and 5. | ||
| 62 | |||
| 63 | mbufs | ||
| 64 | This is an integer between 1 and 10. It will tell the module the number of | ||
| 65 | buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends. | ||
| 66 | The default is 2, which is adequate for most applications (double | ||
| 67 | buffering). | ||
| 68 | |||
| 69 | Should you experience a lot of 'Dumping frame...' messages during | ||
| 70 | grabbing with a tool that uses mmap(), you might want to increase if. | ||
| 71 | However, it doesn't really buffer images, it just gives you a bit more | ||
| 72 | slack when your program is behind. But you need a multi-threaded or | ||
| 73 | forked program to really take advantage of these buffers. | ||
| 74 | |||
| 75 | The absolute maximum is 10, but don't set it too high! Every buffer takes | ||
| 76 | up 460 KB of RAM, so unless you have a lot of memory setting this to | ||
| 77 | something more than 4 is an absolute waste. This memory is only | ||
| 78 | allocated during open(), so nothing is wasted when the camera is not in | ||
| 79 | use. | ||
| 80 | |||
| 81 | power_save | ||
| 82 | When power_save is enabled (set to 1), the module will try to shut down | ||
| 83 | the cam on close() and re-activate on open(). This will save power and | ||
| 84 | turn off the LED. Not all cameras support this though (the 645 and 646 | ||
| 85 | don't have power saving at all), and some models don't work either (they | ||
| 86 | will shut down, but never wake up). Consider this experimental. By | ||
| 87 | default this option is disabled. | ||
| 88 | |||
| 89 | compression (only useful with the plugin) | ||
| 90 | With this option you can control the compression factor that the camera | ||
| 91 | uses to squeeze the image through the USB bus. You can set the | ||
| 92 | parameter between 0 and 3: | ||
| 93 | 0 = prefer uncompressed images; if the requested mode is not available | ||
| 94 | in an uncompressed format, the driver will silently switch to low | ||
| 95 | compression. | ||
| 96 | 1 = low compression. | ||
| 97 | 2 = medium compression. | ||
| 98 | 3 = high compression. | ||
| 99 | |||
| 100 | High compression takes less bandwidth of course, but it could also | ||
| 101 | introduce some unwanted artefacts. The default is 2, medium compression. | ||
| 102 | See the FAQ on the website for an overview of which modes require | ||
| 103 | compression. | ||
| 104 | |||
| 105 | The compression parameter does not apply to the 645 and 646 cameras | ||
| 106 | and OEM models derived from those (only a few). Most cams honour this | ||
| 107 | parameter. | ||
| 108 | |||
| 109 | leds | ||
| 110 | This settings takes 2 integers, that define the on/off time for the LED | ||
| 111 | (in milliseconds). One of the interesting things that you can do with | ||
| 112 | this is let the LED blink while the camera is in use. This: | ||
| 113 | |||
| 114 | leds=500,500 | ||
| 115 | |||
| 116 | will blink the LED once every second. But with: | ||
| 117 | |||
| 118 | leds=0,0 | ||
| 119 | |||
| 120 | the LED never goes on, making it suitable for silent surveillance. | ||
| 121 | |||
| 122 | By default the camera's LED is on solid while in use, and turned off | ||
| 123 | when the camera is not used anymore. | ||
| 124 | |||
| 125 | This parameter works only with the ToUCam range of cameras (720, 730, 740, | ||
| 126 | 750) and OEMs. For other cameras this command is silently ignored, and | ||
| 127 | the LED cannot be controlled. | ||
| 128 | |||
| 129 | Finally: this parameters does not take effect UNTIL the first time you | ||
| 130 | open the camera device. Until then, the LED remains on. | ||
| 131 | |||
| 132 | dev_hint | ||
| 133 | A long standing problem with USB devices is their dynamic nature: you | ||
| 134 | never know what device a camera gets assigned; it depends on module load | ||
| 135 | order, the hub configuration, the order in which devices are plugged in, | ||
| 136 | and the phase of the moon (i.e. it can be random). With this option you | ||
| 137 | can give the driver a hint as to what video device node (/dev/videoX) it | ||
| 138 | should use with a specific camera. This is also handy if you have two | ||
| 139 | cameras of the same model. | ||
| 140 | |||
| 141 | A camera is specified by its type (the number from the camera model, | ||
| 142 | like PCA645, PCVC750VC, etc) and optionally the serial number (visible | ||
| 143 | in /proc/bus/usb/devices). A hint consists of a string with the following | ||
| 144 | format: | ||
| 145 | |||
| 146 | [type[.serialnumber]:]node | ||
| 147 | |||
| 148 | The square brackets mean that both the type and the serialnumber are | ||
| 149 | optional, but a serialnumber cannot be specified without a type (which | ||
| 150 | would be rather pointless). The serialnumber is separated from the type | ||
| 151 | by a '.'; the node number by a ':'. | ||
| 152 | |||
| 153 | This somewhat cryptic syntax is best explained by a few examples: | ||
| 154 | |||
| 155 | dev_hint=3,5 The first detected cam gets assigned | ||
| 156 | /dev/video3, the second /dev/video5. Any | ||
| 157 | other cameras will get the first free | ||
| 158 | available slot (see below). | ||
| 159 | |||
| 160 | dev_hint=645:1,680:2 The PCA645 camera will get /dev/video1, | ||
| 161 | and a PCVC680 /dev/video2. | ||
| 162 | |||
| 163 | dev_hint=645.0123:3,645.4567:0 The PCA645 camera with serialnumber | ||
| 164 | 0123 goes to /dev/video3, the same | ||
| 165 | camera model with the 4567 serial | ||
| 166 | gets /dev/video0. | ||
| 167 | |||
| 168 | dev_hint=750:1,4,5,6 The PCVC750 camera will get /dev/video1, the | ||
| 169 | next 3 Philips cams will use /dev/video4 | ||
| 170 | through /dev/video6. | ||
| 171 | |||
| 172 | Some points worth knowing: | ||
| 173 | - Serialnumbers are case sensitive and must be written full, including | ||
| 174 | leading zeroes (it's treated as a string). | ||
| 175 | - If a device node is already occupied, registration will fail and | ||
| 176 | the webcam is not available. | ||
| 177 | - You can have up to 64 video devices; be sure to make enough device | ||
| 178 | nodes in /dev if you want to spread the numbers (this does not apply | ||
| 179 | to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA). | ||
| 180 | - If a camera does not match any dev_hint, it will simply get assigned | ||
| 181 | the first available device node, just as it used to be. | ||
| 182 | |||
| 183 | trace | ||
| 184 | In order to better detect problems, it is now possible to turn on a | ||
| 185 | 'trace' of some of the calls the module makes; it logs all items in your | ||
| 186 | kernel log at debug level. | ||
| 187 | |||
| 188 | The trace variable is a bitmask; each bit represents a certain feature. | ||
| 189 | If you want to trace something, look up the bit value(s) in the table | ||
| 190 | below, add the values together and supply that to the trace variable. | ||
| 191 | |||
| 192 | Value Value Description Default | ||
| 193 | (dec) (hex) | ||
| 194 | 1 0x1 Module initialization; this will log messages On | ||
| 195 | while loading and unloading the module | ||
| 196 | |||
| 197 | 2 0x2 probe() and disconnect() traces On | ||
| 198 | |||
| 199 | 4 0x4 Trace open() and close() calls Off | ||
| 200 | |||
| 201 | 8 0x8 read(), mmap() and associated ioctl() calls Off | ||
| 202 | |||
| 203 | 16 0x10 Memory allocation of buffers, etc. Off | ||
| 204 | |||
| 205 | 32 0x20 Showing underflow, overflow and Dumping frame On | ||
| 206 | messages | ||
| 207 | |||
| 208 | 64 0x40 Show viewport and image sizes Off | ||
| 209 | |||
| 210 | 128 0x80 PWCX debugging Off | ||
| 211 | |||
| 212 | For example, to trace the open() & read() fuctions, sum 8 + 4 = 12, | ||
| 213 | so you would supply trace=12 during insmod or modprobe. If | ||
| 214 | you want to turn the initialization and probing tracing off, set trace=0. | ||
| 215 | The default value for trace is 35 (0x23). | ||
| 216 | |||
| 217 | |||
| 218 | |||
| 219 | Example: | ||
| 220 | |||
| 221 | # modprobe pwc size=cif fps=15 power_save=1 | ||
| 222 | |||
| 223 | The fbufs, mbufs and trace parameters are global and apply to all connected | ||
| 224 | cameras. Each camera has its own set of buffers. | ||
| 225 | |||
| 226 | size and fps only specify defaults when you open() the device; this is to | ||
| 227 | accommodate some tools that don't set the size. You can change these | ||
| 228 | settings after open() with the Video4Linux ioctl() calls. The default of | ||
| 229 | defaults is QCIF size at 10 fps. | ||
| 230 | |||
| 231 | The compression parameter is semiglobal; it sets the initial compression | ||
| 232 | preference for all camera's, but this parameter can be set per camera with | ||
| 233 | the VIDIOCPWCSCQUAL ioctl() call. | ||
| 234 | |||
| 235 | All parameters are optional. | ||
| 236 | |||
diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c deleted file mode 100644 index 0398b812e0ce..000000000000 --- a/drivers/usb/media/pwc/pwc-ctrl.c +++ /dev/null | |||
| @@ -1,1541 +0,0 @@ | |||
| 1 | /* Driver for Philips webcam | ||
| 2 | Functions that send various control messages to the webcam, including | ||
| 3 | video modes. | ||
| 4 | (C) 1999-2003 Nemosoft Unv. | ||
| 5 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 6 | |||
| 7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 8 | driver and thus may have bugs that are not present in the original version. | ||
| 9 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 10 | |||
| 11 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 12 | driver and thus may have bugs that are not present in the original version. | ||
| 13 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 14 | The decompression routines have been implemented by reverse-engineering the | ||
| 15 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 16 | |||
| 17 | This program is free software; you can redistribute it and/or modify | ||
| 18 | it under the terms of the GNU General Public License as published by | ||
| 19 | the Free Software Foundation; either version 2 of the License, or | ||
| 20 | (at your option) any later version. | ||
| 21 | |||
| 22 | This program is distributed in the hope that it will be useful, | ||
| 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 25 | GNU General Public License for more details. | ||
| 26 | |||
| 27 | You should have received a copy of the GNU General Public License | ||
| 28 | along with this program; if not, write to the Free Software | ||
| 29 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 30 | */ | ||
| 31 | |||
| 32 | /* | ||
| 33 | Changes | ||
| 34 | 2001/08/03 Alvarado Added methods for changing white balance and | ||
| 35 | red/green gains | ||
| 36 | */ | ||
| 37 | |||
| 38 | /* Control functions for the cam; brightness, contrast, video mode, etc. */ | ||
| 39 | |||
| 40 | #ifdef __KERNEL__ | ||
| 41 | #include <asm/uaccess.h> | ||
| 42 | #endif | ||
| 43 | #include <asm/errno.h> | ||
| 44 | |||
| 45 | #include "pwc.h" | ||
| 46 | #include "pwc-ioctl.h" | ||
| 47 | #include "pwc-uncompress.h" | ||
| 48 | #include "pwc-kiara.h" | ||
| 49 | #include "pwc-timon.h" | ||
| 50 | |||
| 51 | /* Request types: video */ | ||
| 52 | #define SET_LUM_CTL 0x01 | ||
| 53 | #define GET_LUM_CTL 0x02 | ||
| 54 | #define SET_CHROM_CTL 0x03 | ||
| 55 | #define GET_CHROM_CTL 0x04 | ||
| 56 | #define SET_STATUS_CTL 0x05 | ||
| 57 | #define GET_STATUS_CTL 0x06 | ||
| 58 | #define SET_EP_STREAM_CTL 0x07 | ||
| 59 | #define GET_EP_STREAM_CTL 0x08 | ||
| 60 | #define SET_MPT_CTL 0x0D | ||
| 61 | #define GET_MPT_CTL 0x0E | ||
| 62 | |||
| 63 | /* Selectors for the Luminance controls [GS]ET_LUM_CTL */ | ||
| 64 | #define AGC_MODE_FORMATTER 0x2000 | ||
| 65 | #define PRESET_AGC_FORMATTER 0x2100 | ||
| 66 | #define SHUTTER_MODE_FORMATTER 0x2200 | ||
| 67 | #define PRESET_SHUTTER_FORMATTER 0x2300 | ||
| 68 | #define PRESET_CONTOUR_FORMATTER 0x2400 | ||
| 69 | #define AUTO_CONTOUR_FORMATTER 0x2500 | ||
| 70 | #define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 | ||
| 71 | #define CONTRAST_FORMATTER 0x2700 | ||
| 72 | #define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 | ||
| 73 | #define FLICKERLESS_MODE_FORMATTER 0x2900 | ||
| 74 | #define AE_CONTROL_SPEED 0x2A00 | ||
| 75 | #define BRIGHTNESS_FORMATTER 0x2B00 | ||
| 76 | #define GAMMA_FORMATTER 0x2C00 | ||
| 77 | |||
| 78 | /* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ | ||
| 79 | #define WB_MODE_FORMATTER 0x1000 | ||
| 80 | #define AWB_CONTROL_SPEED_FORMATTER 0x1100 | ||
| 81 | #define AWB_CONTROL_DELAY_FORMATTER 0x1200 | ||
| 82 | #define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 | ||
| 83 | #define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 | ||
| 84 | #define COLOUR_MODE_FORMATTER 0x1500 | ||
| 85 | #define SATURATION_MODE_FORMATTER1 0x1600 | ||
| 86 | #define SATURATION_MODE_FORMATTER2 0x1700 | ||
| 87 | |||
| 88 | /* Selectors for the Status controls [GS]ET_STATUS_CTL */ | ||
| 89 | #define SAVE_USER_DEFAULTS_FORMATTER 0x0200 | ||
| 90 | #define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 | ||
| 91 | #define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 | ||
| 92 | #define READ_AGC_FORMATTER 0x0500 | ||
| 93 | #define READ_SHUTTER_FORMATTER 0x0600 | ||
| 94 | #define READ_RED_GAIN_FORMATTER 0x0700 | ||
| 95 | #define READ_BLUE_GAIN_FORMATTER 0x0800 | ||
| 96 | #define SENSOR_TYPE_FORMATTER1 0x0C00 | ||
| 97 | #define READ_RAW_Y_MEAN_FORMATTER 0x3100 | ||
| 98 | #define SET_POWER_SAVE_MODE_FORMATTER 0x3200 | ||
| 99 | #define MIRROR_IMAGE_FORMATTER 0x3300 | ||
| 100 | #define LED_FORMATTER 0x3400 | ||
| 101 | #define SENSOR_TYPE_FORMATTER2 0x3700 | ||
| 102 | |||
| 103 | /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ | ||
| 104 | #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 | ||
| 105 | |||
| 106 | /* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ | ||
| 107 | #define PT_RELATIVE_CONTROL_FORMATTER 0x01 | ||
| 108 | #define PT_RESET_CONTROL_FORMATTER 0x02 | ||
| 109 | #define PT_STATUS_FORMATTER 0x03 | ||
| 110 | |||
| 111 | static const char *size2name[PSZ_MAX] = | ||
| 112 | { | ||
| 113 | "subQCIF", | ||
| 114 | "QSIF", | ||
| 115 | "QCIF", | ||
| 116 | "SIF", | ||
| 117 | "CIF", | ||
| 118 | "VGA", | ||
| 119 | }; | ||
| 120 | |||
| 121 | /********/ | ||
| 122 | |||
| 123 | /* Entries for the Nala (645/646) camera; the Nala doesn't have compression | ||
| 124 | preferences, so you either get compressed or non-compressed streams. | ||
| 125 | |||
| 126 | An alternate value of 0 means this mode is not available at all. | ||
| 127 | */ | ||
| 128 | |||
| 129 | struct Nala_table_entry { | ||
| 130 | char alternate; /* USB alternate setting */ | ||
| 131 | int compressed; /* Compressed yes/no */ | ||
| 132 | |||
| 133 | unsigned char mode[3]; /* precomputed mode table */ | ||
| 134 | }; | ||
| 135 | |||
| 136 | static struct Nala_table_entry Nala_table[PSZ_MAX][8] = | ||
| 137 | { | ||
| 138 | #include "pwc-nala.h" | ||
| 139 | }; | ||
| 140 | |||
| 141 | |||
| 142 | /****************************************************************************/ | ||
| 143 | |||
| 144 | |||
| 145 | #define SendControlMsg(request, value, buflen) \ | ||
| 146 | usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ | ||
| 147 | request, \ | ||
| 148 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ | ||
| 149 | value, \ | ||
| 150 | pdev->vcinterface, \ | ||
| 151 | &buf, buflen, 500) | ||
| 152 | |||
| 153 | #define RecvControlMsg(request, value, buflen) \ | ||
| 154 | usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ | ||
| 155 | request, \ | ||
| 156 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ | ||
| 157 | value, \ | ||
| 158 | pdev->vcinterface, \ | ||
| 159 | &buf, buflen, 500) | ||
| 160 | |||
| 161 | |||
| 162 | #if PWC_DEBUG | ||
| 163 | void pwc_hexdump(void *p, int len) | ||
| 164 | { | ||
| 165 | int i; | ||
| 166 | unsigned char *s; | ||
| 167 | char buf[100], *d; | ||
| 168 | |||
| 169 | s = (unsigned char *)p; | ||
| 170 | d = buf; | ||
| 171 | *d = '\0'; | ||
| 172 | Debug("Doing hexdump @ %p, %d bytes.\n", p, len); | ||
| 173 | for (i = 0; i < len; i++) { | ||
| 174 | d += sprintf(d, "%02X ", *s++); | ||
| 175 | if ((i & 0xF) == 0xF) { | ||
| 176 | Debug("%s\n", buf); | ||
| 177 | d = buf; | ||
| 178 | *d = '\0'; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | if ((i & 0xF) != 0) | ||
| 182 | Debug("%s\n", buf); | ||
| 183 | } | ||
| 184 | #endif | ||
| 185 | |||
| 186 | static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) | ||
| 187 | { | ||
| 188 | return usb_control_msg(udev, | ||
| 189 | usb_sndctrlpipe(udev, 0), | ||
| 190 | SET_EP_STREAM_CTL, | ||
| 191 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 192 | VIDEO_OUTPUT_CONTROL_FORMATTER, | ||
| 193 | index, | ||
| 194 | buf, buflen, 1000); | ||
| 195 | } | ||
| 196 | |||
| 197 | |||
| 198 | |||
| 199 | static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) | ||
| 200 | { | ||
| 201 | unsigned char buf[3]; | ||
| 202 | int ret, fps; | ||
| 203 | struct Nala_table_entry *pEntry; | ||
| 204 | int frames2frames[31] = | ||
| 205 | { /* closest match of framerate */ | ||
| 206 | 0, 0, 0, 0, 4, /* 0-4 */ | ||
| 207 | 5, 5, 7, 7, 10, /* 5-9 */ | ||
| 208 | 10, 10, 12, 12, 15, /* 10-14 */ | ||
| 209 | 15, 15, 15, 20, 20, /* 15-19 */ | ||
| 210 | 20, 20, 20, 24, 24, /* 20-24 */ | ||
| 211 | 24, 24, 24, 24, 24, /* 25-29 */ | ||
| 212 | 24 /* 30 */ | ||
| 213 | }; | ||
| 214 | int frames2table[31] = | ||
| 215 | { 0, 0, 0, 0, 0, /* 0-4 */ | ||
| 216 | 1, 1, 1, 2, 2, /* 5-9 */ | ||
| 217 | 3, 3, 4, 4, 4, /* 10-14 */ | ||
| 218 | 5, 5, 5, 5, 5, /* 15-19 */ | ||
| 219 | 6, 6, 6, 6, 7, /* 20-24 */ | ||
| 220 | 7, 7, 7, 7, 7, /* 25-29 */ | ||
| 221 | 7 /* 30 */ | ||
| 222 | }; | ||
| 223 | |||
| 224 | if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) | ||
| 225 | return -EINVAL; | ||
| 226 | frames = frames2frames[frames]; | ||
| 227 | fps = frames2table[frames]; | ||
| 228 | pEntry = &Nala_table[size][fps]; | ||
| 229 | if (pEntry->alternate == 0) | ||
| 230 | return -EINVAL; | ||
| 231 | |||
| 232 | if (pEntry->compressed) | ||
| 233 | return -ENOENT; /* Not supported. */ | ||
| 234 | |||
| 235 | memcpy(buf, pEntry->mode, 3); | ||
| 236 | ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); | ||
| 237 | if (ret < 0) { | ||
| 238 | Debug("Failed to send video command... %d\n", ret); | ||
| 239 | return ret; | ||
| 240 | } | ||
| 241 | if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) | ||
| 242 | { | ||
| 243 | switch(pdev->type) { | ||
| 244 | case 645: | ||
| 245 | case 646: | ||
| 246 | /* pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ | ||
| 247 | break; | ||
| 248 | |||
| 249 | case 675: | ||
| 250 | case 680: | ||
| 251 | case 690: | ||
| 252 | case 720: | ||
| 253 | case 730: | ||
| 254 | case 740: | ||
| 255 | case 750: | ||
| 256 | /* pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | pdev->cmd_len = 3; | ||
| 262 | memcpy(pdev->cmd_buf, buf, 3); | ||
| 263 | |||
| 264 | /* Set various parameters */ | ||
| 265 | pdev->vframes = frames; | ||
| 266 | pdev->vsize = size; | ||
| 267 | pdev->valternate = pEntry->alternate; | ||
| 268 | pdev->image = pwc_image_sizes[size]; | ||
| 269 | pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; | ||
| 270 | if (pEntry->compressed) { | ||
| 271 | if (pdev->release < 5) { /* 4 fold compression */ | ||
| 272 | pdev->vbandlength = 528; | ||
| 273 | pdev->frame_size /= 4; | ||
| 274 | } | ||
| 275 | else { | ||
| 276 | pdev->vbandlength = 704; | ||
| 277 | pdev->frame_size /= 3; | ||
| 278 | } | ||
| 279 | } | ||
| 280 | else | ||
| 281 | pdev->vbandlength = 0; | ||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | |||
| 286 | static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) | ||
| 287 | { | ||
| 288 | unsigned char buf[13]; | ||
| 289 | const struct Timon_table_entry *pChoose; | ||
| 290 | int ret, fps; | ||
| 291 | |||
| 292 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) | ||
| 293 | return -EINVAL; | ||
| 294 | if (size == PSZ_VGA && frames > 15) | ||
| 295 | return -EINVAL; | ||
| 296 | fps = (frames / 5) - 1; | ||
| 297 | |||
| 298 | /* Find a supported framerate with progressively higher compression ratios | ||
| 299 | if the preferred ratio is not available. | ||
| 300 | */ | ||
| 301 | pChoose = NULL; | ||
| 302 | while (compression <= 3) { | ||
| 303 | pChoose = &Timon_table[size][fps][compression]; | ||
| 304 | if (pChoose->alternate != 0) | ||
| 305 | break; | ||
| 306 | compression++; | ||
| 307 | } | ||
| 308 | if (pChoose == NULL || pChoose->alternate == 0) | ||
| 309 | return -ENOENT; /* Not supported. */ | ||
| 310 | |||
| 311 | memcpy(buf, pChoose->mode, 13); | ||
| 312 | if (snapshot) | ||
| 313 | buf[0] |= 0x80; | ||
| 314 | ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); | ||
| 315 | if (ret < 0) | ||
| 316 | return ret; | ||
| 317 | |||
| 318 | /* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) | ||
| 319 | pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ | ||
| 320 | |||
| 321 | pdev->cmd_len = 13; | ||
| 322 | memcpy(pdev->cmd_buf, buf, 13); | ||
| 323 | |||
| 324 | /* Set various parameters */ | ||
| 325 | pdev->vframes = frames; | ||
| 326 | pdev->vsize = size; | ||
| 327 | pdev->vsnapshot = snapshot; | ||
| 328 | pdev->valternate = pChoose->alternate; | ||
| 329 | pdev->image = pwc_image_sizes[size]; | ||
| 330 | pdev->vbandlength = pChoose->bandlength; | ||
| 331 | if (pChoose->bandlength > 0) | ||
| 332 | pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; | ||
| 333 | else | ||
| 334 | pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; | ||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | |||
| 339 | static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) | ||
| 340 | { | ||
| 341 | const struct Kiara_table_entry *pChoose = NULL; | ||
| 342 | int fps, ret; | ||
| 343 | unsigned char buf[12]; | ||
| 344 | struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; | ||
| 345 | |||
| 346 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) | ||
| 347 | return -EINVAL; | ||
| 348 | if (size == PSZ_VGA && frames > 15) | ||
| 349 | return -EINVAL; | ||
| 350 | fps = (frames / 5) - 1; | ||
| 351 | |||
| 352 | /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ | ||
| 353 | if (size == PSZ_VGA && frames == 5 && snapshot) | ||
| 354 | { | ||
| 355 | /* Only available in case the raw palette is selected or | ||
| 356 | we have the decompressor available. This mode is | ||
| 357 | only available in compressed form | ||
| 358 | */ | ||
| 359 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
| 360 | { | ||
| 361 | Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette); | ||
| 362 | pChoose = &RawEntry; | ||
| 363 | } | ||
| 364 | else | ||
| 365 | { | ||
| 366 | Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | else | ||
| 370 | { | ||
| 371 | /* Find a supported framerate with progressively higher compression ratios | ||
| 372 | if the preferred ratio is not available. | ||
| 373 | Skip this step when using RAW modes. | ||
| 374 | */ | ||
| 375 | while (compression <= 3) { | ||
| 376 | pChoose = &Kiara_table[size][fps][compression]; | ||
| 377 | if (pChoose->alternate != 0) | ||
| 378 | break; | ||
| 379 | compression++; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | if (pChoose == NULL || pChoose->alternate == 0) | ||
| 383 | return -ENOENT; /* Not supported. */ | ||
| 384 | |||
| 385 | Debug("Using alternate setting %d.\n", pChoose->alternate); | ||
| 386 | |||
| 387 | /* usb_control_msg won't take staticly allocated arrays as argument?? */ | ||
| 388 | memcpy(buf, pChoose->mode, 12); | ||
| 389 | if (snapshot) | ||
| 390 | buf[0] |= 0x80; | ||
| 391 | |||
| 392 | /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ | ||
| 393 | ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); | ||
| 394 | if (ret < 0) | ||
| 395 | return ret; | ||
| 396 | |||
| 397 | /* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) | ||
| 398 | pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ | ||
| 399 | |||
| 400 | pdev->cmd_len = 12; | ||
| 401 | memcpy(pdev->cmd_buf, buf, 12); | ||
| 402 | /* All set and go */ | ||
| 403 | pdev->vframes = frames; | ||
| 404 | pdev->vsize = size; | ||
| 405 | pdev->vsnapshot = snapshot; | ||
| 406 | pdev->valternate = pChoose->alternate; | ||
| 407 | pdev->image = pwc_image_sizes[size]; | ||
| 408 | pdev->vbandlength = pChoose->bandlength; | ||
| 409 | if (pdev->vbandlength > 0) | ||
| 410 | pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; | ||
| 411 | else | ||
| 412 | pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; | ||
| 413 | return 0; | ||
| 414 | } | ||
| 415 | |||
| 416 | |||
| 417 | |||
| 418 | static void pwc_set_image_buffer_size(struct pwc_device *pdev) | ||
| 419 | { | ||
| 420 | int i, factor = 0, filler = 0; | ||
| 421 | |||
| 422 | /* for PALETTE_YUV420P */ | ||
| 423 | switch(pdev->vpalette) | ||
| 424 | { | ||
| 425 | case VIDEO_PALETTE_YUV420P: | ||
| 426 | factor = 6; | ||
| 427 | filler = 128; | ||
| 428 | break; | ||
| 429 | case VIDEO_PALETTE_RAW: | ||
| 430 | factor = 6; /* can be uncompressed YUV420P */ | ||
| 431 | filler = 0; | ||
| 432 | break; | ||
| 433 | } | ||
| 434 | |||
| 435 | /* Set sizes in bytes */ | ||
| 436 | pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; | ||
| 437 | pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; | ||
| 438 | |||
| 439 | /* Align offset, or you'll get some very weird results in | ||
| 440 | YUV420 mode... x must be multiple of 4 (to get the Y's in | ||
| 441 | place), and y even (or you'll mixup U & V). This is less of a | ||
| 442 | problem for YUV420P. | ||
| 443 | */ | ||
| 444 | pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; | ||
| 445 | pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; | ||
| 446 | |||
| 447 | /* Fill buffers with gray or black */ | ||
| 448 | for (i = 0; i < MAX_IMAGES; i++) { | ||
| 449 | if (pdev->image_ptr[i] != NULL) | ||
| 450 | memset(pdev->image_ptr[i], filler, pdev->view.size); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | |||
| 454 | |||
| 455 | |||
| 456 | /** | ||
| 457 | @pdev: device structure | ||
| 458 | @width: viewport width | ||
| 459 | @height: viewport height | ||
| 460 | @frame: framerate, in fps | ||
| 461 | @compression: preferred compression ratio | ||
| 462 | @snapshot: snapshot mode or streaming | ||
| 463 | */ | ||
| 464 | int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) | ||
| 465 | { | ||
| 466 | int ret, size; | ||
| 467 | |||
| 468 | Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); | ||
| 469 | size = pwc_decode_size(pdev, width, height); | ||
| 470 | if (size < 0) { | ||
| 471 | Debug("Could not find suitable size.\n"); | ||
| 472 | return -ERANGE; | ||
| 473 | } | ||
| 474 | Debug("decode_size = %d.\n", size); | ||
| 475 | |||
| 476 | ret = -EINVAL; | ||
| 477 | switch(pdev->type) { | ||
| 478 | case 645: | ||
| 479 | case 646: | ||
| 480 | ret = set_video_mode_Nala(pdev, size, frames); | ||
| 481 | break; | ||
| 482 | |||
| 483 | case 675: | ||
| 484 | case 680: | ||
| 485 | case 690: | ||
| 486 | ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); | ||
| 487 | break; | ||
| 488 | |||
| 489 | case 720: | ||
| 490 | case 730: | ||
| 491 | case 740: | ||
| 492 | case 750: | ||
| 493 | ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); | ||
| 494 | break; | ||
| 495 | } | ||
| 496 | if (ret < 0) { | ||
| 497 | if (ret == -ENOENT) | ||
| 498 | Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames); | ||
| 499 | else { | ||
| 500 | Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); | ||
| 501 | } | ||
| 502 | return ret; | ||
| 503 | } | ||
| 504 | pdev->view.x = width; | ||
| 505 | pdev->view.y = height; | ||
| 506 | pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; | ||
| 507 | pwc_set_image_buffer_size(pdev); | ||
| 508 | Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); | ||
| 509 | return 0; | ||
| 510 | } | ||
| 511 | |||
| 512 | |||
| 513 | /* BRIGHTNESS */ | ||
| 514 | |||
| 515 | int pwc_get_brightness(struct pwc_device *pdev) | ||
| 516 | { | ||
| 517 | char buf; | ||
| 518 | int ret; | ||
| 519 | |||
| 520 | ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); | ||
| 521 | if (ret < 0) | ||
| 522 | return ret; | ||
| 523 | return buf << 9; | ||
| 524 | } | ||
| 525 | |||
| 526 | int pwc_set_brightness(struct pwc_device *pdev, int value) | ||
| 527 | { | ||
| 528 | char buf; | ||
| 529 | |||
| 530 | if (value < 0) | ||
| 531 | value = 0; | ||
| 532 | if (value > 0xffff) | ||
| 533 | value = 0xffff; | ||
| 534 | buf = (value >> 9) & 0x7f; | ||
| 535 | return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); | ||
| 536 | } | ||
| 537 | |||
| 538 | /* CONTRAST */ | ||
| 539 | |||
| 540 | int pwc_get_contrast(struct pwc_device *pdev) | ||
| 541 | { | ||
| 542 | char buf; | ||
| 543 | int ret; | ||
| 544 | |||
| 545 | ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); | ||
| 546 | if (ret < 0) | ||
| 547 | return ret; | ||
| 548 | return buf << 10; | ||
| 549 | } | ||
| 550 | |||
| 551 | int pwc_set_contrast(struct pwc_device *pdev, int value) | ||
| 552 | { | ||
| 553 | char buf; | ||
| 554 | |||
| 555 | if (value < 0) | ||
| 556 | value = 0; | ||
| 557 | if (value > 0xffff) | ||
| 558 | value = 0xffff; | ||
| 559 | buf = (value >> 10) & 0x3f; | ||
| 560 | return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1); | ||
| 561 | } | ||
| 562 | |||
| 563 | /* GAMMA */ | ||
| 564 | |||
| 565 | int pwc_get_gamma(struct pwc_device *pdev) | ||
| 566 | { | ||
| 567 | char buf; | ||
| 568 | int ret; | ||
| 569 | |||
| 570 | ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); | ||
| 571 | if (ret < 0) | ||
| 572 | return ret; | ||
| 573 | return buf << 11; | ||
| 574 | } | ||
| 575 | |||
| 576 | int pwc_set_gamma(struct pwc_device *pdev, int value) | ||
| 577 | { | ||
| 578 | char buf; | ||
| 579 | |||
| 580 | if (value < 0) | ||
| 581 | value = 0; | ||
| 582 | if (value > 0xffff) | ||
| 583 | value = 0xffff; | ||
| 584 | buf = (value >> 11) & 0x1f; | ||
| 585 | return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1); | ||
| 586 | } | ||
| 587 | |||
| 588 | |||
| 589 | /* SATURATION */ | ||
| 590 | |||
| 591 | int pwc_get_saturation(struct pwc_device *pdev) | ||
| 592 | { | ||
| 593 | char buf; | ||
| 594 | int ret; | ||
| 595 | |||
| 596 | if (pdev->type < 675) | ||
| 597 | return -1; | ||
| 598 | ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); | ||
| 599 | if (ret < 0) | ||
| 600 | return ret; | ||
| 601 | return 32768 + buf * 327; | ||
| 602 | } | ||
| 603 | |||
| 604 | int pwc_set_saturation(struct pwc_device *pdev, int value) | ||
| 605 | { | ||
| 606 | char buf; | ||
| 607 | |||
| 608 | if (pdev->type < 675) | ||
| 609 | return -EINVAL; | ||
| 610 | if (value < 0) | ||
| 611 | value = 0; | ||
| 612 | if (value > 0xffff) | ||
| 613 | value = 0xffff; | ||
| 614 | /* saturation ranges from -100 to +100 */ | ||
| 615 | buf = (value - 32768) / 327; | ||
| 616 | return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); | ||
| 617 | } | ||
| 618 | |||
| 619 | /* AGC */ | ||
| 620 | |||
| 621 | static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value) | ||
| 622 | { | ||
| 623 | char buf; | ||
| 624 | int ret; | ||
| 625 | |||
| 626 | if (mode) | ||
| 627 | buf = 0x0; /* auto */ | ||
| 628 | else | ||
| 629 | buf = 0xff; /* fixed */ | ||
| 630 | |||
| 631 | ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); | ||
| 632 | |||
| 633 | if (!mode && ret >= 0) { | ||
| 634 | if (value < 0) | ||
| 635 | value = 0; | ||
| 636 | if (value > 0xffff) | ||
| 637 | value = 0xffff; | ||
| 638 | buf = (value >> 10) & 0x3F; | ||
| 639 | ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1); | ||
| 640 | } | ||
| 641 | if (ret < 0) | ||
| 642 | return ret; | ||
| 643 | return 0; | ||
| 644 | } | ||
| 645 | |||
| 646 | static inline int pwc_get_agc(struct pwc_device *pdev, int *value) | ||
| 647 | { | ||
| 648 | unsigned char buf; | ||
| 649 | int ret; | ||
| 650 | |||
| 651 | ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); | ||
| 652 | if (ret < 0) | ||
| 653 | return ret; | ||
| 654 | |||
| 655 | if (buf != 0) { /* fixed */ | ||
| 656 | ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1); | ||
| 657 | if (ret < 0) | ||
| 658 | return ret; | ||
| 659 | if (buf > 0x3F) | ||
| 660 | buf = 0x3F; | ||
| 661 | *value = (buf << 10); | ||
| 662 | } | ||
| 663 | else { /* auto */ | ||
| 664 | ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1); | ||
| 665 | if (ret < 0) | ||
| 666 | return ret; | ||
| 667 | /* Gah... this value ranges from 0x00 ... 0x9F */ | ||
| 668 | if (buf > 0x9F) | ||
| 669 | buf = 0x9F; | ||
| 670 | *value = -(48 + buf * 409); | ||
| 671 | } | ||
| 672 | |||
| 673 | return 0; | ||
| 674 | } | ||
| 675 | |||
| 676 | static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) | ||
| 677 | { | ||
| 678 | char buf[2]; | ||
| 679 | int speed, ret; | ||
| 680 | |||
| 681 | |||
| 682 | if (mode) | ||
| 683 | buf[0] = 0x0; /* auto */ | ||
| 684 | else | ||
| 685 | buf[0] = 0xff; /* fixed */ | ||
| 686 | |||
| 687 | ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); | ||
| 688 | |||
| 689 | if (!mode && ret >= 0) { | ||
| 690 | if (value < 0) | ||
| 691 | value = 0; | ||
| 692 | if (value > 0xffff) | ||
| 693 | value = 0xffff; | ||
| 694 | switch(pdev->type) { | ||
| 695 | case 675: | ||
| 696 | case 680: | ||
| 697 | case 690: | ||
| 698 | /* speed ranges from 0x0 to 0x290 (656) */ | ||
| 699 | speed = (value / 100); | ||
| 700 | buf[1] = speed >> 8; | ||
| 701 | buf[0] = speed & 0xff; | ||
| 702 | break; | ||
| 703 | case 720: | ||
| 704 | case 730: | ||
| 705 | case 740: | ||
| 706 | case 750: | ||
| 707 | /* speed seems to range from 0x0 to 0xff */ | ||
| 708 | buf[1] = 0; | ||
| 709 | buf[0] = value >> 8; | ||
| 710 | break; | ||
| 711 | } | ||
| 712 | |||
| 713 | ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); | ||
| 714 | } | ||
| 715 | return ret; | ||
| 716 | } | ||
| 717 | |||
| 718 | |||
| 719 | /* POWER */ | ||
| 720 | |||
| 721 | int pwc_camera_power(struct pwc_device *pdev, int power) | ||
| 722 | { | ||
| 723 | char buf; | ||
| 724 | |||
| 725 | if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) | ||
| 726 | return 0; /* Not supported by Nala or Timon < release 6 */ | ||
| 727 | |||
| 728 | if (power) | ||
| 729 | buf = 0x00; /* active */ | ||
| 730 | else | ||
| 731 | buf = 0xFF; /* power save */ | ||
| 732 | return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1); | ||
| 733 | } | ||
| 734 | |||
| 735 | |||
| 736 | |||
| 737 | /* private calls */ | ||
| 738 | |||
| 739 | static inline int pwc_restore_user(struct pwc_device *pdev) | ||
| 740 | { | ||
| 741 | char buf; /* dummy */ | ||
| 742 | return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0); | ||
| 743 | } | ||
| 744 | |||
| 745 | static inline int pwc_save_user(struct pwc_device *pdev) | ||
| 746 | { | ||
| 747 | char buf; /* dummy */ | ||
| 748 | return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0); | ||
| 749 | } | ||
| 750 | |||
| 751 | static inline int pwc_restore_factory(struct pwc_device *pdev) | ||
| 752 | { | ||
| 753 | char buf; /* dummy */ | ||
| 754 | return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); | ||
| 755 | } | ||
| 756 | |||
| 757 | /* ************************************************* */ | ||
| 758 | /* Patch by Alvarado: (not in the original version */ | ||
| 759 | |||
| 760 | /* | ||
| 761 | * the camera recognizes modes from 0 to 4: | ||
| 762 | * | ||
| 763 | * 00: indoor (incandescant lighting) | ||
| 764 | * 01: outdoor (sunlight) | ||
| 765 | * 02: fluorescent lighting | ||
| 766 | * 03: manual | ||
| 767 | * 04: auto | ||
| 768 | */ | ||
| 769 | static inline int pwc_set_awb(struct pwc_device *pdev, int mode) | ||
| 770 | { | ||
| 771 | char buf; | ||
| 772 | int ret; | ||
| 773 | |||
| 774 | if (mode < 0) | ||
| 775 | mode = 0; | ||
| 776 | |||
| 777 | if (mode > 4) | ||
| 778 | mode = 4; | ||
| 779 | |||
| 780 | buf = mode & 0x07; /* just the lowest three bits */ | ||
| 781 | |||
| 782 | ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); | ||
| 783 | |||
| 784 | if (ret < 0) | ||
| 785 | return ret; | ||
| 786 | return 0; | ||
| 787 | } | ||
| 788 | |||
| 789 | static inline int pwc_get_awb(struct pwc_device *pdev) | ||
| 790 | { | ||
| 791 | unsigned char buf; | ||
| 792 | int ret; | ||
| 793 | |||
| 794 | ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); | ||
| 795 | |||
| 796 | if (ret < 0) | ||
| 797 | return ret; | ||
| 798 | return buf; | ||
| 799 | } | ||
| 800 | |||
| 801 | static inline int pwc_set_red_gain(struct pwc_device *pdev, int value) | ||
| 802 | { | ||
| 803 | unsigned char buf; | ||
| 804 | |||
| 805 | if (value < 0) | ||
| 806 | value = 0; | ||
| 807 | if (value > 0xffff) | ||
| 808 | value = 0xffff; | ||
| 809 | /* only the msb is considered */ | ||
| 810 | buf = value >> 8; | ||
| 811 | return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); | ||
| 812 | } | ||
| 813 | |||
| 814 | static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value) | ||
| 815 | { | ||
| 816 | unsigned char buf; | ||
| 817 | int ret; | ||
| 818 | |||
| 819 | ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); | ||
| 820 | if (ret < 0) | ||
| 821 | return ret; | ||
| 822 | *value = buf << 8; | ||
| 823 | return 0; | ||
| 824 | } | ||
| 825 | |||
| 826 | |||
| 827 | static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value) | ||
| 828 | { | ||
| 829 | unsigned char buf; | ||
| 830 | |||
| 831 | if (value < 0) | ||
| 832 | value = 0; | ||
| 833 | if (value > 0xffff) | ||
| 834 | value = 0xffff; | ||
| 835 | /* only the msb is considered */ | ||
| 836 | buf = value >> 8; | ||
| 837 | return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); | ||
| 838 | } | ||
| 839 | |||
| 840 | static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value) | ||
| 841 | { | ||
| 842 | unsigned char buf; | ||
| 843 | int ret; | ||
| 844 | |||
| 845 | ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); | ||
| 846 | if (ret < 0) | ||
| 847 | return ret; | ||
| 848 | *value = buf << 8; | ||
| 849 | return 0; | ||
| 850 | } | ||
| 851 | |||
| 852 | |||
| 853 | /* The following two functions are different, since they only read the | ||
| 854 | internal red/blue gains, which may be different from the manual | ||
| 855 | gains set or read above. | ||
| 856 | */ | ||
| 857 | static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value) | ||
| 858 | { | ||
| 859 | unsigned char buf; | ||
| 860 | int ret; | ||
| 861 | |||
| 862 | ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); | ||
| 863 | if (ret < 0) | ||
| 864 | return ret; | ||
| 865 | *value = buf << 8; | ||
| 866 | return 0; | ||
| 867 | } | ||
| 868 | |||
| 869 | static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value) | ||
| 870 | { | ||
| 871 | unsigned char buf; | ||
| 872 | int ret; | ||
| 873 | |||
| 874 | ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); | ||
| 875 | if (ret < 0) | ||
| 876 | return ret; | ||
| 877 | *value = buf << 8; | ||
| 878 | return 0; | ||
| 879 | } | ||
| 880 | |||
| 881 | |||
| 882 | static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) | ||
| 883 | { | ||
| 884 | unsigned char buf; | ||
| 885 | |||
| 886 | /* useful range is 0x01..0x20 */ | ||
| 887 | buf = speed / 0x7f0; | ||
| 888 | return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); | ||
| 889 | } | ||
| 890 | |||
| 891 | static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value) | ||
| 892 | { | ||
| 893 | unsigned char buf; | ||
| 894 | int ret; | ||
| 895 | |||
| 896 | ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); | ||
| 897 | if (ret < 0) | ||
| 898 | return ret; | ||
| 899 | *value = buf * 0x7f0; | ||
| 900 | return 0; | ||
| 901 | } | ||
| 902 | |||
| 903 | |||
| 904 | static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) | ||
| 905 | { | ||
| 906 | unsigned char buf; | ||
| 907 | |||
| 908 | /* useful range is 0x01..0x3F */ | ||
| 909 | buf = (delay >> 10); | ||
| 910 | return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); | ||
| 911 | } | ||
| 912 | |||
| 913 | static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value) | ||
| 914 | { | ||
| 915 | unsigned char buf; | ||
| 916 | int ret; | ||
| 917 | |||
| 918 | ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); | ||
| 919 | if (ret < 0) | ||
| 920 | return ret; | ||
| 921 | *value = buf << 10; | ||
| 922 | return 0; | ||
| 923 | } | ||
| 924 | |||
| 925 | |||
| 926 | int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) | ||
| 927 | { | ||
| 928 | unsigned char buf[2]; | ||
| 929 | |||
| 930 | if (pdev->type < 730) | ||
| 931 | return 0; | ||
| 932 | on_value /= 100; | ||
| 933 | off_value /= 100; | ||
| 934 | if (on_value < 0) | ||
| 935 | on_value = 0; | ||
| 936 | if (on_value > 0xff) | ||
| 937 | on_value = 0xff; | ||
| 938 | if (off_value < 0) | ||
| 939 | off_value = 0; | ||
| 940 | if (off_value > 0xff) | ||
| 941 | off_value = 0xff; | ||
| 942 | |||
| 943 | buf[0] = on_value; | ||
| 944 | buf[1] = off_value; | ||
| 945 | |||
| 946 | return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); | ||
| 947 | } | ||
| 948 | |||
| 949 | static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) | ||
| 950 | { | ||
| 951 | unsigned char buf[2]; | ||
| 952 | int ret; | ||
| 953 | |||
| 954 | if (pdev->type < 730) { | ||
| 955 | *on_value = -1; | ||
| 956 | *off_value = -1; | ||
| 957 | return 0; | ||
| 958 | } | ||
| 959 | |||
| 960 | ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); | ||
| 961 | if (ret < 0) | ||
| 962 | return ret; | ||
| 963 | *on_value = buf[0] * 100; | ||
| 964 | *off_value = buf[1] * 100; | ||
| 965 | return 0; | ||
| 966 | } | ||
| 967 | |||
| 968 | static inline int pwc_set_contour(struct pwc_device *pdev, int contour) | ||
| 969 | { | ||
| 970 | unsigned char buf; | ||
| 971 | int ret; | ||
| 972 | |||
| 973 | if (contour < 0) | ||
| 974 | buf = 0xff; /* auto contour on */ | ||
| 975 | else | ||
| 976 | buf = 0x0; /* auto contour off */ | ||
| 977 | ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); | ||
| 978 | if (ret < 0) | ||
| 979 | return ret; | ||
| 980 | |||
| 981 | if (contour < 0) | ||
| 982 | return 0; | ||
| 983 | if (contour > 0xffff) | ||
| 984 | contour = 0xffff; | ||
| 985 | |||
| 986 | buf = (contour >> 10); /* contour preset is [0..3f] */ | ||
| 987 | ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); | ||
| 988 | if (ret < 0) | ||
| 989 | return ret; | ||
| 990 | return 0; | ||
| 991 | } | ||
| 992 | |||
| 993 | static inline int pwc_get_contour(struct pwc_device *pdev, int *contour) | ||
| 994 | { | ||
| 995 | unsigned char buf; | ||
| 996 | int ret; | ||
| 997 | |||
| 998 | ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); | ||
| 999 | if (ret < 0) | ||
| 1000 | return ret; | ||
| 1001 | |||
| 1002 | if (buf == 0) { | ||
| 1003 | /* auto mode off, query current preset value */ | ||
| 1004 | ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); | ||
| 1005 | if (ret < 0) | ||
| 1006 | return ret; | ||
| 1007 | *contour = buf << 10; | ||
| 1008 | } | ||
| 1009 | else | ||
| 1010 | *contour = -1; | ||
| 1011 | return 0; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | |||
| 1015 | static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight) | ||
| 1016 | { | ||
| 1017 | unsigned char buf; | ||
| 1018 | |||
| 1019 | if (backlight) | ||
| 1020 | buf = 0xff; | ||
| 1021 | else | ||
| 1022 | buf = 0x0; | ||
| 1023 | return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight) | ||
| 1027 | { | ||
| 1028 | int ret; | ||
| 1029 | unsigned char buf; | ||
| 1030 | |||
| 1031 | ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); | ||
| 1032 | if (ret < 0) | ||
| 1033 | return ret; | ||
| 1034 | *backlight = buf; | ||
| 1035 | return 0; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | |||
| 1039 | static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker) | ||
| 1040 | { | ||
| 1041 | unsigned char buf; | ||
| 1042 | |||
| 1043 | if (flicker) | ||
| 1044 | buf = 0xff; | ||
| 1045 | else | ||
| 1046 | buf = 0x0; | ||
| 1047 | return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker) | ||
| 1051 | { | ||
| 1052 | int ret; | ||
| 1053 | unsigned char buf; | ||
| 1054 | |||
| 1055 | ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); | ||
| 1056 | if (ret < 0) | ||
| 1057 | return ret; | ||
| 1058 | *flicker = buf; | ||
| 1059 | return 0; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | |||
| 1063 | static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) | ||
| 1064 | { | ||
| 1065 | unsigned char buf; | ||
| 1066 | |||
| 1067 | if (noise < 0) | ||
| 1068 | noise = 0; | ||
| 1069 | if (noise > 3) | ||
| 1070 | noise = 3; | ||
| 1071 | buf = noise; | ||
| 1072 | return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) | ||
| 1076 | { | ||
| 1077 | int ret; | ||
| 1078 | unsigned char buf; | ||
| 1079 | |||
| 1080 | ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); | ||
| 1081 | if (ret < 0) | ||
| 1082 | return ret; | ||
| 1083 | *noise = buf; | ||
| 1084 | return 0; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | static int pwc_mpt_reset(struct pwc_device *pdev, int flags) | ||
| 1088 | { | ||
| 1089 | unsigned char buf; | ||
| 1090 | |||
| 1091 | buf = flags & 0x03; // only lower two bits are currently used | ||
| 1092 | return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) | ||
| 1096 | { | ||
| 1097 | unsigned char buf[4]; | ||
| 1098 | |||
| 1099 | /* set new relative angle; angles are expressed in degrees * 100, | ||
| 1100 | but cam as .5 degree resolution, hence divide by 200. Also | ||
| 1101 | the angle must be multiplied by 64 before it's send to | ||
| 1102 | the cam (??) | ||
| 1103 | */ | ||
| 1104 | pan = 64 * pan / 100; | ||
| 1105 | tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ | ||
| 1106 | buf[0] = pan & 0xFF; | ||
| 1107 | buf[1] = (pan >> 8) & 0xFF; | ||
| 1108 | buf[2] = tilt & 0xFF; | ||
| 1109 | buf[3] = (tilt >> 8) & 0xFF; | ||
| 1110 | return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) | ||
| 1114 | { | ||
| 1115 | int ret; | ||
| 1116 | unsigned char buf[5]; | ||
| 1117 | |||
| 1118 | ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5); | ||
| 1119 | if (ret < 0) | ||
| 1120 | return ret; | ||
| 1121 | status->status = buf[0] & 0x7; // 3 bits are used for reporting | ||
| 1122 | status->time_pan = (buf[1] << 8) + buf[2]; | ||
| 1123 | status->time_tilt = (buf[3] << 8) + buf[4]; | ||
| 1124 | return 0; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | |||
| 1128 | int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) | ||
| 1129 | { | ||
| 1130 | unsigned char buf; | ||
| 1131 | int ret = -1, request; | ||
| 1132 | |||
| 1133 | if (pdev->type < 675) | ||
| 1134 | request = SENSOR_TYPE_FORMATTER1; | ||
| 1135 | else if (pdev->type < 730) | ||
| 1136 | return -1; /* The Vesta series doesn't have this call */ | ||
| 1137 | else | ||
| 1138 | request = SENSOR_TYPE_FORMATTER2; | ||
| 1139 | |||
| 1140 | ret = RecvControlMsg(GET_STATUS_CTL, request, 1); | ||
| 1141 | if (ret < 0) | ||
| 1142 | return ret; | ||
| 1143 | if (pdev->type < 675) | ||
| 1144 | *sensor = buf | 0x100; | ||
| 1145 | else | ||
| 1146 | *sensor = buf; | ||
| 1147 | return 0; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | |||
| 1151 | /* End of Add-Ons */ | ||
| 1152 | /* ************************************************* */ | ||
| 1153 | |||
| 1154 | |||
| 1155 | int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | ||
| 1156 | { | ||
| 1157 | int ret = 0; | ||
| 1158 | |||
| 1159 | switch(cmd) { | ||
| 1160 | case VIDIOCPWCRUSER: | ||
| 1161 | { | ||
| 1162 | if (pwc_restore_user(pdev)) | ||
| 1163 | ret = -EINVAL; | ||
| 1164 | break; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | case VIDIOCPWCSUSER: | ||
| 1168 | { | ||
| 1169 | if (pwc_save_user(pdev)) | ||
| 1170 | ret = -EINVAL; | ||
| 1171 | break; | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | case VIDIOCPWCFACTORY: | ||
| 1175 | { | ||
| 1176 | if (pwc_restore_factory(pdev)) | ||
| 1177 | ret = -EINVAL; | ||
| 1178 | break; | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | case VIDIOCPWCSCQUAL: | ||
| 1182 | { | ||
| 1183 | int *qual = arg; | ||
| 1184 | |||
| 1185 | if (*qual < 0 || *qual > 3) | ||
| 1186 | ret = -EINVAL; | ||
| 1187 | else | ||
| 1188 | ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot); | ||
| 1189 | if (ret >= 0) | ||
| 1190 | pdev->vcompression = *qual; | ||
| 1191 | break; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | case VIDIOCPWCGCQUAL: | ||
| 1195 | { | ||
| 1196 | int *qual = arg; | ||
| 1197 | *qual = pdev->vcompression; | ||
| 1198 | break; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | case VIDIOCPWCPROBE: | ||
| 1202 | { | ||
| 1203 | struct pwc_probe *probe = arg; | ||
| 1204 | strcpy(probe->name, pdev->vdev->name); | ||
| 1205 | probe->type = pdev->type; | ||
| 1206 | break; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | case VIDIOCPWCGSERIAL: | ||
| 1210 | { | ||
| 1211 | struct pwc_serial *serial = arg; | ||
| 1212 | strcpy(serial->serial, pdev->serial); | ||
| 1213 | break; | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | case VIDIOCPWCSAGC: | ||
| 1217 | { | ||
| 1218 | int *agc = arg; | ||
| 1219 | if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc)) | ||
| 1220 | ret = -EINVAL; | ||
| 1221 | break; | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | case VIDIOCPWCGAGC: | ||
| 1225 | { | ||
| 1226 | int *agc = arg; | ||
| 1227 | |||
| 1228 | if (pwc_get_agc(pdev, agc)) | ||
| 1229 | ret = -EINVAL; | ||
| 1230 | break; | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | case VIDIOCPWCSSHUTTER: | ||
| 1234 | { | ||
| 1235 | int *shutter_speed = arg; | ||
| 1236 | ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed); | ||
| 1237 | break; | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | case VIDIOCPWCSAWB: | ||
| 1241 | { | ||
| 1242 | struct pwc_whitebalance *wb = arg; | ||
| 1243 | |||
| 1244 | ret = pwc_set_awb(pdev, wb->mode); | ||
| 1245 | if (ret >= 0 && wb->mode == PWC_WB_MANUAL) { | ||
| 1246 | pwc_set_red_gain(pdev, wb->manual_red); | ||
| 1247 | pwc_set_blue_gain(pdev, wb->manual_blue); | ||
| 1248 | } | ||
| 1249 | break; | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | case VIDIOCPWCGAWB: | ||
| 1253 | { | ||
| 1254 | struct pwc_whitebalance *wb = arg; | ||
| 1255 | |||
| 1256 | memset(wb, 0, sizeof(struct pwc_whitebalance)); | ||
| 1257 | wb->mode = pwc_get_awb(pdev); | ||
| 1258 | if (wb->mode < 0) | ||
| 1259 | ret = -EINVAL; | ||
| 1260 | else { | ||
| 1261 | if (wb->mode == PWC_WB_MANUAL) { | ||
| 1262 | ret = pwc_get_red_gain(pdev, &wb->manual_red); | ||
| 1263 | if (ret < 0) | ||
| 1264 | break; | ||
| 1265 | ret = pwc_get_blue_gain(pdev, &wb->manual_blue); | ||
| 1266 | if (ret < 0) | ||
| 1267 | break; | ||
| 1268 | } | ||
| 1269 | if (wb->mode == PWC_WB_AUTO) { | ||
| 1270 | ret = pwc_read_red_gain(pdev, &wb->read_red); | ||
| 1271 | if (ret < 0) | ||
| 1272 | break; | ||
| 1273 | ret = pwc_read_blue_gain(pdev, &wb->read_blue); | ||
| 1274 | if (ret < 0) | ||
| 1275 | break; | ||
| 1276 | } | ||
| 1277 | } | ||
| 1278 | break; | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | case VIDIOCPWCSAWBSPEED: | ||
| 1282 | { | ||
| 1283 | struct pwc_wb_speed *wbs = arg; | ||
| 1284 | |||
| 1285 | if (wbs->control_speed > 0) { | ||
| 1286 | ret = pwc_set_wb_speed(pdev, wbs->control_speed); | ||
| 1287 | } | ||
| 1288 | if (wbs->control_delay > 0) { | ||
| 1289 | ret = pwc_set_wb_delay(pdev, wbs->control_delay); | ||
| 1290 | } | ||
| 1291 | break; | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | case VIDIOCPWCGAWBSPEED: | ||
| 1295 | { | ||
| 1296 | struct pwc_wb_speed *wbs = arg; | ||
| 1297 | |||
| 1298 | ret = pwc_get_wb_speed(pdev, &wbs->control_speed); | ||
| 1299 | if (ret < 0) | ||
| 1300 | break; | ||
| 1301 | ret = pwc_get_wb_delay(pdev, &wbs->control_delay); | ||
| 1302 | if (ret < 0) | ||
| 1303 | break; | ||
| 1304 | break; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | case VIDIOCPWCSLED: | ||
| 1308 | { | ||
| 1309 | struct pwc_leds *leds = arg; | ||
| 1310 | ret = pwc_set_leds(pdev, leds->led_on, leds->led_off); | ||
| 1311 | break; | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | |||
| 1315 | case VIDIOCPWCGLED: | ||
| 1316 | { | ||
| 1317 | struct pwc_leds *leds = arg; | ||
| 1318 | ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off); | ||
| 1319 | break; | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | case VIDIOCPWCSCONTOUR: | ||
| 1323 | { | ||
| 1324 | int *contour = arg; | ||
| 1325 | ret = pwc_set_contour(pdev, *contour); | ||
| 1326 | break; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | case VIDIOCPWCGCONTOUR: | ||
| 1330 | { | ||
| 1331 | int *contour = arg; | ||
| 1332 | ret = pwc_get_contour(pdev, contour); | ||
| 1333 | break; | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | case VIDIOCPWCSBACKLIGHT: | ||
| 1337 | { | ||
| 1338 | int *backlight = arg; | ||
| 1339 | ret = pwc_set_backlight(pdev, *backlight); | ||
| 1340 | break; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | case VIDIOCPWCGBACKLIGHT: | ||
| 1344 | { | ||
| 1345 | int *backlight = arg; | ||
| 1346 | ret = pwc_get_backlight(pdev, backlight); | ||
| 1347 | break; | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | case VIDIOCPWCSFLICKER: | ||
| 1351 | { | ||
| 1352 | int *flicker = arg; | ||
| 1353 | ret = pwc_set_flicker(pdev, *flicker); | ||
| 1354 | break; | ||
| 1355 | } | ||
| 1356 | |||
| 1357 | case VIDIOCPWCGFLICKER: | ||
| 1358 | { | ||
| 1359 | int *flicker = arg; | ||
| 1360 | ret = pwc_get_flicker(pdev, flicker); | ||
| 1361 | break; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | case VIDIOCPWCSDYNNOISE: | ||
| 1365 | { | ||
| 1366 | int *dynnoise = arg; | ||
| 1367 | ret = pwc_set_dynamic_noise(pdev, *dynnoise); | ||
| 1368 | break; | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | case VIDIOCPWCGDYNNOISE: | ||
| 1372 | { | ||
| 1373 | int *dynnoise = arg; | ||
| 1374 | ret = pwc_get_dynamic_noise(pdev, dynnoise); | ||
| 1375 | break; | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | case VIDIOCPWCGREALSIZE: | ||
| 1379 | { | ||
| 1380 | struct pwc_imagesize *size = arg; | ||
| 1381 | size->width = pdev->image.x; | ||
| 1382 | size->height = pdev->image.y; | ||
| 1383 | break; | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | case VIDIOCPWCMPTRESET: | ||
| 1387 | { | ||
| 1388 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
| 1389 | { | ||
| 1390 | int *flags = arg; | ||
| 1391 | |||
| 1392 | ret = pwc_mpt_reset(pdev, *flags); | ||
| 1393 | if (ret >= 0) | ||
| 1394 | { | ||
| 1395 | pdev->pan_angle = 0; | ||
| 1396 | pdev->tilt_angle = 0; | ||
| 1397 | } | ||
| 1398 | } | ||
| 1399 | else | ||
| 1400 | { | ||
| 1401 | ret = -ENXIO; | ||
| 1402 | } | ||
| 1403 | break; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | case VIDIOCPWCMPTGRANGE: | ||
| 1407 | { | ||
| 1408 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
| 1409 | { | ||
| 1410 | struct pwc_mpt_range *range = arg; | ||
| 1411 | *range = pdev->angle_range; | ||
| 1412 | } | ||
| 1413 | else | ||
| 1414 | { | ||
| 1415 | ret = -ENXIO; | ||
| 1416 | } | ||
| 1417 | break; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | case VIDIOCPWCMPTSANGLE: | ||
| 1421 | { | ||
| 1422 | int new_pan, new_tilt; | ||
| 1423 | |||
| 1424 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
| 1425 | { | ||
| 1426 | struct pwc_mpt_angles *angles = arg; | ||
| 1427 | /* The camera can only set relative angles, so | ||
| 1428 | do some calculations when getting an absolute angle . | ||
| 1429 | */ | ||
| 1430 | if (angles->absolute) | ||
| 1431 | { | ||
| 1432 | new_pan = angles->pan; | ||
| 1433 | new_tilt = angles->tilt; | ||
| 1434 | } | ||
| 1435 | else | ||
| 1436 | { | ||
| 1437 | new_pan = pdev->pan_angle + angles->pan; | ||
| 1438 | new_tilt = pdev->tilt_angle + angles->tilt; | ||
| 1439 | } | ||
| 1440 | /* check absolute ranges */ | ||
| 1441 | if (new_pan < pdev->angle_range.pan_min || | ||
| 1442 | new_pan > pdev->angle_range.pan_max || | ||
| 1443 | new_tilt < pdev->angle_range.tilt_min || | ||
| 1444 | new_tilt > pdev->angle_range.tilt_max) | ||
| 1445 | { | ||
| 1446 | ret = -ERANGE; | ||
| 1447 | } | ||
| 1448 | else | ||
| 1449 | { | ||
| 1450 | /* go to relative range, check again */ | ||
| 1451 | new_pan -= pdev->pan_angle; | ||
| 1452 | new_tilt -= pdev->tilt_angle; | ||
| 1453 | /* angles are specified in degrees * 100, thus the limit = 36000 */ | ||
| 1454 | if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000) | ||
| 1455 | ret = -ERANGE; | ||
| 1456 | } | ||
| 1457 | if (ret == 0) /* no errors so far */ | ||
| 1458 | { | ||
| 1459 | ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); | ||
| 1460 | if (ret >= 0) | ||
| 1461 | { | ||
| 1462 | pdev->pan_angle += new_pan; | ||
| 1463 | pdev->tilt_angle += new_tilt; | ||
| 1464 | } | ||
| 1465 | if (ret == -EPIPE) /* stall -> out of range */ | ||
| 1466 | ret = -ERANGE; | ||
| 1467 | } | ||
| 1468 | } | ||
| 1469 | else | ||
| 1470 | { | ||
| 1471 | ret = -ENXIO; | ||
| 1472 | } | ||
| 1473 | break; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | case VIDIOCPWCMPTGANGLE: | ||
| 1477 | { | ||
| 1478 | |||
| 1479 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
| 1480 | { | ||
| 1481 | struct pwc_mpt_angles *angles = arg; | ||
| 1482 | |||
| 1483 | angles->absolute = 1; | ||
| 1484 | angles->pan = pdev->pan_angle; | ||
| 1485 | angles->tilt = pdev->tilt_angle; | ||
| 1486 | } | ||
| 1487 | else | ||
| 1488 | { | ||
| 1489 | ret = -ENXIO; | ||
| 1490 | } | ||
| 1491 | break; | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | case VIDIOCPWCMPTSTATUS: | ||
| 1495 | { | ||
| 1496 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
| 1497 | { | ||
| 1498 | struct pwc_mpt_status *status = arg; | ||
| 1499 | ret = pwc_mpt_get_status(pdev, status); | ||
| 1500 | } | ||
| 1501 | else | ||
| 1502 | { | ||
| 1503 | ret = -ENXIO; | ||
| 1504 | } | ||
| 1505 | break; | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | case VIDIOCPWCGVIDCMD: | ||
| 1509 | { | ||
| 1510 | struct pwc_video_command *cmd = arg; | ||
| 1511 | |||
| 1512 | cmd->type = pdev->type; | ||
| 1513 | cmd->release = pdev->release; | ||
| 1514 | cmd->command_len = pdev->cmd_len; | ||
| 1515 | memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len); | ||
| 1516 | cmd->bandlength = pdev->vbandlength; | ||
| 1517 | cmd->frame_size = pdev->frame_size; | ||
| 1518 | break; | ||
| 1519 | } | ||
| 1520 | /* | ||
| 1521 | case VIDIOCPWCGVIDTABLE: | ||
| 1522 | { | ||
| 1523 | struct pwc_table_init_buffer *table = arg; | ||
| 1524 | table->len = pdev->cmd_len; | ||
| 1525 | memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size); | ||
| 1526 | break; | ||
| 1527 | } | ||
| 1528 | */ | ||
| 1529 | |||
| 1530 | default: | ||
| 1531 | ret = -ENOIOCTLCMD; | ||
| 1532 | break; | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | if (ret > 0) | ||
| 1536 | return 0; | ||
| 1537 | return ret; | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | |||
| 1541 | |||
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c deleted file mode 100644 index 90eb26042817..000000000000 --- a/drivers/usb/media/pwc/pwc-if.c +++ /dev/null | |||
| @@ -1,2205 +0,0 @@ | |||
| 1 | /* Linux driver for Philips webcam | ||
| 2 | USB and Video4Linux interface part. | ||
| 3 | (C) 1999-2004 Nemosoft Unv. | ||
| 4 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 5 | |||
| 6 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 7 | driver and thus may have bugs that are not present in the original version. | ||
| 8 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 9 | The decompression routines have been implemented by reverse-engineering the | ||
| 10 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 11 | |||
| 12 | This program is free software; you can redistribute it and/or modify | ||
| 13 | it under the terms of the GNU General Public License as published by | ||
| 14 | the Free Software Foundation; either version 2 of the License, or | ||
| 15 | (at your option) any later version. | ||
| 16 | |||
| 17 | This program is distributed in the hope that it will be useful, | ||
| 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | GNU General Public License for more details. | ||
| 21 | |||
| 22 | You should have received a copy of the GNU General Public License | ||
| 23 | along with this program; if not, write to the Free Software | ||
| 24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | |||
| 26 | */ | ||
| 27 | |||
| 28 | /* | ||
| 29 | This code forms the interface between the USB layers and the Philips | ||
| 30 | specific stuff. Some adanved stuff of the driver falls under an | ||
| 31 | NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and | ||
| 32 | is thus not distributed in source form. The binary pwcx.o module | ||
| 33 | contains the code that falls under the NDA. | ||
| 34 | |||
| 35 | In case you're wondering: 'pwc' stands for "Philips WebCam", but | ||
| 36 | I really didn't want to type 'philips_web_cam' every time (I'm lazy as | ||
| 37 | any Linux kernel hacker, but I don't like uncomprehensible abbreviations | ||
| 38 | without explanation). | ||
| 39 | |||
| 40 | Oh yes, convention: to disctinguish between all the various pointers to | ||
| 41 | device-structures, I use these names for the pointer variables: | ||
| 42 | udev: struct usb_device * | ||
| 43 | vdev: struct video_device * | ||
| 44 | pdev: struct pwc_devive * | ||
| 45 | */ | ||
| 46 | |||
| 47 | /* Contributors: | ||
| 48 | - Alvarado: adding whitebalance code | ||
| 49 | - Alistar Moire: QuickCam 3000 Pro device/product ID | ||
| 50 | - Tony Hoyle: Creative Labs Webcam 5 device/product ID | ||
| 51 | - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged | ||
| 52 | - Jk Fang: Sotec Afina Eye ID | ||
| 53 | - Xavier Roche: QuickCam Pro 4000 ID | ||
| 54 | - Jens Knudsen: QuickCam Zoom ID | ||
| 55 | - J. Debert: QuickCam for Notebooks ID | ||
| 56 | */ | ||
| 57 | |||
| 58 | #include <linux/errno.h> | ||
| 59 | #include <linux/init.h> | ||
| 60 | #include <linux/mm.h> | ||
| 61 | #include <linux/module.h> | ||
| 62 | #include <linux/poll.h> | ||
| 63 | #include <linux/slab.h> | ||
| 64 | #include <linux/vmalloc.h> | ||
| 65 | #include <asm/io.h> | ||
| 66 | |||
| 67 | #include "pwc.h" | ||
| 68 | #include "pwc-ioctl.h" | ||
| 69 | #include "pwc-kiara.h" | ||
| 70 | #include "pwc-timon.h" | ||
| 71 | #include "pwc-uncompress.h" | ||
| 72 | |||
| 73 | /* Function prototypes and driver templates */ | ||
| 74 | |||
| 75 | /* hotplug device table support */ | ||
| 76 | static struct usb_device_id pwc_device_table [] = { | ||
| 77 | { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ | ||
| 78 | { USB_DEVICE(0x0471, 0x0303) }, | ||
| 79 | { USB_DEVICE(0x0471, 0x0304) }, | ||
| 80 | { USB_DEVICE(0x0471, 0x0307) }, | ||
| 81 | { USB_DEVICE(0x0471, 0x0308) }, | ||
| 82 | { USB_DEVICE(0x0471, 0x030C) }, | ||
| 83 | { USB_DEVICE(0x0471, 0x0310) }, | ||
| 84 | { USB_DEVICE(0x0471, 0x0311) }, | ||
| 85 | { USB_DEVICE(0x0471, 0x0312) }, | ||
| 86 | { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ | ||
| 87 | { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ | ||
| 88 | { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ | ||
| 89 | { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ | ||
| 90 | { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ | ||
| 91 | { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ | ||
| 92 | { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ | ||
| 93 | { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ | ||
| 94 | { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ | ||
| 95 | { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ | ||
| 96 | { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ | ||
| 97 | { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ | ||
| 98 | { USB_DEVICE(0x055D, 0x9001) }, | ||
| 99 | { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ | ||
| 100 | { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ | ||
| 101 | { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ | ||
| 102 | { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ | ||
| 103 | { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ | ||
| 104 | { USB_DEVICE(0x0d81, 0x1900) }, | ||
| 105 | { } | ||
| 106 | }; | ||
| 107 | MODULE_DEVICE_TABLE(usb, pwc_device_table); | ||
| 108 | |||
| 109 | static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); | ||
| 110 | static void usb_pwc_disconnect(struct usb_interface *intf); | ||
| 111 | |||
| 112 | static struct usb_driver pwc_driver = { | ||
| 113 | .name = "Philips webcam", /* name */ | ||
| 114 | .id_table = pwc_device_table, | ||
| 115 | .probe = usb_pwc_probe, /* probe() */ | ||
| 116 | .disconnect = usb_pwc_disconnect, /* disconnect() */ | ||
| 117 | }; | ||
| 118 | |||
| 119 | #define MAX_DEV_HINTS 20 | ||
| 120 | #define MAX_ISOC_ERRORS 20 | ||
| 121 | |||
| 122 | static int default_size = PSZ_QCIF; | ||
| 123 | static int default_fps = 10; | ||
| 124 | static int default_fbufs = 3; /* Default number of frame buffers */ | ||
| 125 | static int default_mbufs = 2; /* Default number of mmap() buffers */ | ||
| 126 | int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; | ||
| 127 | static int power_save = 0; | ||
| 128 | static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ | ||
| 129 | static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ | ||
| 130 | static struct { | ||
| 131 | int type; | ||
| 132 | char serial_number[30]; | ||
| 133 | int device_node; | ||
| 134 | struct pwc_device *pdev; | ||
| 135 | } device_hint[MAX_DEV_HINTS]; | ||
| 136 | |||
| 137 | /***/ | ||
| 138 | |||
| 139 | static int pwc_video_open(struct inode *inode, struct file *file); | ||
| 140 | static int pwc_video_close(struct inode *inode, struct file *file); | ||
| 141 | static ssize_t pwc_video_read(struct file *file, char __user * buf, | ||
| 142 | size_t count, loff_t *ppos); | ||
| 143 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait); | ||
| 144 | static int pwc_video_ioctl(struct inode *inode, struct file *file, | ||
| 145 | unsigned int ioctlnr, unsigned long arg); | ||
| 146 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); | ||
| 147 | |||
| 148 | static struct file_operations pwc_fops = { | ||
| 149 | .owner = THIS_MODULE, | ||
| 150 | .open = pwc_video_open, | ||
| 151 | .release = pwc_video_close, | ||
| 152 | .read = pwc_video_read, | ||
| 153 | .poll = pwc_video_poll, | ||
| 154 | .mmap = pwc_video_mmap, | ||
| 155 | .ioctl = pwc_video_ioctl, | ||
| 156 | .compat_ioctl = v4l_compat_ioctl32, | ||
| 157 | .llseek = no_llseek, | ||
| 158 | }; | ||
| 159 | static struct video_device pwc_template = { | ||
| 160 | .owner = THIS_MODULE, | ||
| 161 | .name = "Philips Webcam", /* Filled in later */ | ||
| 162 | .type = VID_TYPE_CAPTURE, | ||
| 163 | .hardware = VID_HARDWARE_PWC, | ||
| 164 | .release = video_device_release, | ||
| 165 | .fops = &pwc_fops, | ||
| 166 | .minor = -1, | ||
| 167 | }; | ||
| 168 | |||
| 169 | /***************************************************************************/ | ||
| 170 | |||
| 171 | /* Okay, this is some magic that I worked out and the reasoning behind it... | ||
| 172 | |||
| 173 | The biggest problem with any USB device is of course: "what to do | ||
| 174 | when the user unplugs the device while it is in use by an application?" | ||
| 175 | We have several options: | ||
| 176 | 1) Curse them with the 7 plagues when they do (requires divine intervention) | ||
| 177 | 2) Tell them not to (won't work: they'll do it anyway) | ||
| 178 | 3) Oops the kernel (this will have a negative effect on a user's uptime) | ||
| 179 | 4) Do something sensible. | ||
| 180 | |||
| 181 | Of course, we go for option 4. | ||
| 182 | |||
| 183 | It happens that this device will be linked to two times, once from | ||
| 184 | usb_device and once from the video_device in their respective 'private' | ||
| 185 | pointers. This is done when the device is probed() and all initialization | ||
| 186 | succeeded. The pwc_device struct links back to both structures. | ||
| 187 | |||
| 188 | When a device is unplugged while in use it will be removed from the | ||
| 189 | list of known USB devices; I also de-register it as a V4L device, but | ||
| 190 | unfortunately I can't free the memory since the struct is still in use | ||
| 191 | by the file descriptor. This free-ing is then deferend until the first | ||
| 192 | opportunity. Crude, but it works. | ||
| 193 | |||
| 194 | A small 'advantage' is that if a user unplugs the cam and plugs it back | ||
| 195 | in, it should get assigned the same video device minor, but unfortunately | ||
| 196 | it's non-trivial to re-link the cam back to the video device... (that | ||
| 197 | would surely be magic! :)) | ||
| 198 | */ | ||
| 199 | |||
| 200 | /***************************************************************************/ | ||
| 201 | /* Private functions */ | ||
| 202 | |||
| 203 | /* Here we want the physical address of the memory. | ||
| 204 | * This is used when initializing the contents of the area. | ||
| 205 | */ | ||
| 206 | static inline unsigned long kvirt_to_pa(unsigned long adr) | ||
| 207 | { | ||
| 208 | unsigned long kva, ret; | ||
| 209 | |||
| 210 | kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); | ||
| 211 | kva |= adr & (PAGE_SIZE-1); /* restore the offset */ | ||
| 212 | ret = __pa(kva); | ||
| 213 | return ret; | ||
| 214 | } | ||
| 215 | |||
| 216 | static void * rvmalloc(unsigned long size) | ||
| 217 | { | ||
| 218 | void * mem; | ||
| 219 | unsigned long adr; | ||
| 220 | |||
| 221 | size=PAGE_ALIGN(size); | ||
| 222 | mem=vmalloc_32(size); | ||
| 223 | if (mem) | ||
| 224 | { | ||
| 225 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
| 226 | adr=(unsigned long) mem; | ||
| 227 | while (size > 0) | ||
| 228 | { | ||
| 229 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
| 230 | adr+=PAGE_SIZE; | ||
| 231 | size-=PAGE_SIZE; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | return mem; | ||
| 235 | } | ||
| 236 | |||
| 237 | static void rvfree(void * mem, unsigned long size) | ||
| 238 | { | ||
| 239 | unsigned long adr; | ||
| 240 | |||
| 241 | if (mem) | ||
| 242 | { | ||
| 243 | adr=(unsigned long) mem; | ||
| 244 | while ((long) size > 0) | ||
| 245 | { | ||
| 246 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
| 247 | adr+=PAGE_SIZE; | ||
| 248 | size-=PAGE_SIZE; | ||
| 249 | } | ||
| 250 | vfree(mem); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | |||
| 255 | |||
| 256 | |||
| 257 | static int pwc_allocate_buffers(struct pwc_device *pdev) | ||
| 258 | { | ||
| 259 | int i; | ||
| 260 | void *kbuf; | ||
| 261 | |||
| 262 | Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); | ||
| 263 | |||
| 264 | if (pdev == NULL) | ||
| 265 | return -ENXIO; | ||
| 266 | |||
| 267 | #ifdef PWC_MAGIC | ||
| 268 | if (pdev->magic != PWC_MAGIC) { | ||
| 269 | Err("allocate_buffers(): magic failed.\n"); | ||
| 270 | return -ENXIO; | ||
| 271 | } | ||
| 272 | #endif | ||
| 273 | /* Allocate Isochronous pipe buffers */ | ||
| 274 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
| 275 | if (pdev->sbuf[i].data == NULL) { | ||
| 276 | kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); | ||
| 277 | if (kbuf == NULL) { | ||
| 278 | Err("Failed to allocate iso buffer %d.\n", i); | ||
| 279 | return -ENOMEM; | ||
| 280 | } | ||
| 281 | Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf); | ||
| 282 | pdev->sbuf[i].data = kbuf; | ||
| 283 | memset(kbuf, 0, ISO_BUFFER_SIZE); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | /* Allocate frame buffer structure */ | ||
| 288 | if (pdev->fbuf == NULL) { | ||
| 289 | kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); | ||
| 290 | if (kbuf == NULL) { | ||
| 291 | Err("Failed to allocate frame buffer structure.\n"); | ||
| 292 | return -ENOMEM; | ||
| 293 | } | ||
| 294 | Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf); | ||
| 295 | pdev->fbuf = kbuf; | ||
| 296 | memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); | ||
| 297 | } | ||
| 298 | /* create frame buffers, and make circular ring */ | ||
| 299 | for (i = 0; i < default_fbufs; i++) { | ||
| 300 | if (pdev->fbuf[i].data == NULL) { | ||
| 301 | kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ | ||
| 302 | if (kbuf == NULL) { | ||
| 303 | Err("Failed to allocate frame buffer %d.\n", i); | ||
| 304 | return -ENOMEM; | ||
| 305 | } | ||
| 306 | Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf); | ||
| 307 | pdev->fbuf[i].data = kbuf; | ||
| 308 | memset(kbuf, 128, PWC_FRAME_SIZE); | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | /* Allocate decompressor table space */ | ||
| 313 | kbuf = NULL; | ||
| 314 | switch (pdev->type) | ||
| 315 | { | ||
| 316 | case 675: | ||
| 317 | case 680: | ||
| 318 | case 690: | ||
| 319 | case 720: | ||
| 320 | case 730: | ||
| 321 | case 740: | ||
| 322 | case 750: | ||
| 323 | #if 0 | ||
| 324 | Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private)); | ||
| 325 | kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */ | ||
| 326 | break; | ||
| 327 | case 645: | ||
| 328 | case 646: | ||
| 329 | /* TODO & FIXME */ | ||
| 330 | kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); | ||
| 331 | break; | ||
| 332 | #endif | ||
| 333 | ; | ||
| 334 | } | ||
| 335 | pdev->decompress_data = kbuf; | ||
| 336 | |||
| 337 | /* Allocate image buffer; double buffer for mmap() */ | ||
| 338 | kbuf = rvmalloc(default_mbufs * pdev->len_per_image); | ||
| 339 | if (kbuf == NULL) { | ||
| 340 | Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image); | ||
| 341 | return -ENOMEM; | ||
| 342 | } | ||
| 343 | Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf); | ||
| 344 | pdev->image_data = kbuf; | ||
| 345 | for (i = 0; i < default_mbufs; i++) | ||
| 346 | pdev->image_ptr[i] = kbuf + i * pdev->len_per_image; | ||
| 347 | for (; i < MAX_IMAGES; i++) | ||
| 348 | pdev->image_ptr[i] = NULL; | ||
| 349 | |||
| 350 | kbuf = NULL; | ||
| 351 | |||
| 352 | Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); | ||
| 353 | return 0; | ||
| 354 | } | ||
| 355 | |||
| 356 | static void pwc_free_buffers(struct pwc_device *pdev) | ||
| 357 | { | ||
| 358 | int i; | ||
| 359 | |||
| 360 | Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); | ||
| 361 | |||
| 362 | if (pdev == NULL) | ||
| 363 | return; | ||
| 364 | #ifdef PWC_MAGIC | ||
| 365 | if (pdev->magic != PWC_MAGIC) { | ||
| 366 | Err("free_buffers(): magic failed.\n"); | ||
| 367 | return; | ||
| 368 | } | ||
| 369 | #endif | ||
| 370 | |||
| 371 | /* Release Iso-pipe buffers */ | ||
| 372 | for (i = 0; i < MAX_ISO_BUFS; i++) | ||
| 373 | if (pdev->sbuf[i].data != NULL) { | ||
| 374 | Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); | ||
| 375 | kfree(pdev->sbuf[i].data); | ||
| 376 | pdev->sbuf[i].data = NULL; | ||
| 377 | } | ||
| 378 | |||
| 379 | /* The same for frame buffers */ | ||
| 380 | if (pdev->fbuf != NULL) { | ||
| 381 | for (i = 0; i < default_fbufs; i++) { | ||
| 382 | if (pdev->fbuf[i].data != NULL) { | ||
| 383 | Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); | ||
| 384 | vfree(pdev->fbuf[i].data); | ||
| 385 | pdev->fbuf[i].data = NULL; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | kfree(pdev->fbuf); | ||
| 389 | pdev->fbuf = NULL; | ||
| 390 | } | ||
| 391 | |||
| 392 | /* Intermediate decompression buffer & tables */ | ||
| 393 | if (pdev->decompress_data != NULL) { | ||
| 394 | Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data); | ||
| 395 | kfree(pdev->decompress_data); | ||
| 396 | pdev->decompress_data = NULL; | ||
| 397 | } | ||
| 398 | pdev->decompressor = NULL; | ||
| 399 | |||
| 400 | /* Release image buffers */ | ||
| 401 | if (pdev->image_data != NULL) { | ||
| 402 | Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data); | ||
| 403 | rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); | ||
| 404 | } | ||
| 405 | pdev->image_data = NULL; | ||
| 406 | |||
| 407 | Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); | ||
| 408 | } | ||
| 409 | |||
| 410 | /* The frame & image buffer mess. | ||
| 411 | |||
| 412 | Yes, this is a mess. Well, it used to be simple, but alas... In this | ||
| 413 | module, 3 buffers schemes are used to get the data from the USB bus to | ||
| 414 | the user program. The first scheme involves the ISO buffers (called thus | ||
| 415 | since they transport ISO data from the USB controller), and not really | ||
| 416 | interesting. Suffices to say the data from this buffer is quickly | ||
| 417 | gathered in an interrupt handler (pwc_isoc_handler) and placed into the | ||
| 418 | frame buffer. | ||
| 419 | |||
| 420 | The frame buffer is the second scheme, and is the central element here. | ||
| 421 | It collects the data from a single frame from the camera (hence, the | ||
| 422 | name). Frames are delimited by the USB camera with a short USB packet, | ||
| 423 | so that's easy to detect. The frame buffers form a list that is filled | ||
| 424 | by the camera+USB controller and drained by the user process through | ||
| 425 | either read() or mmap(). | ||
| 426 | |||
| 427 | The image buffer is the third scheme, in which frames are decompressed | ||
| 428 | and converted into planar format. For mmap() there is more than | ||
| 429 | one image buffer available. | ||
| 430 | |||
| 431 | The frame buffers provide the image buffering. In case the user process | ||
| 432 | is a bit slow, this introduces lag and some undesired side-effects. | ||
| 433 | The problem arises when the frame buffer is full. I used to drop the last | ||
| 434 | frame, which makes the data in the queue stale very quickly. But dropping | ||
| 435 | the frame at the head of the queue proved to be a litte bit more difficult. | ||
| 436 | I tried a circular linked scheme, but this introduced more problems than | ||
| 437 | it solved. | ||
| 438 | |||
| 439 | Because filling and draining are completely asynchronous processes, this | ||
| 440 | requires some fiddling with pointers and mutexes. | ||
| 441 | |||
| 442 | Eventually, I came up with a system with 2 lists: an 'empty' frame list | ||
| 443 | and a 'full' frame list: | ||
| 444 | * Initially, all frame buffers but one are on the 'empty' list; the one | ||
| 445 | remaining buffer is our initial fill frame. | ||
| 446 | * If a frame is needed for filling, we try to take it from the 'empty' | ||
| 447 | list, unless that list is empty, in which case we take the buffer at | ||
| 448 | the head of the 'full' list. | ||
| 449 | * When our fill buffer has been filled, it is appended to the 'full' | ||
| 450 | list. | ||
| 451 | * If a frame is needed by read() or mmap(), it is taken from the head of | ||
| 452 | the 'full' list, handled, and then appended to the 'empty' list. If no | ||
| 453 | buffer is present on the 'full' list, we wait. | ||
| 454 | The advantage is that the buffer that is currently being decompressed/ | ||
| 455 | converted, is on neither list, and thus not in our way (any other scheme | ||
| 456 | I tried had the problem of old data lingering in the queue). | ||
| 457 | |||
| 458 | Whatever strategy you choose, it always remains a tradeoff: with more | ||
| 459 | frame buffers the chances of a missed frame are reduced. On the other | ||
| 460 | hand, on slower machines it introduces lag because the queue will | ||
| 461 | always be full. | ||
| 462 | */ | ||
| 463 | |||
| 464 | /** | ||
| 465 | \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. | ||
| 466 | */ | ||
| 467 | static inline int pwc_next_fill_frame(struct pwc_device *pdev) | ||
| 468 | { | ||
| 469 | int ret; | ||
| 470 | unsigned long flags; | ||
| 471 | |||
| 472 | ret = 0; | ||
| 473 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
| 474 | if (pdev->fill_frame != NULL) { | ||
| 475 | /* append to 'full' list */ | ||
| 476 | if (pdev->full_frames == NULL) { | ||
| 477 | pdev->full_frames = pdev->fill_frame; | ||
| 478 | pdev->full_frames_tail = pdev->full_frames; | ||
| 479 | } | ||
| 480 | else { | ||
| 481 | pdev->full_frames_tail->next = pdev->fill_frame; | ||
| 482 | pdev->full_frames_tail = pdev->fill_frame; | ||
| 483 | } | ||
| 484 | } | ||
| 485 | if (pdev->empty_frames != NULL) { | ||
| 486 | /* We have empty frames available. That's easy */ | ||
| 487 | pdev->fill_frame = pdev->empty_frames; | ||
| 488 | pdev->empty_frames = pdev->empty_frames->next; | ||
| 489 | } | ||
| 490 | else { | ||
| 491 | /* Hmm. Take it from the full list */ | ||
| 492 | #if PWC_DEBUG | ||
| 493 | /* sanity check */ | ||
| 494 | if (pdev->full_frames == NULL) { | ||
| 495 | Err("Neither empty or full frames available!\n"); | ||
| 496 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
| 497 | return -EINVAL; | ||
| 498 | } | ||
| 499 | #endif | ||
| 500 | pdev->fill_frame = pdev->full_frames; | ||
| 501 | pdev->full_frames = pdev->full_frames->next; | ||
| 502 | ret = 1; | ||
| 503 | } | ||
| 504 | pdev->fill_frame->next = NULL; | ||
| 505 | #if PWC_DEBUG | ||
| 506 | Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence); | ||
| 507 | pdev->fill_frame->sequence = pdev->sequence++; | ||
| 508 | #endif | ||
| 509 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
| 510 | return ret; | ||
| 511 | } | ||
| 512 | |||
| 513 | |||
| 514 | /** | ||
| 515 | \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. | ||
| 516 | |||
| 517 | If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. | ||
| 518 | */ | ||
| 519 | static void pwc_reset_buffers(struct pwc_device *pdev) | ||
| 520 | { | ||
| 521 | int i; | ||
| 522 | unsigned long flags; | ||
| 523 | |||
| 524 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
| 525 | pdev->full_frames = NULL; | ||
| 526 | pdev->full_frames_tail = NULL; | ||
| 527 | for (i = 0; i < default_fbufs; i++) { | ||
| 528 | pdev->fbuf[i].filled = 0; | ||
| 529 | if (i > 0) | ||
| 530 | pdev->fbuf[i].next = &pdev->fbuf[i - 1]; | ||
| 531 | else | ||
| 532 | pdev->fbuf->next = NULL; | ||
| 533 | } | ||
| 534 | pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; | ||
| 535 | pdev->empty_frames_tail = pdev->fbuf; | ||
| 536 | pdev->read_frame = NULL; | ||
| 537 | pdev->fill_frame = pdev->empty_frames; | ||
| 538 | pdev->empty_frames = pdev->empty_frames->next; | ||
| 539 | |||
| 540 | pdev->image_read_pos = 0; | ||
| 541 | pdev->fill_image = 0; | ||
| 542 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
| 543 | } | ||
| 544 | |||
| 545 | |||
| 546 | /** | ||
| 547 | \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. | ||
| 548 | */ | ||
| 549 | static int pwc_handle_frame(struct pwc_device *pdev) | ||
| 550 | { | ||
| 551 | int ret = 0; | ||
| 552 | unsigned long flags; | ||
| 553 | |||
| 554 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
| 555 | /* First grab our read_frame; this is removed from all lists, so | ||
| 556 | we can release the lock after this without problems */ | ||
| 557 | if (pdev->read_frame != NULL) { | ||
| 558 | /* This can't theoretically happen */ | ||
| 559 | Err("Huh? Read frame still in use?\n"); | ||
| 560 | } | ||
| 561 | else { | ||
| 562 | if (pdev->full_frames == NULL) { | ||
| 563 | Err("Woops. No frames ready.\n"); | ||
| 564 | } | ||
| 565 | else { | ||
| 566 | pdev->read_frame = pdev->full_frames; | ||
| 567 | pdev->full_frames = pdev->full_frames->next; | ||
| 568 | pdev->read_frame->next = NULL; | ||
| 569 | } | ||
| 570 | |||
| 571 | if (pdev->read_frame != NULL) { | ||
| 572 | #if PWC_DEBUG | ||
| 573 | Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence); | ||
| 574 | #endif | ||
| 575 | /* Decompression is a lenghty process, so it's outside of the lock. | ||
| 576 | This gives the isoc_handler the opportunity to fill more frames | ||
| 577 | in the mean time. | ||
| 578 | */ | ||
| 579 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
| 580 | ret = pwc_decompress(pdev); | ||
| 581 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
| 582 | |||
| 583 | /* We're done with read_buffer, tack it to the end of the empty buffer list */ | ||
| 584 | if (pdev->empty_frames == NULL) { | ||
| 585 | pdev->empty_frames = pdev->read_frame; | ||
| 586 | pdev->empty_frames_tail = pdev->empty_frames; | ||
| 587 | } | ||
| 588 | else { | ||
| 589 | pdev->empty_frames_tail->next = pdev->read_frame; | ||
| 590 | pdev->empty_frames_tail = pdev->read_frame; | ||
| 591 | } | ||
| 592 | pdev->read_frame = NULL; | ||
| 593 | } | ||
| 594 | } | ||
| 595 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
| 596 | return ret; | ||
| 597 | } | ||
| 598 | |||
| 599 | /** | ||
| 600 | \brief Advance pointers of image buffer (after each user request) | ||
| 601 | */ | ||
| 602 | static inline void pwc_next_image(struct pwc_device *pdev) | ||
| 603 | { | ||
| 604 | pdev->image_used[pdev->fill_image] = 0; | ||
| 605 | pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; | ||
| 606 | } | ||
| 607 | |||
| 608 | |||
| 609 | /* This gets called for the Isochronous pipe (video). This is done in | ||
| 610 | * interrupt time, so it has to be fast, not crash, and not stall. Neat. | ||
| 611 | */ | ||
| 612 | static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) | ||
| 613 | { | ||
| 614 | struct pwc_device *pdev; | ||
| 615 | int i, fst, flen; | ||
| 616 | int awake; | ||
| 617 | struct pwc_frame_buf *fbuf; | ||
| 618 | unsigned char *fillptr = NULL, *iso_buf = NULL; | ||
| 619 | |||
| 620 | awake = 0; | ||
| 621 | pdev = (struct pwc_device *)urb->context; | ||
| 622 | if (pdev == NULL) { | ||
| 623 | Err("isoc_handler() called with NULL device?!\n"); | ||
| 624 | return; | ||
| 625 | } | ||
| 626 | #ifdef PWC_MAGIC | ||
| 627 | if (pdev->magic != PWC_MAGIC) { | ||
| 628 | Err("isoc_handler() called with bad magic!\n"); | ||
| 629 | return; | ||
| 630 | } | ||
| 631 | #endif | ||
| 632 | if (urb->status == -ENOENT || urb->status == -ECONNRESET) { | ||
| 633 | Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); | ||
| 634 | return; | ||
| 635 | } | ||
| 636 | if (urb->status != -EINPROGRESS && urb->status != 0) { | ||
| 637 | const char *errmsg; | ||
| 638 | |||
| 639 | errmsg = "Unknown"; | ||
| 640 | switch(urb->status) { | ||
| 641 | case -ENOSR: errmsg = "Buffer error (overrun)"; break; | ||
| 642 | case -EPIPE: errmsg = "Stalled (device not responding)"; break; | ||
| 643 | case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; | ||
| 644 | case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; | ||
| 645 | case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; | ||
| 646 | case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; | ||
| 647 | } | ||
| 648 | Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); | ||
| 649 | /* Give up after a number of contiguous errors on the USB bus. | ||
| 650 | Appearantly something is wrong so we simulate an unplug event. | ||
| 651 | */ | ||
| 652 | if (++pdev->visoc_errors > MAX_ISOC_ERRORS) | ||
| 653 | { | ||
| 654 | Info("Too many ISOC errors, bailing out.\n"); | ||
| 655 | pdev->error_status = EIO; | ||
| 656 | awake = 1; | ||
| 657 | wake_up_interruptible(&pdev->frameq); | ||
| 658 | } | ||
| 659 | goto handler_end; // ugly, but practical | ||
| 660 | } | ||
| 661 | |||
| 662 | fbuf = pdev->fill_frame; | ||
| 663 | if (fbuf == NULL) { | ||
| 664 | Err("pwc_isoc_handler without valid fill frame.\n"); | ||
| 665 | awake = 1; | ||
| 666 | goto handler_end; | ||
| 667 | } | ||
| 668 | else { | ||
| 669 | fillptr = fbuf->data + fbuf->filled; | ||
| 670 | } | ||
| 671 | |||
| 672 | /* Reset ISOC error counter. We did get here, after all. */ | ||
| 673 | pdev->visoc_errors = 0; | ||
| 674 | |||
| 675 | /* vsync: 0 = don't copy data | ||
| 676 | 1 = sync-hunt | ||
| 677 | 2 = synched | ||
| 678 | */ | ||
| 679 | /* Compact data */ | ||
| 680 | for (i = 0; i < urb->number_of_packets; i++) { | ||
| 681 | fst = urb->iso_frame_desc[i].status; | ||
| 682 | flen = urb->iso_frame_desc[i].actual_length; | ||
| 683 | iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
| 684 | if (fst == 0) { | ||
| 685 | if (flen > 0) { /* if valid data... */ | ||
| 686 | if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ | ||
| 687 | pdev->vsync = 2; | ||
| 688 | |||
| 689 | /* ...copy data to frame buffer, if possible */ | ||
| 690 | if (flen + fbuf->filled > pdev->frame_total_size) { | ||
| 691 | Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); | ||
| 692 | pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ | ||
| 693 | pdev->vframes_error++; | ||
| 694 | } | ||
| 695 | else { | ||
| 696 | memmove(fillptr, iso_buf, flen); | ||
| 697 | fillptr += flen; | ||
| 698 | } | ||
| 699 | } | ||
| 700 | fbuf->filled += flen; | ||
| 701 | } /* ..flen > 0 */ | ||
| 702 | |||
| 703 | if (flen < pdev->vlast_packet_size) { | ||
| 704 | /* Shorter packet... We probably have the end of an image-frame; | ||
| 705 | wake up read() process and let select()/poll() do something. | ||
| 706 | Decompression is done in user time over there. | ||
| 707 | */ | ||
| 708 | if (pdev->vsync == 2) { | ||
| 709 | /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus | ||
| 710 | frames on the USB wire after an exposure change. This conditition is | ||
| 711 | however detected in the cam and a bit is set in the header. | ||
| 712 | */ | ||
| 713 | if (pdev->type == 730) { | ||
| 714 | unsigned char *ptr = (unsigned char *)fbuf->data; | ||
| 715 | |||
| 716 | if (ptr[1] == 1 && ptr[0] & 0x10) { | ||
| 717 | #if PWC_DEBUG | ||
| 718 | Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); | ||
| 719 | #endif | ||
| 720 | pdev->drop_frames += 2; | ||
| 721 | pdev->vframes_error++; | ||
| 722 | } | ||
| 723 | if ((ptr[0] ^ pdev->vmirror) & 0x01) { | ||
| 724 | if (ptr[0] & 0x01) | ||
| 725 | Info("Snapshot button pressed.\n"); | ||
| 726 | else | ||
| 727 | Info("Snapshot button released.\n"); | ||
| 728 | } | ||
| 729 | if ((ptr[0] ^ pdev->vmirror) & 0x02) { | ||
| 730 | if (ptr[0] & 0x02) | ||
| 731 | Info("Image is mirrored.\n"); | ||
| 732 | else | ||
| 733 | Info("Image is normal.\n"); | ||
| 734 | } | ||
| 735 | pdev->vmirror = ptr[0] & 0x03; | ||
| 736 | /* Sometimes the trailer of the 730 is still sent as a 4 byte packet | ||
| 737 | after a short frame; this condition is filtered out specifically. A 4 byte | ||
| 738 | frame doesn't make sense anyway. | ||
| 739 | So we get either this sequence: | ||
| 740 | drop_bit set -> 4 byte frame -> short frame -> good frame | ||
| 741 | Or this one: | ||
| 742 | drop_bit set -> short frame -> good frame | ||
| 743 | So we drop either 3 or 2 frames in all! | ||
| 744 | */ | ||
| 745 | if (fbuf->filled == 4) | ||
| 746 | pdev->drop_frames++; | ||
| 747 | } | ||
| 748 | |||
| 749 | /* In case we were instructed to drop the frame, do so silently. | ||
| 750 | The buffer pointers are not updated either (but the counters are reset below). | ||
| 751 | */ | ||
| 752 | if (pdev->drop_frames > 0) | ||
| 753 | pdev->drop_frames--; | ||
| 754 | else { | ||
| 755 | /* Check for underflow first */ | ||
| 756 | if (fbuf->filled < pdev->frame_total_size) { | ||
| 757 | Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); | ||
| 758 | pdev->vframes_error++; | ||
| 759 | } | ||
| 760 | else { | ||
| 761 | /* Send only once per EOF */ | ||
| 762 | awake = 1; /* delay wake_ups */ | ||
| 763 | |||
| 764 | /* Find our next frame to fill. This will always succeed, since we | ||
| 765 | * nick a frame from either empty or full list, but if we had to | ||
| 766 | * take it from the full list, it means a frame got dropped. | ||
| 767 | */ | ||
| 768 | if (pwc_next_fill_frame(pdev)) { | ||
| 769 | pdev->vframes_dumped++; | ||
| 770 | if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) { | ||
| 771 | if (pdev->vframes_dumped < 20) | ||
| 772 | Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count); | ||
| 773 | if (pdev->vframes_dumped == 20) | ||
| 774 | Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count); | ||
| 775 | } | ||
| 776 | } | ||
| 777 | fbuf = pdev->fill_frame; | ||
| 778 | } | ||
| 779 | } /* !drop_frames */ | ||
| 780 | pdev->vframe_count++; | ||
| 781 | } | ||
| 782 | fbuf->filled = 0; | ||
| 783 | fillptr = fbuf->data; | ||
| 784 | pdev->vsync = 1; | ||
| 785 | } /* .. flen < last_packet_size */ | ||
| 786 | pdev->vlast_packet_size = flen; | ||
| 787 | } /* ..status == 0 */ | ||
| 788 | #if PWC_DEBUG | ||
| 789 | /* This is normally not interesting to the user, unless you are really debugging something */ | ||
| 790 | else { | ||
| 791 | static int iso_error = 0; | ||
| 792 | iso_error++; | ||
| 793 | if (iso_error < 20) | ||
| 794 | Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); | ||
| 795 | } | ||
| 796 | #endif | ||
| 797 | } | ||
| 798 | |||
| 799 | handler_end: | ||
| 800 | if (awake) | ||
| 801 | wake_up_interruptible(&pdev->frameq); | ||
| 802 | |||
| 803 | urb->dev = pdev->udev; | ||
| 804 | i = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 805 | if (i != 0) | ||
| 806 | Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); | ||
| 807 | } | ||
| 808 | |||
| 809 | |||
| 810 | static int pwc_isoc_init(struct pwc_device *pdev) | ||
| 811 | { | ||
| 812 | struct usb_device *udev; | ||
| 813 | struct urb *urb; | ||
| 814 | int i, j, ret; | ||
| 815 | |||
| 816 | struct usb_interface *intf; | ||
| 817 | struct usb_host_interface *idesc = NULL; | ||
| 818 | |||
| 819 | if (pdev == NULL) | ||
| 820 | return -EFAULT; | ||
| 821 | if (pdev->iso_init) | ||
| 822 | return 0; | ||
| 823 | pdev->vsync = 0; | ||
| 824 | udev = pdev->udev; | ||
| 825 | |||
| 826 | /* Get the current alternate interface, adjust packet size */ | ||
| 827 | if (!udev->actconfig) | ||
| 828 | return -EFAULT; | ||
| 829 | |||
| 830 | intf = usb_ifnum_to_if(udev, 0); | ||
| 831 | if (intf) | ||
| 832 | idesc = usb_altnum_to_altsetting(intf, pdev->valternate); | ||
| 833 | |||
| 834 | if (!idesc) | ||
| 835 | return -EFAULT; | ||
| 836 | |||
| 837 | /* Search video endpoint */ | ||
| 838 | pdev->vmax_packet_size = -1; | ||
| 839 | for (i = 0; i < idesc->desc.bNumEndpoints; i++) | ||
| 840 | if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { | ||
| 841 | pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize); | ||
| 842 | break; | ||
| 843 | } | ||
| 844 | |||
| 845 | if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { | ||
| 846 | Err("Failed to find packet size for video endpoint in current alternate setting.\n"); | ||
| 847 | return -ENFILE; /* Odd error, that should be noticeable */ | ||
| 848 | } | ||
| 849 | |||
| 850 | /* Set alternate interface */ | ||
| 851 | ret = 0; | ||
| 852 | Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); | ||
| 853 | ret = usb_set_interface(pdev->udev, 0, pdev->valternate); | ||
| 854 | if (ret < 0) | ||
| 855 | return ret; | ||
| 856 | |||
| 857 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
| 858 | urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); | ||
| 859 | if (urb == NULL) { | ||
| 860 | Err("Failed to allocate urb %d\n", i); | ||
| 861 | ret = -ENOMEM; | ||
| 862 | break; | ||
| 863 | } | ||
| 864 | pdev->sbuf[i].urb = urb; | ||
| 865 | Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); | ||
| 866 | } | ||
| 867 | if (ret) { | ||
| 868 | /* De-allocate in reverse order */ | ||
| 869 | while (i >= 0) { | ||
| 870 | if (pdev->sbuf[i].urb != NULL) | ||
| 871 | usb_free_urb(pdev->sbuf[i].urb); | ||
| 872 | pdev->sbuf[i].urb = NULL; | ||
| 873 | i--; | ||
| 874 | } | ||
| 875 | return ret; | ||
| 876 | } | ||
| 877 | |||
| 878 | /* init URB structure */ | ||
| 879 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
| 880 | urb = pdev->sbuf[i].urb; | ||
| 881 | |||
| 882 | urb->interval = 1; // devik | ||
| 883 | urb->dev = udev; | ||
| 884 | urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); | ||
| 885 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 886 | urb->transfer_buffer = pdev->sbuf[i].data; | ||
| 887 | urb->transfer_buffer_length = ISO_BUFFER_SIZE; | ||
| 888 | urb->complete = pwc_isoc_handler; | ||
| 889 | urb->context = pdev; | ||
| 890 | urb->start_frame = 0; | ||
| 891 | urb->number_of_packets = ISO_FRAMES_PER_DESC; | ||
| 892 | for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { | ||
| 893 | urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; | ||
| 894 | urb->iso_frame_desc[j].length = pdev->vmax_packet_size; | ||
| 895 | } | ||
| 896 | } | ||
| 897 | |||
| 898 | /* link */ | ||
| 899 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
| 900 | ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); | ||
| 901 | if (ret) | ||
| 902 | Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); | ||
| 903 | else | ||
| 904 | Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); | ||
| 905 | } | ||
| 906 | |||
| 907 | /* All is done... */ | ||
| 908 | pdev->iso_init = 1; | ||
| 909 | Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); | ||
| 910 | return 0; | ||
| 911 | } | ||
| 912 | |||
| 913 | static void pwc_isoc_cleanup(struct pwc_device *pdev) | ||
| 914 | { | ||
| 915 | int i; | ||
| 916 | |||
| 917 | Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); | ||
| 918 | if (pdev == NULL) | ||
| 919 | return; | ||
| 920 | |||
| 921 | /* Unlinking ISOC buffers one by one */ | ||
| 922 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
| 923 | struct urb *urb; | ||
| 924 | |||
| 925 | urb = pdev->sbuf[i].urb; | ||
| 926 | if (urb != 0) { | ||
| 927 | if (pdev->iso_init) { | ||
| 928 | Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); | ||
| 929 | usb_kill_urb(urb); | ||
| 930 | } | ||
| 931 | Trace(TRACE_MEMORY, "Freeing URB\n"); | ||
| 932 | usb_free_urb(urb); | ||
| 933 | pdev->sbuf[i].urb = NULL; | ||
| 934 | } | ||
| 935 | } | ||
| 936 | |||
| 937 | /* Stop camera, but only if we are sure the camera is still there (unplug | ||
| 938 | is signalled by EPIPE) | ||
| 939 | */ | ||
| 940 | if (pdev->error_status && pdev->error_status != EPIPE) { | ||
| 941 | Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); | ||
| 942 | usb_set_interface(pdev->udev, 0, 0); | ||
| 943 | } | ||
| 944 | |||
| 945 | pdev->iso_init = 0; | ||
| 946 | Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); | ||
| 947 | } | ||
| 948 | |||
| 949 | int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) | ||
| 950 | { | ||
| 951 | int ret, start; | ||
| 952 | |||
| 953 | /* Stop isoc stuff */ | ||
| 954 | pwc_isoc_cleanup(pdev); | ||
| 955 | /* Reset parameters */ | ||
| 956 | pwc_reset_buffers(pdev); | ||
| 957 | /* Try to set video mode... */ | ||
| 958 | start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); | ||
| 959 | if (ret) { | ||
| 960 | Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); | ||
| 961 | /* That failed... restore old mode (we know that worked) */ | ||
| 962 | start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
| 963 | if (start) { | ||
| 964 | Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); | ||
| 965 | } | ||
| 966 | } | ||
| 967 | if (start == 0) | ||
| 968 | { | ||
| 969 | if (pwc_isoc_init(pdev) < 0) | ||
| 970 | { | ||
| 971 | Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n"); | ||
| 972 | ret = -EAGAIN; /* let's try again, who knows if it works a second time */ | ||
| 973 | } | ||
| 974 | } | ||
| 975 | pdev->drop_frames++; /* try to avoid garbage during switch */ | ||
| 976 | return ret; /* Return original error code */ | ||
| 977 | } | ||
| 978 | |||
| 979 | |||
| 980 | /***************************************************************************/ | ||
| 981 | /* Video4Linux functions */ | ||
| 982 | |||
| 983 | static int pwc_video_open(struct inode *inode, struct file *file) | ||
| 984 | { | ||
| 985 | int i; | ||
| 986 | struct video_device *vdev = video_devdata(file); | ||
| 987 | struct pwc_device *pdev; | ||
| 988 | |||
| 989 | Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); | ||
| 990 | |||
| 991 | pdev = (struct pwc_device *)vdev->priv; | ||
| 992 | if (pdev == NULL) | ||
| 993 | BUG(); | ||
| 994 | if (pdev->vopen) | ||
| 995 | return -EBUSY; | ||
| 996 | |||
| 997 | down(&pdev->modlock); | ||
| 998 | if (!pdev->usb_init) { | ||
| 999 | Trace(TRACE_OPEN, "Doing first time initialization.\n"); | ||
| 1000 | pdev->usb_init = 1; | ||
| 1001 | |||
| 1002 | if (pwc_trace & TRACE_OPEN) | ||
| 1003 | { | ||
| 1004 | /* Query sensor type */ | ||
| 1005 | const char *sensor_type = NULL; | ||
| 1006 | int ret; | ||
| 1007 | |||
| 1008 | ret = pwc_get_cmos_sensor(pdev, &i); | ||
| 1009 | if (ret >= 0) | ||
| 1010 | { | ||
| 1011 | switch(i) { | ||
| 1012 | case 0x00: sensor_type = "Hyundai CMOS sensor"; break; | ||
| 1013 | case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; | ||
| 1014 | case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; | ||
| 1015 | case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; | ||
| 1016 | case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; | ||
| 1017 | case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; | ||
| 1018 | case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; | ||
| 1019 | case 0x40: sensor_type = "UPA 1021 sensor"; break; | ||
| 1020 | case 0x100: sensor_type = "VGA sensor"; break; | ||
| 1021 | case 0x101: sensor_type = "PAL MR sensor"; break; | ||
| 1022 | default: sensor_type = "unknown type of sensor"; break; | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | if (sensor_type != NULL) | ||
| 1026 | Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); | ||
| 1027 | } | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | /* Turn on camera */ | ||
| 1031 | if (power_save) { | ||
| 1032 | i = pwc_camera_power(pdev, 1); | ||
| 1033 | if (i < 0) | ||
| 1034 | Info("Failed to restore power to the camera! (%d)\n", i); | ||
| 1035 | } | ||
| 1036 | /* Set LED on/off time */ | ||
| 1037 | if (pwc_set_leds(pdev, led_on, led_off) < 0) | ||
| 1038 | Info("Failed to set LED on/off time.\n"); | ||
| 1039 | |||
| 1040 | pwc_construct(pdev); /* set min/max sizes correct */ | ||
| 1041 | |||
| 1042 | /* So far, so good. Allocate memory. */ | ||
| 1043 | i = pwc_allocate_buffers(pdev); | ||
| 1044 | if (i < 0) { | ||
| 1045 | Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n"); | ||
| 1046 | up(&pdev->modlock); | ||
| 1047 | return i; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | /* Reset buffers & parameters */ | ||
| 1051 | pwc_reset_buffers(pdev); | ||
| 1052 | for (i = 0; i < default_mbufs; i++) | ||
| 1053 | pdev->image_used[i] = 0; | ||
| 1054 | pdev->vframe_count = 0; | ||
| 1055 | pdev->vframes_dumped = 0; | ||
| 1056 | pdev->vframes_error = 0; | ||
| 1057 | pdev->visoc_errors = 0; | ||
| 1058 | pdev->error_status = 0; | ||
| 1059 | #if PWC_DEBUG | ||
| 1060 | pdev->sequence = 0; | ||
| 1061 | #endif | ||
| 1062 | pwc_construct(pdev); /* set min/max sizes correct */ | ||
| 1063 | |||
| 1064 | /* Set some defaults */ | ||
| 1065 | pdev->vsnapshot = 0; | ||
| 1066 | |||
| 1067 | /* Start iso pipe for video; first try the last used video size | ||
| 1068 | (or the default one); if that fails try QCIF/10 or QSIF/10; | ||
| 1069 | it that fails too, give up. | ||
| 1070 | */ | ||
| 1071 | i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); | ||
| 1072 | if (i) { | ||
| 1073 | Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); | ||
| 1074 | if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750) | ||
| 1075 | i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0); | ||
| 1076 | else | ||
| 1077 | i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0); | ||
| 1078 | } | ||
| 1079 | if (i) { | ||
| 1080 | Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); | ||
| 1081 | up(&pdev->modlock); | ||
| 1082 | return i; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | i = pwc_isoc_init(pdev); | ||
| 1086 | if (i) { | ||
| 1087 | Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); | ||
| 1088 | up(&pdev->modlock); | ||
| 1089 | return i; | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | pdev->vopen++; | ||
| 1093 | file->private_data = vdev; | ||
| 1094 | up(&pdev->modlock); | ||
| 1095 | Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); | ||
| 1096 | return 0; | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | /* Note that all cleanup is done in the reverse order as in _open */ | ||
| 1100 | static int pwc_video_close(struct inode *inode, struct file *file) | ||
| 1101 | { | ||
| 1102 | struct video_device *vdev = file->private_data; | ||
| 1103 | struct pwc_device *pdev; | ||
| 1104 | int i; | ||
| 1105 | |||
| 1106 | Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); | ||
| 1107 | |||
| 1108 | pdev = (struct pwc_device *)vdev->priv; | ||
| 1109 | if (pdev->vopen == 0) | ||
| 1110 | Info("video_close() called on closed device?\n"); | ||
| 1111 | |||
| 1112 | /* Dump statistics, but only if a reasonable amount of frames were | ||
| 1113 | processed (to prevent endless log-entries in case of snap-shot | ||
| 1114 | programs) | ||
| 1115 | */ | ||
| 1116 | if (pdev->vframe_count > 20) | ||
| 1117 | Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); | ||
| 1118 | |||
| 1119 | switch (pdev->type) | ||
| 1120 | { | ||
| 1121 | case 675: | ||
| 1122 | case 680: | ||
| 1123 | case 690: | ||
| 1124 | case 720: | ||
| 1125 | case 730: | ||
| 1126 | case 740: | ||
| 1127 | case 750: | ||
| 1128 | /* pwc_dec23_exit(); *//* Timon & Kiara */ | ||
| 1129 | break; | ||
| 1130 | case 645: | ||
| 1131 | case 646: | ||
| 1132 | /* pwc_dec1_exit(); */ | ||
| 1133 | break; | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | pwc_isoc_cleanup(pdev); | ||
| 1137 | pwc_free_buffers(pdev); | ||
| 1138 | |||
| 1139 | /* Turn off LEDS and power down camera, but only when not unplugged */ | ||
| 1140 | if (pdev->error_status != EPIPE) { | ||
| 1141 | /* Turn LEDs off */ | ||
| 1142 | if (pwc_set_leds(pdev, 0, 0) < 0) | ||
| 1143 | Info("Failed to set LED on/off time.\n"); | ||
| 1144 | if (power_save) { | ||
| 1145 | i = pwc_camera_power(pdev, 0); | ||
| 1146 | if (i < 0) | ||
| 1147 | Err("Failed to power down camera (%d)\n", i); | ||
| 1148 | } | ||
| 1149 | } | ||
| 1150 | pdev->vopen = 0; | ||
| 1151 | Trace(TRACE_OPEN, "<< video_close()\n"); | ||
| 1152 | return 0; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | /* | ||
| 1156 | * FIXME: what about two parallel reads ???? | ||
| 1157 | * ANSWER: Not supported. You can't open the device more than once, | ||
| 1158 | despite what the V4L1 interface says. First, I don't see | ||
| 1159 | the need, second there's no mechanism of alerting the | ||
| 1160 | 2nd/3rd/... process of events like changing image size. | ||
| 1161 | And I don't see the point of blocking that for the | ||
| 1162 | 2nd/3rd/... process. | ||
| 1163 | In multi-threaded environments reading parallel from any | ||
| 1164 | device is tricky anyhow. | ||
| 1165 | */ | ||
| 1166 | |||
| 1167 | static ssize_t pwc_video_read(struct file *file, char __user * buf, | ||
| 1168 | size_t count, loff_t *ppos) | ||
| 1169 | { | ||
| 1170 | struct video_device *vdev = file->private_data; | ||
| 1171 | struct pwc_device *pdev; | ||
| 1172 | int noblock = file->f_flags & O_NONBLOCK; | ||
| 1173 | DECLARE_WAITQUEUE(wait, current); | ||
| 1174 | int bytes_to_read; | ||
| 1175 | |||
| 1176 | Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count); | ||
| 1177 | if (vdev == NULL) | ||
| 1178 | return -EFAULT; | ||
| 1179 | pdev = vdev->priv; | ||
| 1180 | if (pdev == NULL) | ||
| 1181 | return -EFAULT; | ||
| 1182 | if (pdev->error_status) | ||
| 1183 | return -pdev->error_status; /* Something happened, report what. */ | ||
| 1184 | |||
| 1185 | /* In case we're doing partial reads, we don't have to wait for a frame */ | ||
| 1186 | if (pdev->image_read_pos == 0) { | ||
| 1187 | /* Do wait queueing according to the (doc)book */ | ||
| 1188 | add_wait_queue(&pdev->frameq, &wait); | ||
| 1189 | while (pdev->full_frames == NULL) { | ||
| 1190 | /* Check for unplugged/etc. here */ | ||
| 1191 | if (pdev->error_status) { | ||
| 1192 | remove_wait_queue(&pdev->frameq, &wait); | ||
| 1193 | set_current_state(TASK_RUNNING); | ||
| 1194 | return -pdev->error_status ; | ||
| 1195 | } | ||
| 1196 | if (noblock) { | ||
| 1197 | remove_wait_queue(&pdev->frameq, &wait); | ||
| 1198 | set_current_state(TASK_RUNNING); | ||
| 1199 | return -EWOULDBLOCK; | ||
| 1200 | } | ||
| 1201 | if (signal_pending(current)) { | ||
| 1202 | remove_wait_queue(&pdev->frameq, &wait); | ||
| 1203 | set_current_state(TASK_RUNNING); | ||
| 1204 | return -ERESTARTSYS; | ||
| 1205 | } | ||
| 1206 | schedule(); | ||
| 1207 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 1208 | } | ||
| 1209 | remove_wait_queue(&pdev->frameq, &wait); | ||
| 1210 | set_current_state(TASK_RUNNING); | ||
| 1211 | |||
| 1212 | /* Decompress and release frame */ | ||
| 1213 | if (pwc_handle_frame(pdev)) | ||
| 1214 | return -EFAULT; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | Trace(TRACE_READ, "Copying data to user space.\n"); | ||
| 1218 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
| 1219 | bytes_to_read = pdev->frame_size; | ||
| 1220 | else | ||
| 1221 | bytes_to_read = pdev->view.size; | ||
| 1222 | |||
| 1223 | /* copy bytes to user space; we allow for partial reads */ | ||
| 1224 | if (count + pdev->image_read_pos > bytes_to_read) | ||
| 1225 | count = bytes_to_read - pdev->image_read_pos; | ||
| 1226 | if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count)) | ||
| 1227 | return -EFAULT; | ||
| 1228 | pdev->image_read_pos += count; | ||
| 1229 | if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ | ||
| 1230 | pdev->image_read_pos = 0; | ||
| 1231 | pwc_next_image(pdev); | ||
| 1232 | } | ||
| 1233 | return count; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait) | ||
| 1237 | { | ||
| 1238 | struct video_device *vdev = file->private_data; | ||
| 1239 | struct pwc_device *pdev; | ||
| 1240 | |||
| 1241 | if (vdev == NULL) | ||
| 1242 | return -EFAULT; | ||
| 1243 | pdev = vdev->priv; | ||
| 1244 | if (pdev == NULL) | ||
| 1245 | return -EFAULT; | ||
| 1246 | |||
| 1247 | poll_wait(file, &pdev->frameq, wait); | ||
| 1248 | if (pdev->error_status) | ||
| 1249 | return POLLERR; | ||
| 1250 | if (pdev->full_frames != NULL) /* we have frames waiting */ | ||
| 1251 | return (POLLIN | POLLRDNORM); | ||
| 1252 | |||
| 1253 | return 0; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | static int pwc_video_do_ioctl(struct inode *inode, struct file *file, | ||
| 1257 | unsigned int cmd, void *arg) | ||
| 1258 | { | ||
| 1259 | struct video_device *vdev = file->private_data; | ||
| 1260 | struct pwc_device *pdev; | ||
| 1261 | DECLARE_WAITQUEUE(wait, current); | ||
| 1262 | |||
| 1263 | if (vdev == NULL) | ||
| 1264 | return -EFAULT; | ||
| 1265 | pdev = vdev->priv; | ||
| 1266 | if (pdev == NULL) | ||
| 1267 | return -EFAULT; | ||
| 1268 | |||
| 1269 | switch (cmd) { | ||
| 1270 | /* Query cabapilities */ | ||
| 1271 | case VIDIOCGCAP: | ||
| 1272 | { | ||
| 1273 | struct video_capability *caps = arg; | ||
| 1274 | |||
| 1275 | strcpy(caps->name, vdev->name); | ||
| 1276 | caps->type = VID_TYPE_CAPTURE; | ||
| 1277 | caps->channels = 1; | ||
| 1278 | caps->audios = 1; | ||
| 1279 | caps->minwidth = pdev->view_min.x; | ||
| 1280 | caps->minheight = pdev->view_min.y; | ||
| 1281 | caps->maxwidth = pdev->view_max.x; | ||
| 1282 | caps->maxheight = pdev->view_max.y; | ||
| 1283 | break; | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | /* Channel functions (simulate 1 channel) */ | ||
| 1287 | case VIDIOCGCHAN: | ||
| 1288 | { | ||
| 1289 | struct video_channel *v = arg; | ||
| 1290 | |||
| 1291 | if (v->channel != 0) | ||
| 1292 | return -EINVAL; | ||
| 1293 | v->flags = 0; | ||
| 1294 | v->tuners = 0; | ||
| 1295 | v->type = VIDEO_TYPE_CAMERA; | ||
| 1296 | strcpy(v->name, "Webcam"); | ||
| 1297 | return 0; | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | case VIDIOCSCHAN: | ||
| 1301 | { | ||
| 1302 | /* The spec says the argument is an integer, but | ||
| 1303 | the bttv driver uses a video_channel arg, which | ||
| 1304 | makes sense becasue it also has the norm flag. | ||
| 1305 | */ | ||
| 1306 | struct video_channel *v = arg; | ||
| 1307 | if (v->channel != 0) | ||
| 1308 | return -EINVAL; | ||
| 1309 | return 0; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | |||
| 1313 | /* Picture functions; contrast etc. */ | ||
| 1314 | case VIDIOCGPICT: | ||
| 1315 | { | ||
| 1316 | struct video_picture *p = arg; | ||
| 1317 | int val; | ||
| 1318 | |||
| 1319 | val = pwc_get_brightness(pdev); | ||
| 1320 | if (val >= 0) | ||
| 1321 | p->brightness = val; | ||
| 1322 | else | ||
| 1323 | p->brightness = 0xffff; | ||
| 1324 | val = pwc_get_contrast(pdev); | ||
| 1325 | if (val >= 0) | ||
| 1326 | p->contrast = val; | ||
| 1327 | else | ||
| 1328 | p->contrast = 0xffff; | ||
| 1329 | /* Gamma, Whiteness, what's the difference? :) */ | ||
| 1330 | val = pwc_get_gamma(pdev); | ||
| 1331 | if (val >= 0) | ||
| 1332 | p->whiteness = val; | ||
| 1333 | else | ||
| 1334 | p->whiteness = 0xffff; | ||
| 1335 | val = pwc_get_saturation(pdev); | ||
| 1336 | if (val >= 0) | ||
| 1337 | p->colour = val; | ||
| 1338 | else | ||
| 1339 | p->colour = 0xffff; | ||
| 1340 | p->depth = 24; | ||
| 1341 | p->palette = pdev->vpalette; | ||
| 1342 | p->hue = 0xFFFF; /* N/A */ | ||
| 1343 | break; | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | case VIDIOCSPICT: | ||
| 1347 | { | ||
| 1348 | struct video_picture *p = arg; | ||
| 1349 | /* | ||
| 1350 | * FIXME: Suppose we are mid read | ||
| 1351 | ANSWER: No problem: the firmware of the camera | ||
| 1352 | can handle brightness/contrast/etc | ||
| 1353 | changes at _any_ time, and the palette | ||
| 1354 | is used exactly once in the uncompress | ||
| 1355 | routine. | ||
| 1356 | */ | ||
| 1357 | pwc_set_brightness(pdev, p->brightness); | ||
| 1358 | pwc_set_contrast(pdev, p->contrast); | ||
| 1359 | pwc_set_gamma(pdev, p->whiteness); | ||
| 1360 | pwc_set_saturation(pdev, p->colour); | ||
| 1361 | if (p->palette && p->palette != pdev->vpalette) { | ||
| 1362 | switch (p->palette) { | ||
| 1363 | case VIDEO_PALETTE_YUV420P: | ||
| 1364 | case VIDEO_PALETTE_RAW: | ||
| 1365 | pdev->vpalette = p->palette; | ||
| 1366 | return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
| 1367 | break; | ||
| 1368 | default: | ||
| 1369 | return -EINVAL; | ||
| 1370 | break; | ||
| 1371 | } | ||
| 1372 | } | ||
| 1373 | break; | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | /* Window/size parameters */ | ||
| 1377 | case VIDIOCGWIN: | ||
| 1378 | { | ||
| 1379 | struct video_window *vw = arg; | ||
| 1380 | |||
| 1381 | vw->x = 0; | ||
| 1382 | vw->y = 0; | ||
| 1383 | vw->width = pdev->view.x; | ||
| 1384 | vw->height = pdev->view.y; | ||
| 1385 | vw->chromakey = 0; | ||
| 1386 | vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | | ||
| 1387 | (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); | ||
| 1388 | break; | ||
| 1389 | } | ||
| 1390 | |||
| 1391 | case VIDIOCSWIN: | ||
| 1392 | { | ||
| 1393 | struct video_window *vw = arg; | ||
| 1394 | int fps, snapshot, ret; | ||
| 1395 | |||
| 1396 | fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; | ||
| 1397 | snapshot = vw->flags & PWC_FPS_SNAPSHOT; | ||
| 1398 | if (fps == 0) | ||
| 1399 | fps = pdev->vframes; | ||
| 1400 | if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) | ||
| 1401 | return 0; | ||
| 1402 | ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); | ||
| 1403 | if (ret) | ||
| 1404 | return ret; | ||
| 1405 | break; | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | /* We don't have overlay support (yet) */ | ||
| 1409 | case VIDIOCGFBUF: | ||
| 1410 | { | ||
| 1411 | struct video_buffer *vb = arg; | ||
| 1412 | |||
| 1413 | memset(vb,0,sizeof(*vb)); | ||
| 1414 | break; | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | /* mmap() functions */ | ||
| 1418 | case VIDIOCGMBUF: | ||
| 1419 | { | ||
| 1420 | /* Tell the user program how much memory is needed for a mmap() */ | ||
| 1421 | struct video_mbuf *vm = arg; | ||
| 1422 | int i; | ||
| 1423 | |||
| 1424 | memset(vm, 0, sizeof(*vm)); | ||
| 1425 | vm->size = default_mbufs * pdev->len_per_image; | ||
| 1426 | vm->frames = default_mbufs; /* double buffering should be enough for most applications */ | ||
| 1427 | for (i = 0; i < default_mbufs; i++) | ||
| 1428 | vm->offsets[i] = i * pdev->len_per_image; | ||
| 1429 | break; | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | case VIDIOCMCAPTURE: | ||
| 1433 | { | ||
| 1434 | /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ | ||
| 1435 | struct video_mmap *vm = arg; | ||
| 1436 | |||
| 1437 | Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); | ||
| 1438 | if (vm->frame < 0 || vm->frame >= default_mbufs) | ||
| 1439 | return -EINVAL; | ||
| 1440 | |||
| 1441 | /* xawtv is nasty. It probes the available palettes | ||
| 1442 | by setting a very small image size and trying | ||
| 1443 | various palettes... The driver doesn't support | ||
| 1444 | such small images, so I'm working around it. | ||
| 1445 | */ | ||
| 1446 | if (vm->format) | ||
| 1447 | { | ||
| 1448 | switch (vm->format) | ||
| 1449 | { | ||
| 1450 | case VIDEO_PALETTE_YUV420P: | ||
| 1451 | case VIDEO_PALETTE_RAW: | ||
| 1452 | break; | ||
| 1453 | default: | ||
| 1454 | return -EINVAL; | ||
| 1455 | break; | ||
| 1456 | } | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && | ||
| 1460 | (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { | ||
| 1461 | int ret; | ||
| 1462 | |||
| 1463 | Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); | ||
| 1464 | ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
| 1465 | if (ret) | ||
| 1466 | return ret; | ||
| 1467 | } /* ... size mismatch */ | ||
| 1468 | |||
| 1469 | /* FIXME: should we lock here? */ | ||
| 1470 | if (pdev->image_used[vm->frame]) | ||
| 1471 | return -EBUSY; /* buffer wasn't available. Bummer */ | ||
| 1472 | pdev->image_used[vm->frame] = 1; | ||
| 1473 | |||
| 1474 | /* Okay, we're done here. In the SYNC call we wait until a | ||
| 1475 | frame comes available, then expand image into the given | ||
| 1476 | buffer. | ||
| 1477 | In contrast to the CPiA cam the Philips cams deliver a | ||
| 1478 | constant stream, almost like a grabber card. Also, | ||
| 1479 | we have separate buffers for the rawdata and the image, | ||
| 1480 | meaning we can nearly always expand into the requested buffer. | ||
| 1481 | */ | ||
| 1482 | Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); | ||
| 1483 | break; | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | case VIDIOCSYNC: | ||
| 1487 | { | ||
| 1488 | /* The doc says: "Whenever a buffer is used it should | ||
| 1489 | call VIDIOCSYNC to free this frame up and continue." | ||
| 1490 | |||
| 1491 | The only odd thing about this whole procedure is | ||
| 1492 | that MCAPTURE flags the buffer as "in use", and | ||
| 1493 | SYNC immediately unmarks it, while it isn't | ||
| 1494 | after SYNC that you know that the buffer actually | ||
| 1495 | got filled! So you better not start a CAPTURE in | ||
| 1496 | the same frame immediately (use double buffering). | ||
| 1497 | This is not a problem for this cam, since it has | ||
| 1498 | extra intermediate buffers, but a hardware | ||
| 1499 | grabber card will then overwrite the buffer | ||
| 1500 | you're working on. | ||
| 1501 | */ | ||
| 1502 | int *mbuf = arg; | ||
| 1503 | int ret; | ||
| 1504 | |||
| 1505 | Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); | ||
| 1506 | |||
| 1507 | /* bounds check */ | ||
| 1508 | if (*mbuf < 0 || *mbuf >= default_mbufs) | ||
| 1509 | return -EINVAL; | ||
| 1510 | /* check if this buffer was requested anyway */ | ||
| 1511 | if (pdev->image_used[*mbuf] == 0) | ||
| 1512 | return -EINVAL; | ||
| 1513 | |||
| 1514 | /* Add ourselves to the frame wait-queue. | ||
| 1515 | |||
| 1516 | FIXME: needs auditing for safety. | ||
| 1517 | QUESTION: In what respect? I think that using the | ||
| 1518 | frameq is safe now. | ||
| 1519 | */ | ||
| 1520 | add_wait_queue(&pdev->frameq, &wait); | ||
| 1521 | while (pdev->full_frames == NULL) { | ||
| 1522 | if (pdev->error_status) { | ||
| 1523 | remove_wait_queue(&pdev->frameq, &wait); | ||
| 1524 | set_current_state(TASK_RUNNING); | ||
| 1525 | return -pdev->error_status; | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | if (signal_pending(current)) { | ||
| 1529 | remove_wait_queue(&pdev->frameq, &wait); | ||
| 1530 | set_current_state(TASK_RUNNING); | ||
| 1531 | return -ERESTARTSYS; | ||
| 1532 | } | ||
| 1533 | schedule(); | ||
| 1534 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 1535 | } | ||
| 1536 | remove_wait_queue(&pdev->frameq, &wait); | ||
| 1537 | set_current_state(TASK_RUNNING); | ||
| 1538 | |||
| 1539 | /* The frame is ready. Expand in the image buffer | ||
| 1540 | requested by the user. I don't care if you | ||
| 1541 | mmap() 5 buffers and request data in this order: | ||
| 1542 | buffer 4 2 3 0 1 2 3 0 4 3 1 . . . | ||
| 1543 | Grabber hardware may not be so forgiving. | ||
| 1544 | */ | ||
| 1545 | Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); | ||
| 1546 | pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ | ||
| 1547 | /* Decompress, etc */ | ||
| 1548 | ret = pwc_handle_frame(pdev); | ||
| 1549 | pdev->image_used[*mbuf] = 0; | ||
| 1550 | if (ret) | ||
| 1551 | return -EFAULT; | ||
| 1552 | break; | ||
| 1553 | } | ||
| 1554 | |||
| 1555 | case VIDIOCGAUDIO: | ||
| 1556 | { | ||
| 1557 | struct video_audio *v = arg; | ||
| 1558 | |||
| 1559 | strcpy(v->name, "Microphone"); | ||
| 1560 | v->audio = -1; /* unknown audio minor */ | ||
| 1561 | v->flags = 0; | ||
| 1562 | v->mode = VIDEO_SOUND_MONO; | ||
| 1563 | v->volume = 0; | ||
| 1564 | v->bass = 0; | ||
| 1565 | v->treble = 0; | ||
| 1566 | v->balance = 0x8000; | ||
| 1567 | v->step = 1; | ||
| 1568 | break; | ||
| 1569 | } | ||
| 1570 | |||
| 1571 | case VIDIOCSAUDIO: | ||
| 1572 | { | ||
| 1573 | /* Dummy: nothing can be set */ | ||
| 1574 | break; | ||
| 1575 | } | ||
| 1576 | |||
| 1577 | case VIDIOCGUNIT: | ||
| 1578 | { | ||
| 1579 | struct video_unit *vu = arg; | ||
| 1580 | |||
| 1581 | vu->video = pdev->vdev->minor & 0x3F; | ||
| 1582 | vu->audio = -1; /* not known yet */ | ||
| 1583 | vu->vbi = -1; | ||
| 1584 | vu->radio = -1; | ||
| 1585 | vu->teletext = -1; | ||
| 1586 | break; | ||
| 1587 | } | ||
| 1588 | default: | ||
| 1589 | return pwc_ioctl(pdev, cmd, arg); | ||
| 1590 | } /* ..switch */ | ||
| 1591 | return 0; | ||
| 1592 | } | ||
| 1593 | |||
| 1594 | static int pwc_video_ioctl(struct inode *inode, struct file *file, | ||
| 1595 | unsigned int cmd, unsigned long arg) | ||
| 1596 | { | ||
| 1597 | return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); | ||
| 1598 | } | ||
| 1599 | |||
| 1600 | |||
| 1601 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 1602 | { | ||
| 1603 | struct video_device *vdev = file->private_data; | ||
| 1604 | struct pwc_device *pdev; | ||
| 1605 | unsigned long start = vma->vm_start; | ||
| 1606 | unsigned long size = vma->vm_end-vma->vm_start; | ||
| 1607 | unsigned long page, pos; | ||
| 1608 | |||
| 1609 | Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); | ||
| 1610 | pdev = vdev->priv; | ||
| 1611 | |||
| 1612 | vma->vm_flags |= VM_IO; | ||
| 1613 | |||
| 1614 | pos = (unsigned long)pdev->image_data; | ||
| 1615 | while (size > 0) { | ||
| 1616 | page = vmalloc_to_pfn((void *)pos); | ||
| 1617 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) | ||
| 1618 | return -EAGAIN; | ||
| 1619 | |||
| 1620 | start += PAGE_SIZE; | ||
| 1621 | pos += PAGE_SIZE; | ||
| 1622 | if (size > PAGE_SIZE) | ||
| 1623 | size -= PAGE_SIZE; | ||
| 1624 | else | ||
| 1625 | size = 0; | ||
| 1626 | } | ||
| 1627 | |||
| 1628 | return 0; | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | /***************************************************************************/ | ||
| 1632 | /* USB functions */ | ||
| 1633 | |||
| 1634 | /* This function gets called when a new device is plugged in or the usb core | ||
| 1635 | * is loaded. | ||
| 1636 | */ | ||
| 1637 | |||
| 1638 | static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
| 1639 | { | ||
| 1640 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 1641 | struct pwc_device *pdev = NULL; | ||
| 1642 | int vendor_id, product_id, type_id; | ||
| 1643 | int i, hint; | ||
| 1644 | int features = 0; | ||
| 1645 | int video_nr = -1; /* default: use next available device */ | ||
| 1646 | char serial_number[30], *name; | ||
| 1647 | |||
| 1648 | /* Check if we can handle this device */ | ||
| 1649 | Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", | ||
| 1650 | le16_to_cpu(udev->descriptor.idVendor), | ||
| 1651 | le16_to_cpu(udev->descriptor.idProduct), | ||
| 1652 | intf->altsetting->desc.bInterfaceNumber); | ||
| 1653 | |||
| 1654 | /* the interfaces are probed one by one. We are only interested in the | ||
| 1655 | video interface (0) now. | ||
| 1656 | Interface 1 is the Audio Control, and interface 2 Audio itself. | ||
| 1657 | */ | ||
| 1658 | if (intf->altsetting->desc.bInterfaceNumber > 0) | ||
| 1659 | return -ENODEV; | ||
| 1660 | |||
| 1661 | vendor_id = le16_to_cpu(udev->descriptor.idVendor); | ||
| 1662 | product_id = le16_to_cpu(udev->descriptor.idProduct); | ||
| 1663 | |||
| 1664 | if (vendor_id == 0x0471) { | ||
| 1665 | switch (product_id) { | ||
| 1666 | case 0x0302: | ||
| 1667 | Info("Philips PCA645VC USB webcam detected.\n"); | ||
| 1668 | name = "Philips 645 webcam"; | ||
| 1669 | type_id = 645; | ||
| 1670 | break; | ||
| 1671 | case 0x0303: | ||
| 1672 | Info("Philips PCA646VC USB webcam detected.\n"); | ||
| 1673 | name = "Philips 646 webcam"; | ||
| 1674 | type_id = 646; | ||
| 1675 | break; | ||
| 1676 | case 0x0304: | ||
| 1677 | Info("Askey VC010 type 2 USB webcam detected.\n"); | ||
| 1678 | name = "Askey VC010 webcam"; | ||
| 1679 | type_id = 646; | ||
| 1680 | break; | ||
| 1681 | case 0x0307: | ||
| 1682 | Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); | ||
| 1683 | name = "Philips 675 webcam"; | ||
| 1684 | type_id = 675; | ||
| 1685 | break; | ||
| 1686 | case 0x0308: | ||
| 1687 | Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); | ||
| 1688 | name = "Philips 680 webcam"; | ||
| 1689 | type_id = 680; | ||
| 1690 | break; | ||
| 1691 | case 0x030C: | ||
| 1692 | Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); | ||
| 1693 | name = "Philips 690 webcam"; | ||
| 1694 | type_id = 690; | ||
| 1695 | break; | ||
| 1696 | case 0x0310: | ||
| 1697 | Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); | ||
| 1698 | name = "Philips 730 webcam"; | ||
| 1699 | type_id = 730; | ||
| 1700 | break; | ||
| 1701 | case 0x0311: | ||
| 1702 | Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); | ||
| 1703 | name = "Philips 740 webcam"; | ||
| 1704 | type_id = 740; | ||
| 1705 | break; | ||
| 1706 | case 0x0312: | ||
| 1707 | Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); | ||
| 1708 | name = "Philips 750 webcam"; | ||
| 1709 | type_id = 750; | ||
| 1710 | break; | ||
| 1711 | case 0x0313: | ||
| 1712 | Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); | ||
| 1713 | name = "Philips 720K/40 webcam"; | ||
| 1714 | type_id = 720; | ||
| 1715 | break; | ||
| 1716 | default: | ||
| 1717 | return -ENODEV; | ||
| 1718 | break; | ||
| 1719 | } | ||
| 1720 | } | ||
| 1721 | else if (vendor_id == 0x069A) { | ||
| 1722 | switch(product_id) { | ||
| 1723 | case 0x0001: | ||
| 1724 | Info("Askey VC010 type 1 USB webcam detected.\n"); | ||
| 1725 | name = "Askey VC010 webcam"; | ||
| 1726 | type_id = 645; | ||
| 1727 | break; | ||
| 1728 | default: | ||
| 1729 | return -ENODEV; | ||
| 1730 | break; | ||
| 1731 | } | ||
| 1732 | } | ||
| 1733 | else if (vendor_id == 0x046d) { | ||
| 1734 | switch(product_id) { | ||
| 1735 | case 0x08b0: | ||
| 1736 | Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); | ||
| 1737 | name = "Logitech QuickCam Pro 3000"; | ||
| 1738 | type_id = 740; /* CCD sensor */ | ||
| 1739 | break; | ||
| 1740 | case 0x08b1: | ||
| 1741 | Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); | ||
| 1742 | name = "Logitech QuickCam Notebook Pro"; | ||
| 1743 | type_id = 740; /* CCD sensor */ | ||
| 1744 | break; | ||
| 1745 | case 0x08b2: | ||
| 1746 | Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); | ||
| 1747 | name = "Logitech QuickCam Pro 4000"; | ||
| 1748 | type_id = 740; /* CCD sensor */ | ||
| 1749 | break; | ||
| 1750 | case 0x08b3: | ||
| 1751 | Info("Logitech QuickCam Zoom USB webcam detected.\n"); | ||
| 1752 | name = "Logitech QuickCam Zoom"; | ||
| 1753 | type_id = 740; /* CCD sensor */ | ||
| 1754 | break; | ||
| 1755 | case 0x08B4: | ||
| 1756 | Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); | ||
| 1757 | name = "Logitech QuickCam Zoom"; | ||
| 1758 | type_id = 740; /* CCD sensor */ | ||
| 1759 | break; | ||
| 1760 | case 0x08b5: | ||
| 1761 | Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); | ||
| 1762 | name = "Logitech QuickCam Orbit"; | ||
| 1763 | type_id = 740; /* CCD sensor */ | ||
| 1764 | features |= FEATURE_MOTOR_PANTILT; | ||
| 1765 | break; | ||
| 1766 | case 0x08b6: | ||
| 1767 | case 0x08b7: | ||
| 1768 | case 0x08b8: | ||
| 1769 | Info("Logitech QuickCam detected (reserved ID).\n"); | ||
| 1770 | name = "Logitech QuickCam (res.)"; | ||
| 1771 | type_id = 730; /* Assuming CMOS */ | ||
| 1772 | break; | ||
| 1773 | default: | ||
| 1774 | return -ENODEV; | ||
| 1775 | break; | ||
| 1776 | } | ||
| 1777 | } | ||
| 1778 | else if (vendor_id == 0x055d) { | ||
| 1779 | /* I don't know the difference between the C10 and the C30; | ||
| 1780 | I suppose the difference is the sensor, but both cameras | ||
| 1781 | work equally well with a type_id of 675 | ||
| 1782 | */ | ||
| 1783 | switch(product_id) { | ||
| 1784 | case 0x9000: | ||
| 1785 | Info("Samsung MPC-C10 USB webcam detected.\n"); | ||
| 1786 | name = "Samsung MPC-C10"; | ||
| 1787 | type_id = 675; | ||
| 1788 | break; | ||
| 1789 | case 0x9001: | ||
| 1790 | Info("Samsung MPC-C30 USB webcam detected.\n"); | ||
| 1791 | name = "Samsung MPC-C30"; | ||
| 1792 | type_id = 675; | ||
| 1793 | break; | ||
| 1794 | default: | ||
| 1795 | return -ENODEV; | ||
| 1796 | break; | ||
| 1797 | } | ||
| 1798 | } | ||
| 1799 | else if (vendor_id == 0x041e) { | ||
| 1800 | switch(product_id) { | ||
| 1801 | case 0x400c: | ||
| 1802 | Info("Creative Labs Webcam 5 detected.\n"); | ||
| 1803 | name = "Creative Labs Webcam 5"; | ||
| 1804 | type_id = 730; | ||
| 1805 | break; | ||
| 1806 | case 0x4011: | ||
| 1807 | Info("Creative Labs Webcam Pro Ex detected.\n"); | ||
| 1808 | name = "Creative Labs Webcam Pro Ex"; | ||
| 1809 | type_id = 740; | ||
| 1810 | break; | ||
| 1811 | default: | ||
| 1812 | return -ENODEV; | ||
| 1813 | break; | ||
| 1814 | } | ||
| 1815 | } | ||
| 1816 | else if (vendor_id == 0x04cc) { | ||
| 1817 | switch(product_id) { | ||
| 1818 | case 0x8116: | ||
| 1819 | Info("Sotec Afina Eye USB webcam detected.\n"); | ||
| 1820 | name = "Sotec Afina Eye"; | ||
| 1821 | type_id = 730; | ||
| 1822 | break; | ||
| 1823 | default: | ||
| 1824 | return -ENODEV; | ||
| 1825 | break; | ||
| 1826 | } | ||
| 1827 | } | ||
| 1828 | else if (vendor_id == 0x06be) { | ||
| 1829 | switch(product_id) { | ||
| 1830 | case 0x8116: | ||
| 1831 | /* This is essentially the same cam as the Sotec Afina Eye */ | ||
| 1832 | Info("AME Co. Afina Eye USB webcam detected.\n"); | ||
| 1833 | name = "AME Co. Afina Eye"; | ||
| 1834 | type_id = 750; | ||
| 1835 | break; | ||
| 1836 | default: | ||
| 1837 | return -ENODEV; | ||
| 1838 | break; | ||
| 1839 | } | ||
| 1840 | |||
| 1841 | } | ||
| 1842 | else if (vendor_id == 0x0d81) { | ||
| 1843 | switch(product_id) { | ||
| 1844 | case 0x1900: | ||
| 1845 | Info("Visionite VCS-UC300 USB webcam detected.\n"); | ||
| 1846 | name = "Visionite VCS-UC300"; | ||
| 1847 | type_id = 740; /* CCD sensor */ | ||
| 1848 | break; | ||
| 1849 | case 0x1910: | ||
| 1850 | Info("Visionite VCS-UM100 USB webcam detected.\n"); | ||
| 1851 | name = "Visionite VCS-UM100"; | ||
| 1852 | type_id = 730; /* CMOS sensor */ | ||
| 1853 | break; | ||
| 1854 | default: | ||
| 1855 | return -ENODEV; | ||
| 1856 | break; | ||
| 1857 | } | ||
| 1858 | } | ||
| 1859 | else | ||
| 1860 | return -ENODEV; /* Not any of the know types; but the list keeps growing. */ | ||
| 1861 | |||
| 1862 | memset(serial_number, 0, 30); | ||
| 1863 | usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); | ||
| 1864 | Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); | ||
| 1865 | |||
| 1866 | if (udev->descriptor.bNumConfigurations > 1) | ||
| 1867 | Info("Warning: more than 1 configuration available.\n"); | ||
| 1868 | |||
| 1869 | /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ | ||
| 1870 | pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL); | ||
| 1871 | if (pdev == NULL) { | ||
| 1872 | Err("Oops, could not allocate memory for pwc_device.\n"); | ||
| 1873 | return -ENOMEM; | ||
| 1874 | } | ||
| 1875 | pdev->type = type_id; | ||
| 1876 | pdev->vsize = default_size; | ||
| 1877 | pdev->vframes = default_fps; | ||
| 1878 | strcpy(pdev->serial, serial_number); | ||
| 1879 | pdev->features = features; | ||
| 1880 | if (vendor_id == 0x046D && product_id == 0x08B5) | ||
| 1881 | { | ||
| 1882 | /* Logitech QuickCam Orbit | ||
| 1883 | The ranges have been determined experimentally; they may differ from cam to cam. | ||
| 1884 | Also, the exact ranges left-right and up-down are different for my cam | ||
| 1885 | */ | ||
| 1886 | pdev->angle_range.pan_min = -7000; | ||
| 1887 | pdev->angle_range.pan_max = 7000; | ||
| 1888 | pdev->angle_range.tilt_min = -3000; | ||
| 1889 | pdev->angle_range.tilt_max = 2500; | ||
| 1890 | } | ||
| 1891 | |||
| 1892 | init_MUTEX(&pdev->modlock); | ||
| 1893 | spin_lock_init(&pdev->ptrlock); | ||
| 1894 | |||
| 1895 | pdev->udev = udev; | ||
| 1896 | init_waitqueue_head(&pdev->frameq); | ||
| 1897 | pdev->vcompression = pwc_preferred_compression; | ||
| 1898 | |||
| 1899 | /* Allocate video_device structure */ | ||
| 1900 | pdev->vdev = video_device_alloc(); | ||
| 1901 | if (pdev->vdev == 0) | ||
| 1902 | { | ||
| 1903 | Err("Err, cannot allocate video_device struture. Failing probe."); | ||
| 1904 | kfree(pdev); | ||
| 1905 | return -ENOMEM; | ||
| 1906 | } | ||
| 1907 | memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); | ||
| 1908 | strcpy(pdev->vdev->name, name); | ||
| 1909 | pdev->vdev->owner = THIS_MODULE; | ||
| 1910 | video_set_drvdata(pdev->vdev, pdev); | ||
| 1911 | |||
| 1912 | pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); | ||
| 1913 | Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); | ||
| 1914 | |||
| 1915 | /* Now search device_hint[] table for a match, so we can hint a node number. */ | ||
| 1916 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) { | ||
| 1917 | if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && | ||
| 1918 | (device_hint[hint].pdev == NULL)) { | ||
| 1919 | /* so far, so good... try serial number */ | ||
| 1920 | if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { | ||
| 1921 | /* match! */ | ||
| 1922 | video_nr = device_hint[hint].device_node; | ||
| 1923 | Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr); | ||
| 1924 | break; | ||
| 1925 | } | ||
| 1926 | } | ||
| 1927 | } | ||
| 1928 | |||
| 1929 | pdev->vdev->release = video_device_release; | ||
| 1930 | i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); | ||
| 1931 | if (i < 0) { | ||
| 1932 | Err("Failed to register as video device (%d).\n", i); | ||
| 1933 | video_device_release(pdev->vdev); /* Drip... drip... drip... */ | ||
| 1934 | kfree(pdev); /* Oops, no memory leaks please */ | ||
| 1935 | return -EIO; | ||
| 1936 | } | ||
| 1937 | else { | ||
| 1938 | Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); | ||
| 1939 | } | ||
| 1940 | |||
| 1941 | /* occupy slot */ | ||
| 1942 | if (hint < MAX_DEV_HINTS) | ||
| 1943 | device_hint[hint].pdev = pdev; | ||
| 1944 | |||
| 1945 | Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); | ||
| 1946 | usb_set_intfdata (intf, pdev); | ||
| 1947 | return 0; | ||
| 1948 | } | ||
| 1949 | |||
| 1950 | /* The user janked out the cable... */ | ||
| 1951 | static void usb_pwc_disconnect(struct usb_interface *intf) | ||
| 1952 | { | ||
| 1953 | struct pwc_device *pdev; | ||
| 1954 | int hint; | ||
| 1955 | |||
| 1956 | lock_kernel(); | ||
| 1957 | pdev = usb_get_intfdata (intf); | ||
| 1958 | usb_set_intfdata (intf, NULL); | ||
| 1959 | if (pdev == NULL) { | ||
| 1960 | Err("pwc_disconnect() Called without private pointer.\n"); | ||
| 1961 | goto disconnect_out; | ||
| 1962 | } | ||
| 1963 | if (pdev->udev == NULL) { | ||
| 1964 | Err("pwc_disconnect() already called for %p\n", pdev); | ||
| 1965 | goto disconnect_out; | ||
| 1966 | } | ||
| 1967 | if (pdev->udev != interface_to_usbdev(intf)) { | ||
| 1968 | Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); | ||
| 1969 | goto disconnect_out; | ||
| 1970 | } | ||
| 1971 | #ifdef PWC_MAGIC | ||
| 1972 | if (pdev->magic != PWC_MAGIC) { | ||
| 1973 | Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); | ||
| 1974 | goto disconnect_out; | ||
| 1975 | } | ||
| 1976 | #endif | ||
| 1977 | |||
| 1978 | /* We got unplugged; this is signalled by an EPIPE error code */ | ||
| 1979 | if (pdev->vopen) { | ||
| 1980 | Info("Disconnected while webcam is in use!\n"); | ||
| 1981 | pdev->error_status = EPIPE; | ||
| 1982 | } | ||
| 1983 | |||
| 1984 | /* Alert waiting processes */ | ||
| 1985 | wake_up_interruptible(&pdev->frameq); | ||
| 1986 | /* Wait until device is closed */ | ||
| 1987 | while (pdev->vopen) | ||
| 1988 | schedule(); | ||
| 1989 | /* Device is now closed, so we can safely unregister it */ | ||
| 1990 | Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); | ||
| 1991 | video_unregister_device(pdev->vdev); | ||
| 1992 | |||
| 1993 | /* Free memory (don't set pdev to 0 just yet) */ | ||
| 1994 | kfree(pdev); | ||
| 1995 | |||
| 1996 | disconnect_out: | ||
| 1997 | /* search device_hint[] table if we occupy a slot, by any chance */ | ||
| 1998 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) | ||
| 1999 | if (device_hint[hint].pdev == pdev) | ||
| 2000 | device_hint[hint].pdev = NULL; | ||
| 2001 | |||
| 2002 | unlock_kernel(); | ||
| 2003 | } | ||
| 2004 | |||
| 2005 | |||
| 2006 | /* *grunt* We have to do atoi ourselves :-( */ | ||
| 2007 | static int pwc_atoi(const char *s) | ||
| 2008 | { | ||
| 2009 | int k = 0; | ||
| 2010 | |||
| 2011 | k = 0; | ||
| 2012 | while (*s != '\0' && *s >= '0' && *s <= '9') { | ||
| 2013 | k = 10 * k + (*s - '0'); | ||
| 2014 | s++; | ||
| 2015 | } | ||
| 2016 | return k; | ||
| 2017 | } | ||
| 2018 | |||
| 2019 | |||
| 2020 | /* | ||
| 2021 | * Initialization code & module stuff | ||
| 2022 | */ | ||
| 2023 | |||
| 2024 | static char size[10]; | ||
| 2025 | static int fps = 0; | ||
| 2026 | static int fbufs = 0; | ||
| 2027 | static int mbufs = 0; | ||
| 2028 | static int trace = -1; | ||
| 2029 | static int compression = -1; | ||
| 2030 | static int leds[2] = { -1, -1 }; | ||
| 2031 | static char *dev_hint[MAX_DEV_HINTS] = { }; | ||
| 2032 | |||
| 2033 | module_param_string(size, size, sizeof(size), 0); | ||
| 2034 | MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); | ||
| 2035 | module_param(fps, int, 0000); | ||
| 2036 | MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); | ||
| 2037 | module_param(fbufs, int, 0000); | ||
| 2038 | MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); | ||
| 2039 | module_param(mbufs, int, 0000); | ||
| 2040 | MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); | ||
| 2041 | module_param(trace, int, 0000); | ||
| 2042 | MODULE_PARM_DESC(trace, "For debugging purposes"); | ||
| 2043 | module_param(power_save, bool, 0000); | ||
| 2044 | MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); | ||
| 2045 | module_param(compression, int, 0000); | ||
| 2046 | MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); | ||
| 2047 | module_param_array(leds, int, NULL, 0000); | ||
| 2048 | MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); | ||
| 2049 | module_param_array(dev_hint, charp, NULL, 0000); | ||
| 2050 | MODULE_PARM_DESC(dev_hint, "Device node hints"); | ||
| 2051 | |||
| 2052 | MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); | ||
| 2053 | MODULE_AUTHOR("Luc Saillard <luc@saillard.org>"); | ||
| 2054 | MODULE_LICENSE("GPL"); | ||
| 2055 | |||
| 2056 | static int __init usb_pwc_init(void) | ||
| 2057 | { | ||
| 2058 | int i, sz; | ||
| 2059 | char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; | ||
| 2060 | |||
| 2061 | Info("Philips webcam module version " PWC_VERSION " loaded.\n"); | ||
| 2062 | Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); | ||
| 2063 | Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); | ||
| 2064 | Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); | ||
| 2065 | |||
| 2066 | if (fps) { | ||
| 2067 | if (fps < 4 || fps > 30) { | ||
| 2068 | Err("Framerate out of bounds (4-30).\n"); | ||
| 2069 | return -EINVAL; | ||
| 2070 | } | ||
| 2071 | default_fps = fps; | ||
| 2072 | Info("Default framerate set to %d.\n", default_fps); | ||
| 2073 | } | ||
| 2074 | |||
| 2075 | if (size[0]) { | ||
| 2076 | /* string; try matching with array */ | ||
| 2077 | for (sz = 0; sz < PSZ_MAX; sz++) { | ||
| 2078 | if (!strcmp(sizenames[sz], size)) { /* Found! */ | ||
| 2079 | default_size = sz; | ||
| 2080 | break; | ||
| 2081 | } | ||
| 2082 | } | ||
| 2083 | if (sz == PSZ_MAX) { | ||
| 2084 | Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); | ||
| 2085 | return -EINVAL; | ||
| 2086 | } | ||
| 2087 | Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); | ||
| 2088 | } | ||
| 2089 | if (mbufs) { | ||
| 2090 | if (mbufs < 1 || mbufs > MAX_IMAGES) { | ||
| 2091 | Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); | ||
| 2092 | return -EINVAL; | ||
| 2093 | } | ||
| 2094 | default_mbufs = mbufs; | ||
| 2095 | Info("Number of image buffers set to %d.\n", default_mbufs); | ||
| 2096 | } | ||
| 2097 | if (fbufs) { | ||
| 2098 | if (fbufs < 2 || fbufs > MAX_FRAMES) { | ||
| 2099 | Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); | ||
| 2100 | return -EINVAL; | ||
| 2101 | } | ||
| 2102 | default_fbufs = fbufs; | ||
| 2103 | Info("Number of frame buffers set to %d.\n", default_fbufs); | ||
| 2104 | } | ||
| 2105 | if (trace >= 0) { | ||
| 2106 | Info("Trace options: 0x%04x\n", trace); | ||
| 2107 | pwc_trace = trace; | ||
| 2108 | } | ||
| 2109 | if (compression >= 0) { | ||
| 2110 | if (compression > 3) { | ||
| 2111 | Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); | ||
| 2112 | return -EINVAL; | ||
| 2113 | } | ||
| 2114 | pwc_preferred_compression = compression; | ||
| 2115 | Info("Preferred compression set to %d.\n", pwc_preferred_compression); | ||
| 2116 | } | ||
| 2117 | if (power_save) | ||
| 2118 | Info("Enabling power save on open/close.\n"); | ||
| 2119 | if (leds[0] >= 0) | ||
| 2120 | led_on = leds[0]; | ||
| 2121 | if (leds[1] >= 0) | ||
| 2122 | led_off = leds[1]; | ||
| 2123 | |||
| 2124 | /* Big device node whoopla. Basically, it allows you to assign a | ||
| 2125 | device node (/dev/videoX) to a camera, based on its type | ||
| 2126 | & serial number. The format is [type[.serialnumber]:]node. | ||
| 2127 | |||
| 2128 | Any camera that isn't matched by these rules gets the next | ||
| 2129 | available free device node. | ||
| 2130 | */ | ||
| 2131 | for (i = 0; i < MAX_DEV_HINTS; i++) { | ||
| 2132 | char *s, *colon, *dot; | ||
| 2133 | |||
| 2134 | /* This loop also initializes the array */ | ||
| 2135 | device_hint[i].pdev = NULL; | ||
| 2136 | s = dev_hint[i]; | ||
| 2137 | if (s != NULL && *s != '\0') { | ||
| 2138 | device_hint[i].type = -1; /* wildcard */ | ||
| 2139 | strcpy(device_hint[i].serial_number, "*"); | ||
| 2140 | |||
| 2141 | /* parse string: chop at ':' & '/' */ | ||
| 2142 | colon = dot = s; | ||
| 2143 | while (*colon != '\0' && *colon != ':') | ||
| 2144 | colon++; | ||
| 2145 | while (*dot != '\0' && *dot != '.') | ||
| 2146 | dot++; | ||
| 2147 | /* Few sanity checks */ | ||
| 2148 | if (*dot != '\0' && dot > colon) { | ||
| 2149 | Err("Malformed camera hint: the colon must be after the dot.\n"); | ||
| 2150 | return -EINVAL; | ||
| 2151 | } | ||
| 2152 | |||
| 2153 | if (*colon == '\0') { | ||
| 2154 | /* No colon */ | ||
| 2155 | if (*dot != '\0') { | ||
| 2156 | Err("Malformed camera hint: no colon + device node given.\n"); | ||
| 2157 | return -EINVAL; | ||
| 2158 | } | ||
| 2159 | else { | ||
| 2160 | /* No type or serial number specified, just a number. */ | ||
| 2161 | device_hint[i].device_node = pwc_atoi(s); | ||
| 2162 | } | ||
| 2163 | } | ||
| 2164 | else { | ||
| 2165 | /* There's a colon, so we have at least a type and a device node */ | ||
| 2166 | device_hint[i].type = pwc_atoi(s); | ||
| 2167 | device_hint[i].device_node = pwc_atoi(colon + 1); | ||
| 2168 | if (*dot != '\0') { | ||
| 2169 | /* There's a serial number as well */ | ||
| 2170 | int k; | ||
| 2171 | |||
| 2172 | dot++; | ||
| 2173 | k = 0; | ||
| 2174 | while (*dot != ':' && k < 29) { | ||
| 2175 | device_hint[i].serial_number[k++] = *dot; | ||
| 2176 | dot++; | ||
| 2177 | } | ||
| 2178 | device_hint[i].serial_number[k] = '\0'; | ||
| 2179 | } | ||
| 2180 | } | ||
| 2181 | #if PWC_DEBUG | ||
| 2182 | Debug("device_hint[%d]:\n", i); | ||
| 2183 | Debug(" type : %d\n", device_hint[i].type); | ||
| 2184 | Debug(" serial# : %s\n", device_hint[i].serial_number); | ||
| 2185 | Debug(" node : %d\n", device_hint[i].device_node); | ||
| 2186 | #endif | ||
| 2187 | } | ||
| 2188 | else | ||
| 2189 | device_hint[i].type = 0; /* not filled */ | ||
| 2190 | } /* ..for MAX_DEV_HINTS */ | ||
| 2191 | |||
| 2192 | Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); | ||
| 2193 | return usb_register(&pwc_driver); | ||
| 2194 | } | ||
| 2195 | |||
| 2196 | static void __exit usb_pwc_exit(void) | ||
| 2197 | { | ||
| 2198 | Trace(TRACE_MODULE, "Deregistering driver.\n"); | ||
| 2199 | usb_deregister(&pwc_driver); | ||
| 2200 | Info("Philips webcam module removed.\n"); | ||
| 2201 | } | ||
| 2202 | |||
| 2203 | module_init(usb_pwc_init); | ||
| 2204 | module_exit(usb_pwc_exit); | ||
| 2205 | |||
diff --git a/drivers/usb/media/pwc/pwc-ioctl.h b/drivers/usb/media/pwc/pwc-ioctl.h deleted file mode 100644 index 5f9cb08bc02e..000000000000 --- a/drivers/usb/media/pwc/pwc-ioctl.h +++ /dev/null | |||
| @@ -1,292 +0,0 @@ | |||
| 1 | #ifndef PWC_IOCTL_H | ||
| 2 | #define PWC_IOCTL_H | ||
| 3 | |||
| 4 | /* (C) 2001-2004 Nemosoft Unv. | ||
| 5 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 6 | |||
| 7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 8 | driver and thus may have bugs that are not present in the original version. | ||
| 9 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 10 | The decompression routines have been implemented by reverse-engineering the | ||
| 11 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 12 | |||
| 13 | This program is free software; you can redistribute it and/or modify | ||
| 14 | it under the terms of the GNU General Public License as published by | ||
| 15 | the Free Software Foundation; either version 2 of the License, or | ||
| 16 | (at your option) any later version. | ||
| 17 | |||
| 18 | This program is distributed in the hope that it will be useful, | ||
| 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | GNU General Public License for more details. | ||
| 22 | |||
| 23 | You should have received a copy of the GNU General Public License | ||
| 24 | along with this program; if not, write to the Free Software | ||
| 25 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 26 | */ | ||
| 27 | |||
| 28 | /* This is pwc-ioctl.h belonging to PWC 8.12.1 | ||
| 29 | It contains structures and defines to communicate from user space | ||
| 30 | directly to the driver. | ||
| 31 | */ | ||
| 32 | |||
| 33 | /* | ||
| 34 | Changes | ||
| 35 | 2001/08/03 Alvarado Added ioctl constants to access methods for | ||
| 36 | changing white balance and red/blue gains | ||
| 37 | 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE | ||
| 38 | 2003/12/13 Nemosft Unv. Some modifications to make interfacing to | ||
| 39 | PWCX easier | ||
| 40 | */ | ||
| 41 | |||
| 42 | /* These are private ioctl() commands, specific for the Philips webcams. | ||
| 43 | They contain functions not found in other webcams, and settings not | ||
| 44 | specified in the Video4Linux API. | ||
| 45 | |||
| 46 | The #define names are built up like follows: | ||
| 47 | VIDIOC VIDeo IOCtl prefix | ||
| 48 | PWC Philps WebCam | ||
| 49 | G optional: Get | ||
| 50 | S optional: Set | ||
| 51 | ... the function | ||
| 52 | */ | ||
| 53 | |||
| 54 | |||
| 55 | /* Enumeration of image sizes */ | ||
| 56 | #define PSZ_SQCIF 0x00 | ||
| 57 | #define PSZ_QSIF 0x01 | ||
| 58 | #define PSZ_QCIF 0x02 | ||
| 59 | #define PSZ_SIF 0x03 | ||
| 60 | #define PSZ_CIF 0x04 | ||
| 61 | #define PSZ_VGA 0x05 | ||
| 62 | #define PSZ_MAX 6 | ||
| 63 | |||
| 64 | |||
| 65 | /* The frame rate is encoded in the video_window.flags parameter using | ||
| 66 | the upper 16 bits, since some flags are defined nowadays. The following | ||
| 67 | defines provide a mask and shift to filter out this value. | ||
| 68 | |||
| 69 | In 'Snapshot' mode the camera freezes its automatic exposure and colour | ||
| 70 | balance controls. | ||
| 71 | */ | ||
| 72 | #define PWC_FPS_SHIFT 16 | ||
| 73 | #define PWC_FPS_MASK 0x00FF0000 | ||
| 74 | #define PWC_FPS_FRMASK 0x003F0000 | ||
| 75 | #define PWC_FPS_SNAPSHOT 0x00400000 | ||
| 76 | |||
| 77 | |||
| 78 | /* structure for transferring x & y coordinates */ | ||
| 79 | struct pwc_coord | ||
| 80 | { | ||
| 81 | int x, y; /* guess what */ | ||
| 82 | int size; /* size, or offset */ | ||
| 83 | }; | ||
| 84 | |||
| 85 | |||
| 86 | /* Used with VIDIOCPWCPROBE */ | ||
| 87 | struct pwc_probe | ||
| 88 | { | ||
| 89 | char name[32]; | ||
| 90 | int type; | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct pwc_serial | ||
| 94 | { | ||
| 95 | char serial[30]; /* String with serial number. Contains terminating 0 */ | ||
| 96 | }; | ||
| 97 | |||
| 98 | /* pwc_whitebalance.mode values */ | ||
| 99 | #define PWC_WB_INDOOR 0 | ||
| 100 | #define PWC_WB_OUTDOOR 1 | ||
| 101 | #define PWC_WB_FL 2 | ||
| 102 | #define PWC_WB_MANUAL 3 | ||
| 103 | #define PWC_WB_AUTO 4 | ||
| 104 | |||
| 105 | /* Used with VIDIOCPWC[SG]AWB (Auto White Balance). | ||
| 106 | Set mode to one of the PWC_WB_* values above. | ||
| 107 | *red and *blue are the respective gains of these colour components inside | ||
| 108 | the camera; range 0..65535 | ||
| 109 | When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; | ||
| 110 | otherwise undefined. | ||
| 111 | 'read_red' and 'read_blue' are read-only. | ||
| 112 | */ | ||
| 113 | struct pwc_whitebalance | ||
| 114 | { | ||
| 115 | int mode; | ||
| 116 | int manual_red, manual_blue; /* R/W */ | ||
| 117 | int read_red, read_blue; /* R/O */ | ||
| 118 | }; | ||
| 119 | |||
| 120 | /* | ||
| 121 | 'control_speed' and 'control_delay' are used in automatic whitebalance mode, | ||
| 122 | and tell the camera how fast it should react to changes in lighting, and | ||
| 123 | with how much delay. Valid values are 0..65535. | ||
| 124 | */ | ||
| 125 | struct pwc_wb_speed | ||
| 126 | { | ||
| 127 | int control_speed; | ||
| 128 | int control_delay; | ||
| 129 | |||
| 130 | }; | ||
| 131 | |||
| 132 | /* Used with VIDIOCPWC[SG]LED */ | ||
| 133 | struct pwc_leds | ||
| 134 | { | ||
| 135 | int led_on; /* Led on-time; range = 0..25000 */ | ||
| 136 | int led_off; /* Led off-time; range = 0..25000 */ | ||
| 137 | }; | ||
| 138 | |||
| 139 | /* Image size (used with GREALSIZE) */ | ||
| 140 | struct pwc_imagesize | ||
| 141 | { | ||
| 142 | int width; | ||
| 143 | int height; | ||
| 144 | }; | ||
| 145 | |||
| 146 | /* Defines and structures for Motorized Pan & Tilt */ | ||
| 147 | #define PWC_MPT_PAN 0x01 | ||
| 148 | #define PWC_MPT_TILT 0x02 | ||
| 149 | #define PWC_MPT_TIMEOUT 0x04 /* for status */ | ||
| 150 | |||
| 151 | /* Set angles; when absolute != 0, the angle is absolute and the | ||
| 152 | driver calculates the relative offset for you. This can only | ||
| 153 | be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns | ||
| 154 | absolute angles. | ||
| 155 | */ | ||
| 156 | struct pwc_mpt_angles | ||
| 157 | { | ||
| 158 | int absolute; /* write-only */ | ||
| 159 | int pan; /* degrees * 100 */ | ||
| 160 | int tilt; /* degress * 100 */ | ||
| 161 | }; | ||
| 162 | |||
| 163 | /* Range of angles of the camera, both horizontally and vertically. | ||
| 164 | */ | ||
| 165 | struct pwc_mpt_range | ||
| 166 | { | ||
| 167 | int pan_min, pan_max; /* degrees * 100 */ | ||
| 168 | int tilt_min, tilt_max; | ||
| 169 | }; | ||
| 170 | |||
| 171 | struct pwc_mpt_status | ||
| 172 | { | ||
| 173 | int status; | ||
| 174 | int time_pan; | ||
| 175 | int time_tilt; | ||
| 176 | }; | ||
| 177 | |||
| 178 | |||
| 179 | /* This is used for out-of-kernel decompression. With it, you can get | ||
| 180 | all the necessary information to initialize and use the decompressor | ||
| 181 | routines in standalone applications. | ||
| 182 | */ | ||
| 183 | struct pwc_video_command | ||
| 184 | { | ||
| 185 | int type; /* camera type (645, 675, 730, etc.) */ | ||
| 186 | int release; /* release number */ | ||
| 187 | |||
| 188 | int size; /* one of PSZ_* */ | ||
| 189 | int alternate; | ||
| 190 | int command_len; /* length of USB video command */ | ||
| 191 | unsigned char command_buf[13]; /* Actual USB video command */ | ||
| 192 | int bandlength; /* >0 = compressed */ | ||
| 193 | int frame_size; /* Size of one (un)compressed frame */ | ||
| 194 | }; | ||
| 195 | |||
| 196 | /* Flags for PWCX subroutines. Not all modules honour all flags. */ | ||
| 197 | #define PWCX_FLAG_PLANAR 0x0001 | ||
| 198 | #define PWCX_FLAG_BAYER 0x0008 | ||
| 199 | |||
| 200 | |||
| 201 | /* IOCTL definitions */ | ||
| 202 | |||
| 203 | /* Restore user settings */ | ||
| 204 | #define VIDIOCPWCRUSER _IO('v', 192) | ||
| 205 | /* Save user settings */ | ||
| 206 | #define VIDIOCPWCSUSER _IO('v', 193) | ||
| 207 | /* Restore factory settings */ | ||
| 208 | #define VIDIOCPWCFACTORY _IO('v', 194) | ||
| 209 | |||
| 210 | /* You can manipulate the compression factor. A compression preference of 0 | ||
| 211 | means use uncompressed modes when available; 1 is low compression, 2 is | ||
| 212 | medium and 3 is high compression preferred. Of course, the higher the | ||
| 213 | compression, the lower the bandwidth used but more chance of artefacts | ||
| 214 | in the image. The driver automatically chooses a higher compression when | ||
| 215 | the preferred mode is not available. | ||
| 216 | */ | ||
| 217 | /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ | ||
| 218 | #define VIDIOCPWCSCQUAL _IOW('v', 195, int) | ||
| 219 | /* Get preferred compression quality */ | ||
| 220 | #define VIDIOCPWCGCQUAL _IOR('v', 195, int) | ||
| 221 | |||
| 222 | |||
| 223 | /* Retrieve serial number of camera */ | ||
| 224 | #define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) | ||
| 225 | |||
| 226 | /* This is a probe function; since so many devices are supported, it | ||
| 227 | becomes difficult to include all the names in programs that want to | ||
| 228 | check for the enhanced Philips stuff. So in stead, try this PROBE; | ||
| 229 | it returns a structure with the original name, and the corresponding | ||
| 230 | Philips type. | ||
| 231 | To use, fill the structure with zeroes, call PROBE and if that succeeds, | ||
| 232 | compare the name with that returned from VIDIOCGCAP; they should be the | ||
| 233 | same. If so, you can be assured it is a Philips (OEM) cam and the type | ||
| 234 | is valid. | ||
| 235 | */ | ||
| 236 | #define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) | ||
| 237 | |||
| 238 | /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ | ||
| 239 | #define VIDIOCPWCSAGC _IOW('v', 200, int) | ||
| 240 | /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ | ||
| 241 | #define VIDIOCPWCGAGC _IOR('v', 200, int) | ||
| 242 | /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ | ||
| 243 | #define VIDIOCPWCSSHUTTER _IOW('v', 201, int) | ||
| 244 | |||
| 245 | /* Color compensation (Auto White Balance) */ | ||
| 246 | #define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) | ||
| 247 | #define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) | ||
| 248 | |||
| 249 | /* Auto WB speed */ | ||
| 250 | #define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) | ||
| 251 | #define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) | ||
| 252 | |||
| 253 | /* LEDs on/off/blink; int range 0..65535 */ | ||
| 254 | #define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) | ||
| 255 | #define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) | ||
| 256 | |||
| 257 | /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ | ||
| 258 | #define VIDIOCPWCSCONTOUR _IOW('v', 206, int) | ||
| 259 | #define VIDIOCPWCGCONTOUR _IOR('v', 206, int) | ||
| 260 | |||
| 261 | /* Backlight compensation; 0 = off, otherwise on */ | ||
| 262 | #define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) | ||
| 263 | #define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) | ||
| 264 | |||
| 265 | /* Flickerless mode; = 0 off, otherwise on */ | ||
| 266 | #define VIDIOCPWCSFLICKER _IOW('v', 208, int) | ||
| 267 | #define VIDIOCPWCGFLICKER _IOR('v', 208, int) | ||
| 268 | |||
| 269 | /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ | ||
| 270 | #define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) | ||
| 271 | #define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) | ||
| 272 | |||
| 273 | /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ | ||
| 274 | #define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) | ||
| 275 | |||
| 276 | /* Motorized pan & tilt functions */ | ||
| 277 | #define VIDIOCPWCMPTRESET _IOW('v', 211, int) | ||
| 278 | #define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) | ||
| 279 | #define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) | ||
| 280 | #define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) | ||
| 281 | #define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) | ||
| 282 | |||
| 283 | /* Get the USB set-video command; needed for initializing libpwcx */ | ||
| 284 | #define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) | ||
| 285 | struct pwc_table_init_buffer { | ||
| 286 | int len; | ||
| 287 | char *buffer; | ||
| 288 | |||
| 289 | }; | ||
| 290 | #define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) | ||
| 291 | |||
| 292 | #endif | ||
diff --git a/drivers/usb/media/pwc/pwc-kiara.c b/drivers/usb/media/pwc/pwc-kiara.c deleted file mode 100644 index c498c68bace1..000000000000 --- a/drivers/usb/media/pwc/pwc-kiara.c +++ /dev/null | |||
| @@ -1,318 +0,0 @@ | |||
| 1 | /* Linux driver for Philips webcam | ||
| 2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 3 | |||
| 4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 5 | driver and thus may have bugs that are not present in the original version. | ||
| 6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 7 | The decompression routines have been implemented by reverse-engineering the | ||
| 8 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 9 | |||
| 10 | This program is free software; you can redistribute it and/or modify | ||
| 11 | it under the terms of the GNU General Public License as published by | ||
| 12 | the Free Software Foundation; either version 2 of the License, or | ||
| 13 | (at your option) any later version. | ||
| 14 | |||
| 15 | This program is distributed in the hope that it will be useful, | ||
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | GNU General Public License for more details. | ||
| 19 | |||
| 20 | You should have received a copy of the GNU General Public License | ||
| 21 | along with this program; if not, write to the Free Software | ||
| 22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 23 | */ | ||
| 24 | |||
| 25 | |||
| 26 | /* This tables contains entries for the 730/740/750 (Kiara) camera, with | ||
| 27 | 4 different qualities (no compression, low, medium, high). | ||
| 28 | It lists the bandwidth requirements for said mode by its alternate interface | ||
| 29 | number. An alternate of 0 means that the mode is unavailable. | ||
| 30 | |||
| 31 | There are 6 * 4 * 4 entries: | ||
| 32 | 6 different resolutions subqcif, qsif, qcif, sif, cif, vga | ||
| 33 | 6 framerates: 5, 10, 15, 20, 25, 30 | ||
| 34 | 4 compression modi: none, low, medium, high | ||
| 35 | |||
| 36 | When an uncompressed mode is not available, the next available compressed mode | ||
| 37 | will be chosen (unless the decompressor is absent). Sometimes there are only | ||
| 38 | 1 or 2 compressed modes available; in that case entries are duplicated. | ||
| 39 | */ | ||
| 40 | |||
| 41 | |||
| 42 | #include "pwc-kiara.h" | ||
| 43 | #include "pwc-uncompress.h" | ||
| 44 | |||
| 45 | const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = | ||
| 46 | { | ||
| 47 | /* SQCIF */ | ||
| 48 | { | ||
| 49 | /* 5 fps */ | ||
| 50 | { | ||
| 51 | {0, }, | ||
| 52 | {0, }, | ||
| 53 | {0, }, | ||
| 54 | {0, }, | ||
| 55 | }, | ||
| 56 | /* 10 fps */ | ||
| 57 | { | ||
| 58 | {0, }, | ||
| 59 | {0, }, | ||
| 60 | {0, }, | ||
| 61 | {0, }, | ||
| 62 | }, | ||
| 63 | /* 15 fps */ | ||
| 64 | { | ||
| 65 | {0, }, | ||
| 66 | {0, }, | ||
| 67 | {0, }, | ||
| 68 | {0, }, | ||
| 69 | }, | ||
| 70 | /* 20 fps */ | ||
| 71 | { | ||
| 72 | {0, }, | ||
| 73 | {0, }, | ||
| 74 | {0, }, | ||
| 75 | {0, }, | ||
| 76 | }, | ||
| 77 | /* 25 fps */ | ||
| 78 | { | ||
| 79 | {0, }, | ||
| 80 | {0, }, | ||
| 81 | {0, }, | ||
| 82 | {0, }, | ||
| 83 | }, | ||
| 84 | /* 30 fps */ | ||
| 85 | { | ||
| 86 | {0, }, | ||
| 87 | {0, }, | ||
| 88 | {0, }, | ||
| 89 | {0, }, | ||
| 90 | }, | ||
| 91 | }, | ||
| 92 | /* QSIF */ | ||
| 93 | { | ||
| 94 | /* 5 fps */ | ||
| 95 | { | ||
| 96 | {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, | ||
| 97 | {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, | ||
| 98 | {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, | ||
| 99 | {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, | ||
| 100 | }, | ||
| 101 | /* 10 fps */ | ||
| 102 | { | ||
| 103 | {2, 291, 0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}}, | ||
| 104 | {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, | ||
| 105 | {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, | ||
| 106 | {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, | ||
| 107 | }, | ||
| 108 | /* 15 fps */ | ||
| 109 | { | ||
| 110 | {3, 437, 0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}}, | ||
| 111 | {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, | ||
| 112 | {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, | ||
| 113 | {1, 192, 420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, | ||
| 114 | }, | ||
| 115 | /* 20 fps */ | ||
| 116 | { | ||
| 117 | {4, 589, 0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}}, | ||
| 118 | {3, 448, 730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}}, | ||
| 119 | {2, 292, 476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}}, | ||
| 120 | {1, 192, 312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, | ||
| 121 | }, | ||
| 122 | /* 25 fps */ | ||
| 123 | { | ||
| 124 | {5, 703, 0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}}, | ||
| 125 | {3, 447, 610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}}, | ||
| 126 | {2, 292, 398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}}, | ||
| 127 | {1, 193, 262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}}, | ||
| 128 | }, | ||
| 129 | /* 30 fps */ | ||
| 130 | { | ||
| 131 | {8, 874, 0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}}, | ||
| 132 | {5, 704, 730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}}, | ||
| 133 | {3, 448, 492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}}, | ||
| 134 | {2, 292, 320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}}, | ||
| 135 | }, | ||
| 136 | }, | ||
| 137 | /* QCIF */ | ||
| 138 | { | ||
| 139 | /* 5 fps */ | ||
| 140 | { | ||
| 141 | {0, }, | ||
| 142 | {0, }, | ||
| 143 | {0, }, | ||
| 144 | {0, }, | ||
| 145 | }, | ||
| 146 | /* 10 fps */ | ||
| 147 | { | ||
| 148 | {0, }, | ||
| 149 | {0, }, | ||
| 150 | {0, }, | ||
| 151 | {0, }, | ||
| 152 | }, | ||
| 153 | /* 15 fps */ | ||
| 154 | { | ||
| 155 | {0, }, | ||
| 156 | {0, }, | ||
| 157 | {0, }, | ||
| 158 | {0, }, | ||
| 159 | }, | ||
| 160 | /* 20 fps */ | ||
| 161 | { | ||
| 162 | {0, }, | ||
| 163 | {0, }, | ||
| 164 | {0, }, | ||
| 165 | {0, }, | ||
| 166 | }, | ||
| 167 | /* 25 fps */ | ||
| 168 | { | ||
| 169 | {0, }, | ||
| 170 | {0, }, | ||
| 171 | {0, }, | ||
| 172 | {0, }, | ||
| 173 | }, | ||
| 174 | /* 30 fps */ | ||
| 175 | { | ||
| 176 | {0, }, | ||
| 177 | {0, }, | ||
| 178 | {0, }, | ||
| 179 | {0, }, | ||
| 180 | }, | ||
| 181 | }, | ||
| 182 | /* SIF */ | ||
| 183 | { | ||
| 184 | /* 5 fps */ | ||
| 185 | { | ||
| 186 | {4, 582, 0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}}, | ||
| 187 | {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}}, | ||
| 188 | {2, 291, 960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}}, | ||
| 189 | {1, 191, 630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}}, | ||
| 190 | }, | ||
| 191 | /* 10 fps */ | ||
| 192 | { | ||
| 193 | {0, }, | ||
| 194 | {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}}, | ||
| 195 | {3, 447, 736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}}, | ||
| 196 | {2, 292, 480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}}, | ||
| 197 | }, | ||
| 198 | /* 15 fps */ | ||
| 199 | { | ||
| 200 | {0, }, | ||
| 201 | {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}}, | ||
| 202 | {4, 592, 650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}}, | ||
| 203 | {3, 448, 492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}}, | ||
| 204 | }, | ||
| 205 | /* 20 fps */ | ||
| 206 | { | ||
| 207 | {0, }, | ||
| 208 | {9, 958, 782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}}, | ||
| 209 | {5, 703, 574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}}, | ||
| 210 | {3, 446, 364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}}, | ||
| 211 | }, | ||
| 212 | /* 25 fps */ | ||
| 213 | { | ||
| 214 | {0, }, | ||
| 215 | {9, 958, 654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}}, | ||
| 216 | {6, 776, 530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}}, | ||
| 217 | {4, 592, 404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}}, | ||
| 218 | }, | ||
| 219 | /* 30 fps */ | ||
| 220 | { | ||
| 221 | {0, }, | ||
| 222 | {9, 957, 526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}}, | ||
| 223 | {6, 775, 426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}}, | ||
| 224 | {4, 590, 324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}}, | ||
| 225 | }, | ||
| 226 | }, | ||
| 227 | /* CIF */ | ||
| 228 | { | ||
| 229 | /* 5 fps */ | ||
| 230 | { | ||
| 231 | {0, }, | ||
| 232 | {0, }, | ||
| 233 | {0, }, | ||
| 234 | {0, }, | ||
| 235 | }, | ||
| 236 | /* 10 fps */ | ||
| 237 | { | ||
| 238 | {0, }, | ||
| 239 | {0, }, | ||
| 240 | {0, }, | ||
| 241 | {0, }, | ||
| 242 | }, | ||
| 243 | /* 15 fps */ | ||
| 244 | { | ||
| 245 | {0, }, | ||
| 246 | {0, }, | ||
| 247 | {0, }, | ||
| 248 | {0, }, | ||
| 249 | }, | ||
| 250 | /* 20 fps */ | ||
| 251 | { | ||
| 252 | {0, }, | ||
| 253 | {0, }, | ||
| 254 | {0, }, | ||
| 255 | {0, }, | ||
| 256 | }, | ||
| 257 | /* 25 fps */ | ||
| 258 | { | ||
| 259 | {0, }, | ||
| 260 | {0, }, | ||
| 261 | {0, }, | ||
| 262 | {0, }, | ||
| 263 | }, | ||
| 264 | /* 30 fps */ | ||
| 265 | { | ||
| 266 | {0, }, | ||
| 267 | {0, }, | ||
| 268 | {0, }, | ||
| 269 | {0, }, | ||
| 270 | }, | ||
| 271 | }, | ||
| 272 | /* VGA */ | ||
| 273 | { | ||
| 274 | /* 5 fps */ | ||
| 275 | { | ||
| 276 | {0, }, | ||
| 277 | {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}, | ||
| 278 | {4, 592, 976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}}, | ||
| 279 | {3, 448, 738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}}, | ||
| 280 | }, | ||
| 281 | /* 10 fps */ | ||
| 282 | { | ||
| 283 | {0, }, | ||
| 284 | {9, 956, 788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}}, | ||
| 285 | {6, 776, 640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}}, | ||
| 286 | {4, 592, 488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}}, | ||
| 287 | }, | ||
| 288 | /* 15 fps */ | ||
| 289 | { | ||
| 290 | {0, }, | ||
| 291 | {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, | ||
| 292 | {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, | ||
| 293 | {8, 895, 492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}}, | ||
| 294 | }, | ||
| 295 | /* 20 fps */ | ||
| 296 | { | ||
| 297 | {0, }, | ||
| 298 | {0, }, | ||
| 299 | {0, }, | ||
| 300 | {0, }, | ||
| 301 | }, | ||
| 302 | /* 25 fps */ | ||
| 303 | { | ||
| 304 | {0, }, | ||
| 305 | {0, }, | ||
| 306 | {0, }, | ||
| 307 | {0, }, | ||
| 308 | }, | ||
| 309 | /* 30 fps */ | ||
| 310 | { | ||
| 311 | {0, }, | ||
| 312 | {0, }, | ||
| 313 | {0, }, | ||
| 314 | {0, }, | ||
| 315 | }, | ||
| 316 | }, | ||
| 317 | }; | ||
| 318 | |||
diff --git a/drivers/usb/media/pwc/pwc-kiara.h b/drivers/usb/media/pwc/pwc-kiara.h deleted file mode 100644 index 12929abbb1f0..000000000000 --- a/drivers/usb/media/pwc/pwc-kiara.h +++ /dev/null | |||
| @@ -1,45 +0,0 @@ | |||
| 1 | /* Linux driver for Philips webcam | ||
| 2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 3 | |||
| 4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 5 | driver and thus may have bugs that are not present in the original version. | ||
| 6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 7 | The decompression routines have been implemented by reverse-engineering the | ||
| 8 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 9 | |||
| 10 | This program is free software; you can redistribute it and/or modify | ||
| 11 | it under the terms of the GNU General Public License as published by | ||
| 12 | the Free Software Foundation; either version 2 of the License, or | ||
| 13 | (at your option) any later version. | ||
| 14 | |||
| 15 | This program is distributed in the hope that it will be useful, | ||
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | GNU General Public License for more details. | ||
| 19 | |||
| 20 | You should have received a copy of the GNU General Public License | ||
| 21 | along with this program; if not, write to the Free Software | ||
| 22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* Entries for the Kiara (730/740/750) camera */ | ||
| 26 | |||
| 27 | #ifndef PWC_KIARA_H | ||
| 28 | #define PWC_KIARA_H | ||
| 29 | |||
| 30 | #include "pwc-ioctl.h" | ||
| 31 | |||
| 32 | struct Kiara_table_entry | ||
| 33 | { | ||
| 34 | char alternate; /* USB alternate interface */ | ||
| 35 | unsigned short packetsize; /* Normal packet size */ | ||
| 36 | unsigned short bandlength; /* Bandlength when decompressing */ | ||
| 37 | unsigned char mode[12]; /* precomputed mode settings for cam */ | ||
| 38 | }; | ||
| 39 | |||
| 40 | const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4]; | ||
| 41 | const extern unsigned int KiaraRomTable[8][2][16][8]; | ||
| 42 | |||
| 43 | #endif | ||
| 44 | |||
| 45 | |||
diff --git a/drivers/usb/media/pwc/pwc-misc.c b/drivers/usb/media/pwc/pwc-misc.c deleted file mode 100644 index b7a4bd3524c7..000000000000 --- a/drivers/usb/media/pwc/pwc-misc.c +++ /dev/null | |||
| @@ -1,140 +0,0 @@ | |||
| 1 | /* Linux driver for Philips webcam | ||
| 2 | Various miscellaneous functions and tables. | ||
| 3 | (C) 1999-2003 Nemosoft Unv. | ||
| 4 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 5 | |||
| 6 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 7 | driver and thus may have bugs that are not present in the original version. | ||
| 8 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 9 | The decompression routines have been implemented by reverse-engineering the | ||
| 10 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 11 | |||
| 12 | This program is free software; you can redistribute it and/or modify | ||
| 13 | it under the terms of the GNU General Public License as published by | ||
| 14 | the Free Software Foundation; either version 2 of the License, or | ||
| 15 | (at your option) any later version. | ||
| 16 | |||
| 17 | This program is distributed in the hope that it will be useful, | ||
| 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | GNU General Public License for more details. | ||
| 21 | |||
| 22 | You should have received a copy of the GNU General Public License | ||
| 23 | along with this program; if not, write to the Free Software | ||
| 24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/slab.h> | ||
| 28 | |||
| 29 | #include "pwc.h" | ||
| 30 | |||
| 31 | struct pwc_coord pwc_image_sizes[PSZ_MAX] = | ||
| 32 | { | ||
| 33 | { 128, 96, 0 }, | ||
| 34 | { 160, 120, 0 }, | ||
| 35 | { 176, 144, 0 }, | ||
| 36 | { 320, 240, 0 }, | ||
| 37 | { 352, 288, 0 }, | ||
| 38 | { 640, 480, 0 }, | ||
| 39 | }; | ||
| 40 | |||
| 41 | /* x,y -> PSZ_ */ | ||
| 42 | int pwc_decode_size(struct pwc_device *pdev, int width, int height) | ||
| 43 | { | ||
| 44 | int i, find; | ||
| 45 | |||
| 46 | /* Make sure we don't go beyond our max size. | ||
| 47 | NB: we have different limits for RAW and normal modes. In case | ||
| 48 | you don't have the decompressor loaded or use RAW mode, | ||
| 49 | the maximum viewable size is smaller. | ||
| 50 | */ | ||
| 51 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
| 52 | { | ||
| 53 | if (width > pdev->abs_max.x || height > pdev->abs_max.y) | ||
| 54 | { | ||
| 55 | Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); | ||
| 56 | return -1; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | else | ||
| 60 | { | ||
| 61 | if (width > pdev->view_max.x || height > pdev->view_max.y) | ||
| 62 | { | ||
| 63 | Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n"); | ||
| 64 | return -1; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | /* Find the largest size supported by the camera that fits into the | ||
| 69 | requested size. | ||
| 70 | */ | ||
| 71 | find = -1; | ||
| 72 | for (i = 0; i < PSZ_MAX; i++) { | ||
| 73 | if (pdev->image_mask & (1 << i)) { | ||
| 74 | if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) | ||
| 75 | find = i; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | return find; | ||
| 79 | } | ||
| 80 | |||
| 81 | /* initialize variables depending on type and decompressor*/ | ||
| 82 | void pwc_construct(struct pwc_device *pdev) | ||
| 83 | { | ||
| 84 | switch(pdev->type) { | ||
| 85 | case 645: | ||
| 86 | case 646: | ||
| 87 | pdev->view_min.x = 128; | ||
| 88 | pdev->view_min.y = 96; | ||
| 89 | pdev->view_max.x = 352; | ||
| 90 | pdev->view_max.y = 288; | ||
| 91 | pdev->abs_max.x = 352; | ||
| 92 | pdev->abs_max.y = 288; | ||
| 93 | pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; | ||
| 94 | pdev->vcinterface = 2; | ||
| 95 | pdev->vendpoint = 4; | ||
| 96 | pdev->frame_header_size = 0; | ||
| 97 | pdev->frame_trailer_size = 0; | ||
| 98 | break; | ||
| 99 | case 675: | ||
| 100 | case 680: | ||
| 101 | case 690: | ||
| 102 | pdev->view_min.x = 128; | ||
| 103 | pdev->view_min.y = 96; | ||
| 104 | /* Anthill bug #38: PWC always reports max size, even without PWCX */ | ||
| 105 | pdev->view_max.x = 640; | ||
| 106 | pdev->view_max.y = 480; | ||
| 107 | pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; | ||
| 108 | pdev->abs_max.x = 640; | ||
| 109 | pdev->abs_max.y = 480; | ||
| 110 | pdev->vcinterface = 3; | ||
| 111 | pdev->vendpoint = 4; | ||
| 112 | pdev->frame_header_size = 0; | ||
| 113 | pdev->frame_trailer_size = 0; | ||
| 114 | break; | ||
| 115 | case 720: | ||
| 116 | case 730: | ||
| 117 | case 740: | ||
| 118 | case 750: | ||
| 119 | pdev->view_min.x = 160; | ||
| 120 | pdev->view_min.y = 120; | ||
| 121 | pdev->view_max.x = 640; | ||
| 122 | pdev->view_max.y = 480; | ||
| 123 | pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; | ||
| 124 | pdev->abs_max.x = 640; | ||
| 125 | pdev->abs_max.y = 480; | ||
| 126 | pdev->vcinterface = 3; | ||
| 127 | pdev->vendpoint = 5; | ||
| 128 | pdev->frame_header_size = TOUCAM_HEADER_SIZE; | ||
| 129 | pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; | ||
| 130 | break; | ||
| 131 | } | ||
| 132 | Debug("type = %d\n",pdev->type); | ||
| 133 | pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */ | ||
| 134 | pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; | ||
| 135 | pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; | ||
| 136 | /* length of image, in YUV format; always allocate enough memory. */ | ||
| 137 | pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2; | ||
| 138 | } | ||
| 139 | |||
| 140 | |||
diff --git a/drivers/usb/media/pwc/pwc-nala.h b/drivers/usb/media/pwc/pwc-nala.h deleted file mode 100644 index e6c5cb69d03b..000000000000 --- a/drivers/usb/media/pwc/pwc-nala.h +++ /dev/null | |||
| @@ -1,66 +0,0 @@ | |||
| 1 | /* SQCIF */ | ||
| 2 | { | ||
| 3 | {0, 0, {0x04, 0x01, 0x03}}, | ||
| 4 | {8, 0, {0x05, 0x01, 0x03}}, | ||
| 5 | {7, 0, {0x08, 0x01, 0x03}}, | ||
| 6 | {7, 0, {0x0A, 0x01, 0x03}}, | ||
| 7 | {6, 0, {0x0C, 0x01, 0x03}}, | ||
| 8 | {5, 0, {0x0F, 0x01, 0x03}}, | ||
| 9 | {4, 0, {0x14, 0x01, 0x03}}, | ||
| 10 | {3, 0, {0x18, 0x01, 0x03}}, | ||
| 11 | }, | ||
| 12 | /* QSIF */ | ||
| 13 | { | ||
| 14 | {0}, | ||
| 15 | {0}, | ||
| 16 | {0}, | ||
| 17 | {0}, | ||
| 18 | {0}, | ||
| 19 | {0}, | ||
| 20 | {0}, | ||
| 21 | {0}, | ||
| 22 | }, | ||
| 23 | /* QCIF */ | ||
| 24 | { | ||
| 25 | {0, 0, {0x04, 0x01, 0x02}}, | ||
| 26 | {8, 0, {0x05, 0x01, 0x02}}, | ||
| 27 | {7, 0, {0x08, 0x01, 0x02}}, | ||
| 28 | {6, 0, {0x0A, 0x01, 0x02}}, | ||
| 29 | {5, 0, {0x0C, 0x01, 0x02}}, | ||
| 30 | {4, 0, {0x0F, 0x01, 0x02}}, | ||
| 31 | {1, 0, {0x14, 0x01, 0x02}}, | ||
| 32 | {1, 0, {0x18, 0x01, 0x02}}, | ||
| 33 | }, | ||
| 34 | /* SIF */ | ||
| 35 | { | ||
| 36 | {0}, | ||
| 37 | {0}, | ||
| 38 | {0}, | ||
| 39 | {0}, | ||
| 40 | {0}, | ||
| 41 | {0}, | ||
| 42 | {0}, | ||
| 43 | {0}, | ||
| 44 | }, | ||
| 45 | /* CIF */ | ||
| 46 | { | ||
| 47 | {4, 0, {0x04, 0x01, 0x01}}, | ||
| 48 | {7, 1, {0x05, 0x03, 0x01}}, | ||
| 49 | {6, 1, {0x08, 0x03, 0x01}}, | ||
| 50 | {4, 1, {0x0A, 0x03, 0x01}}, | ||
| 51 | {3, 1, {0x0C, 0x03, 0x01}}, | ||
| 52 | {2, 1, {0x0F, 0x03, 0x01}}, | ||
| 53 | {0}, | ||
| 54 | {0}, | ||
| 55 | }, | ||
| 56 | /* VGA */ | ||
| 57 | { | ||
| 58 | {0}, | ||
| 59 | {0}, | ||
| 60 | {0}, | ||
| 61 | {0}, | ||
| 62 | {0}, | ||
| 63 | {0}, | ||
| 64 | {0}, | ||
| 65 | {0}, | ||
| 66 | }, | ||
diff --git a/drivers/usb/media/pwc/pwc-timon.c b/drivers/usb/media/pwc/pwc-timon.c deleted file mode 100644 index dee967173d6c..000000000000 --- a/drivers/usb/media/pwc/pwc-timon.c +++ /dev/null | |||
| @@ -1,316 +0,0 @@ | |||
| 1 | /* Linux driver for Philips webcam | ||
| 2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 3 | |||
| 4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 5 | driver and thus may have bugs that are not present in the original version. | ||
| 6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 7 | The decompression routines have been implemented by reverse-engineering the | ||
| 8 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 9 | |||
| 10 | This program is free software; you can redistribute it and/or modify | ||
| 11 | it under the terms of the GNU General Public License as published by | ||
| 12 | the Free Software Foundation; either version 2 of the License, or | ||
| 13 | (at your option) any later version. | ||
| 14 | |||
| 15 | This program is distributed in the hope that it will be useful, | ||
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | GNU General Public License for more details. | ||
| 19 | |||
| 20 | You should have received a copy of the GNU General Public License | ||
| 21 | along with this program; if not, write to the Free Software | ||
| 22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 23 | */ | ||
| 24 | |||
| 25 | |||
| 26 | /* This tables contains entries for the 675/680/690 (Timon) camera, with | ||
| 27 | 4 different qualities (no compression, low, medium, high). | ||
| 28 | It lists the bandwidth requirements for said mode by its alternate interface | ||
| 29 | number. An alternate of 0 means that the mode is unavailable. | ||
| 30 | |||
| 31 | There are 6 * 4 * 4 entries: | ||
| 32 | 6 different resolutions subqcif, qsif, qcif, sif, cif, vga | ||
| 33 | 6 framerates: 5, 10, 15, 20, 25, 30 | ||
| 34 | 4 compression modi: none, low, medium, high | ||
| 35 | |||
| 36 | When an uncompressed mode is not available, the next available compressed mode | ||
| 37 | will be chosen (unless the decompressor is absent). Sometimes there are only | ||
| 38 | 1 or 2 compressed modes available; in that case entries are duplicated. | ||
| 39 | */ | ||
| 40 | |||
| 41 | #include "pwc-timon.h" | ||
| 42 | |||
| 43 | const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = | ||
| 44 | { | ||
| 45 | /* SQCIF */ | ||
| 46 | { | ||
| 47 | /* 5 fps */ | ||
| 48 | { | ||
| 49 | {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, | ||
| 50 | {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, | ||
| 51 | {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, | ||
| 52 | {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, | ||
| 53 | }, | ||
| 54 | /* 10 fps */ | ||
| 55 | { | ||
| 56 | {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, | ||
| 57 | {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, | ||
| 58 | {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, | ||
| 59 | {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, | ||
| 60 | }, | ||
| 61 | /* 15 fps */ | ||
| 62 | { | ||
| 63 | {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, | ||
| 64 | {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, | ||
| 65 | {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, | ||
| 66 | {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, | ||
| 67 | }, | ||
| 68 | /* 20 fps */ | ||
| 69 | { | ||
| 70 | {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, | ||
| 71 | {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, | ||
| 72 | {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, | ||
| 73 | {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, | ||
| 74 | }, | ||
| 75 | /* 25 fps */ | ||
| 76 | { | ||
| 77 | {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, | ||
| 78 | {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, | ||
| 79 | {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, | ||
| 80 | {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, | ||
| 81 | }, | ||
| 82 | /* 30 fps */ | ||
| 83 | { | ||
| 84 | {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, | ||
| 85 | {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, | ||
| 86 | {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, | ||
| 87 | {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, | ||
| 88 | }, | ||
| 89 | }, | ||
| 90 | /* QSIF */ | ||
| 91 | { | ||
| 92 | /* 5 fps */ | ||
| 93 | { | ||
| 94 | {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, | ||
| 95 | {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, | ||
| 96 | {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, | ||
| 97 | {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, | ||
| 98 | }, | ||
| 99 | /* 10 fps */ | ||
| 100 | { | ||
| 101 | {2, 291, 0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}}, | ||
| 102 | {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, | ||
| 103 | {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, | ||
| 104 | {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, | ||
| 105 | }, | ||
| 106 | /* 15 fps */ | ||
| 107 | { | ||
| 108 | {3, 437, 0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}}, | ||
| 109 | {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, | ||
| 110 | {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, | ||
| 111 | {1, 191, 420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, | ||
| 112 | }, | ||
| 113 | /* 20 fps */ | ||
| 114 | { | ||
| 115 | {4, 588, 0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}}, | ||
| 116 | {3, 447, 730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, | ||
| 117 | {2, 292, 476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, | ||
| 118 | {1, 192, 312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, | ||
| 119 | }, | ||
| 120 | /* 25 fps */ | ||
| 121 | { | ||
| 122 | {5, 703, 0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}}, | ||
| 123 | {3, 447, 610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, | ||
| 124 | {2, 292, 398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, | ||
| 125 | {1, 192, 262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, | ||
| 126 | }, | ||
| 127 | /* 30 fps */ | ||
| 128 | { | ||
| 129 | {8, 873, 0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}}, | ||
| 130 | {5, 704, 774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}}, | ||
| 131 | {3, 448, 492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}}, | ||
| 132 | {2, 291, 320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, | ||
| 133 | }, | ||
| 134 | }, | ||
| 135 | /* QCIF */ | ||
| 136 | { | ||
| 137 | /* 5 fps */ | ||
| 138 | { | ||
| 139 | {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, | ||
| 140 | {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, | ||
| 141 | {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, | ||
| 142 | {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, | ||
| 143 | }, | ||
| 144 | /* 10 fps */ | ||
| 145 | { | ||
| 146 | {3, 385, 0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}}, | ||
| 147 | {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, | ||
| 148 | {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, | ||
| 149 | {1, 194, 532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}}, | ||
| 150 | }, | ||
| 151 | /* 15 fps */ | ||
| 152 | { | ||
| 153 | {4, 577, 0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}}, | ||
| 154 | {3, 447, 818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}}, | ||
| 155 | {2, 292, 534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}}, | ||
| 156 | {1, 195, 356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}}, | ||
| 157 | }, | ||
| 158 | /* 20 fps */ | ||
| 159 | { | ||
| 160 | {6, 776, 0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}}, | ||
| 161 | {4, 591, 804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}}, | ||
| 162 | {3, 447, 608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, | ||
| 163 | {2, 291, 396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, | ||
| 164 | }, | ||
| 165 | /* 25 fps */ | ||
| 166 | { | ||
| 167 | {9, 928, 0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}}, | ||
| 168 | {5, 703, 800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}}, | ||
| 169 | {3, 447, 508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, | ||
| 170 | {2, 292, 332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, | ||
| 171 | }, | ||
| 172 | /* 30 fps */ | ||
| 173 | { | ||
| 174 | {0, }, | ||
| 175 | {9, 956, 876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}}, | ||
| 176 | {4, 592, 542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}}, | ||
| 177 | {2, 291, 266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}}, | ||
| 178 | }, | ||
| 179 | }, | ||
| 180 | /* SIF */ | ||
| 181 | { | ||
| 182 | /* 5 fps */ | ||
| 183 | { | ||
| 184 | {4, 582, 0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}}, | ||
| 185 | {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}}, | ||
| 186 | {2, 291, 960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}}, | ||
| 187 | {1, 191, 630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}}, | ||
| 188 | }, | ||
| 189 | /* 10 fps */ | ||
| 190 | { | ||
| 191 | {0, }, | ||
| 192 | {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}}, | ||
| 193 | {3, 447, 736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}}, | ||
| 194 | {2, 291, 480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}}, | ||
| 195 | }, | ||
| 196 | /* 15 fps */ | ||
| 197 | { | ||
| 198 | {0, }, | ||
| 199 | {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}}, | ||
| 200 | {4, 591, 650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}}, | ||
| 201 | {3, 448, 492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}}, | ||
| 202 | }, | ||
| 203 | /* 20 fps */ | ||
| 204 | { | ||
| 205 | {0, }, | ||
| 206 | {9, 958, 782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}}, | ||
| 207 | {5, 703, 574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}}, | ||
| 208 | {3, 446, 364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}}, | ||
| 209 | }, | ||
| 210 | /* 25 fps */ | ||
| 211 | { | ||
| 212 | {0, }, | ||
| 213 | {9, 958, 654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}}, | ||
| 214 | {6, 776, 530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}}, | ||
| 215 | {4, 592, 404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}}, | ||
| 216 | }, | ||
| 217 | /* 30 fps */ | ||
| 218 | { | ||
| 219 | {0, }, | ||
| 220 | {9, 957, 526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}}, | ||
| 221 | {6, 775, 426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}}, | ||
| 222 | {4, 590, 324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}}, | ||
| 223 | }, | ||
| 224 | }, | ||
| 225 | /* CIF */ | ||
| 226 | { | ||
| 227 | /* 5 fps */ | ||
| 228 | { | ||
| 229 | {6, 771, 0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}}, | ||
| 230 | {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}}, | ||
| 231 | {2, 291, 800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}}, | ||
| 232 | {1, 193, 528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}}, | ||
| 233 | }, | ||
| 234 | /* 10 fps */ | ||
| 235 | { | ||
| 236 | {0, }, | ||
| 237 | {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}}, | ||
| 238 | {4, 591, 812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}}, | ||
| 239 | {2, 291, 400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}}, | ||
| 240 | }, | ||
| 241 | /* 15 fps */ | ||
| 242 | { | ||
| 243 | {0, }, | ||
| 244 | {9, 956, 876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}}, | ||
| 245 | {5, 703, 644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}}, | ||
| 246 | {3, 448, 410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}}, | ||
| 247 | }, | ||
| 248 | /* 20 fps */ | ||
| 249 | { | ||
| 250 | {0, }, | ||
| 251 | {9, 956, 650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}}, | ||
| 252 | {6, 776, 528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}}, | ||
| 253 | {4, 591, 402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}}, | ||
| 254 | }, | ||
| 255 | /* 25 fps */ | ||
| 256 | { | ||
| 257 | {0, }, | ||
| 258 | {9, 956, 544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}}, | ||
| 259 | {7, 840, 478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}}, | ||
| 260 | {5, 703, 400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}}, | ||
| 261 | }, | ||
| 262 | /* 30 fps */ | ||
| 263 | { | ||
| 264 | {0, }, | ||
| 265 | {9, 956, 438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}}, | ||
| 266 | {7, 838, 384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}}, | ||
| 267 | {6, 773, 354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}}, | ||
| 268 | }, | ||
| 269 | }, | ||
| 270 | /* VGA */ | ||
| 271 | { | ||
| 272 | /* 5 fps */ | ||
| 273 | { | ||
| 274 | {0, }, | ||
| 275 | {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}}, | ||
| 276 | {4, 592, 976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}}, | ||
| 277 | {3, 448, 738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}}, | ||
| 278 | }, | ||
| 279 | /* 10 fps */ | ||
| 280 | { | ||
| 281 | {0, }, | ||
| 282 | {9, 956, 788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}}, | ||
| 283 | {6, 776, 640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}}, | ||
| 284 | {4, 592, 488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}}, | ||
| 285 | }, | ||
| 286 | /* 15 fps */ | ||
| 287 | { | ||
| 288 | {0, }, | ||
| 289 | {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, | ||
| 290 | {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, | ||
| 291 | {8, 895, 492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}}, | ||
| 292 | }, | ||
| 293 | /* 20 fps */ | ||
| 294 | { | ||
| 295 | {0, }, | ||
| 296 | {0, }, | ||
| 297 | {0, }, | ||
| 298 | {0, }, | ||
| 299 | }, | ||
| 300 | /* 25 fps */ | ||
| 301 | { | ||
| 302 | {0, }, | ||
| 303 | {0, }, | ||
| 304 | {0, }, | ||
| 305 | {0, }, | ||
| 306 | }, | ||
| 307 | /* 30 fps */ | ||
| 308 | { | ||
| 309 | {0, }, | ||
| 310 | {0, }, | ||
| 311 | {0, }, | ||
| 312 | {0, }, | ||
| 313 | }, | ||
| 314 | }, | ||
| 315 | }; | ||
| 316 | |||
diff --git a/drivers/usb/media/pwc/pwc-timon.h b/drivers/usb/media/pwc/pwc-timon.h deleted file mode 100644 index a86b3782a081..000000000000 --- a/drivers/usb/media/pwc/pwc-timon.h +++ /dev/null | |||
| @@ -1,61 +0,0 @@ | |||
| 1 | /* Linux driver for Philips webcam | ||
| 2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 3 | |||
| 4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 5 | driver and thus may have bugs that are not present in the original version. | ||
| 6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 7 | The decompression routines have been implemented by reverse-engineering the | ||
| 8 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 9 | |||
| 10 | This program is free software; you can redistribute it and/or modify | ||
| 11 | it under the terms of the GNU General Public License as published by | ||
| 12 | the Free Software Foundation; either version 2 of the License, or | ||
| 13 | (at your option) any later version. | ||
| 14 | |||
| 15 | This program is distributed in the hope that it will be useful, | ||
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | GNU General Public License for more details. | ||
| 19 | |||
| 20 | You should have received a copy of the GNU General Public License | ||
| 21 | along with this program; if not, write to the Free Software | ||
| 22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 23 | */ | ||
| 24 | |||
| 25 | |||
| 26 | |||
| 27 | /* This tables contains entries for the 675/680/690 (Timon) camera, with | ||
| 28 | 4 different qualities (no compression, low, medium, high). | ||
| 29 | It lists the bandwidth requirements for said mode by its alternate interface | ||
| 30 | number. An alternate of 0 means that the mode is unavailable. | ||
| 31 | |||
| 32 | There are 6 * 4 * 4 entries: | ||
| 33 | 6 different resolutions subqcif, qsif, qcif, sif, cif, vga | ||
| 34 | 6 framerates: 5, 10, 15, 20, 25, 30 | ||
| 35 | 4 compression modi: none, low, medium, high | ||
| 36 | |||
| 37 | When an uncompressed mode is not available, the next available compressed mode | ||
| 38 | will be chosen (unless the decompressor is absent). Sometimes there are only | ||
| 39 | 1 or 2 compressed modes available; in that case entries are duplicated. | ||
| 40 | */ | ||
| 41 | |||
| 42 | #ifndef PWC_TIMON_H | ||
| 43 | #define PWC_TIMON_H | ||
| 44 | |||
| 45 | #include "pwc-ioctl.h" | ||
| 46 | |||
| 47 | struct Timon_table_entry | ||
| 48 | { | ||
| 49 | char alternate; /* USB alternate interface */ | ||
| 50 | unsigned short packetsize; /* Normal packet size */ | ||
| 51 | unsigned short bandlength; /* Bandlength when decompressing */ | ||
| 52 | unsigned char mode[13]; /* precomputed mode settings for cam */ | ||
| 53 | }; | ||
| 54 | |||
| 55 | const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4]; | ||
| 56 | const extern unsigned int TimonRomTable [16][2][16][8]; | ||
| 57 | |||
| 58 | |||
| 59 | #endif | ||
| 60 | |||
| 61 | |||
diff --git a/drivers/usb/media/pwc/pwc-uncompress.c b/drivers/usb/media/pwc/pwc-uncompress.c deleted file mode 100644 index ef4204eab6c4..000000000000 --- a/drivers/usb/media/pwc/pwc-uncompress.c +++ /dev/null | |||
| @@ -1,146 +0,0 @@ | |||
| 1 | /* Linux driver for Philips webcam | ||
| 2 | Decompression frontend. | ||
| 3 | (C) 1999-2003 Nemosoft Unv. | ||
| 4 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 5 | |||
| 6 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 7 | driver and thus may have bugs that are not present in the original version. | ||
| 8 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 9 | The decompression routines have been implemented by reverse-engineering the | ||
| 10 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 11 | |||
| 12 | This program is free software; you can redistribute it and/or modify | ||
| 13 | it under the terms of the GNU General Public License as published by | ||
| 14 | the Free Software Foundation; either version 2 of the License, or | ||
| 15 | (at your option) any later version. | ||
| 16 | |||
| 17 | This program is distributed in the hope that it will be useful, | ||
| 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | GNU General Public License for more details. | ||
| 21 | |||
| 22 | You should have received a copy of the GNU General Public License | ||
| 23 | along with this program; if not, write to the Free Software | ||
| 24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <asm/current.h> | ||
| 28 | #include <asm/types.h> | ||
| 29 | |||
| 30 | #include "pwc.h" | ||
| 31 | #include "pwc-uncompress.h" | ||
| 32 | |||
| 33 | int pwc_decompress(struct pwc_device *pdev) | ||
| 34 | { | ||
| 35 | struct pwc_frame_buf *fbuf; | ||
| 36 | int n, line, col, stride; | ||
| 37 | void *yuv, *image; | ||
| 38 | u16 *src; | ||
| 39 | u16 *dsty, *dstu, *dstv; | ||
| 40 | |||
| 41 | if (pdev == NULL) | ||
| 42 | return -EFAULT; | ||
| 43 | #if defined(__KERNEL__) && defined(PWC_MAGIC) | ||
| 44 | if (pdev->magic != PWC_MAGIC) { | ||
| 45 | Err("pwc_decompress(): magic failed.\n"); | ||
| 46 | return -EFAULT; | ||
| 47 | } | ||
| 48 | #endif | ||
| 49 | |||
| 50 | fbuf = pdev->read_frame; | ||
| 51 | if (fbuf == NULL) | ||
| 52 | return -EFAULT; | ||
| 53 | image = pdev->image_ptr[pdev->fill_image]; | ||
| 54 | if (!image) | ||
| 55 | return -EFAULT; | ||
| 56 | |||
| 57 | yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ | ||
| 58 | |||
| 59 | /* Raw format; that's easy... */ | ||
| 60 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
| 61 | { | ||
| 62 | memcpy(image, yuv, pdev->frame_size); | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | if (pdev->vbandlength == 0) { | ||
| 67 | /* Uncompressed mode. We copy the data into the output buffer, | ||
| 68 | using the viewport size (which may be larger than the image | ||
| 69 | size). Unfortunately we have to do a bit of byte stuffing | ||
| 70 | to get the desired output format/size. | ||
| 71 | */ | ||
| 72 | /* | ||
| 73 | * We do some byte shuffling here to go from the | ||
| 74 | * native format to YUV420P. | ||
| 75 | */ | ||
| 76 | src = (u16 *)yuv; | ||
| 77 | n = pdev->view.x * pdev->view.y; | ||
| 78 | |||
| 79 | /* offset in Y plane */ | ||
| 80 | stride = pdev->view.x * pdev->offset.y + pdev->offset.x; | ||
| 81 | dsty = (u16 *)(image + stride); | ||
| 82 | |||
| 83 | /* offsets in U/V planes */ | ||
| 84 | stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; | ||
| 85 | dstu = (u16 *)(image + n + stride); | ||
| 86 | dstv = (u16 *)(image + n + n / 4 + stride); | ||
| 87 | |||
| 88 | /* increment after each line */ | ||
| 89 | stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ | ||
| 90 | |||
| 91 | for (line = 0; line < pdev->image.y; line++) { | ||
| 92 | for (col = 0; col < pdev->image.x; col += 4) { | ||
| 93 | *dsty++ = *src++; | ||
| 94 | *dsty++ = *src++; | ||
| 95 | if (line & 1) | ||
| 96 | *dstv++ = *src++; | ||
| 97 | else | ||
| 98 | *dstu++ = *src++; | ||
| 99 | } | ||
| 100 | dsty += stride; | ||
| 101 | if (line & 1) | ||
| 102 | dstv += (stride >> 1); | ||
| 103 | else | ||
| 104 | dstu += (stride >> 1); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | else { | ||
| 108 | /* Compressed; the decompressor routines will write the data | ||
| 109 | in planar format immediately. | ||
| 110 | */ | ||
| 111 | int flags; | ||
| 112 | |||
| 113 | flags = PWCX_FLAG_PLANAR; | ||
| 114 | if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) | ||
| 115 | { | ||
| 116 | printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n"); | ||
| 117 | flags |= PWCX_FLAG_BAYER; | ||
| 118 | return -ENXIO; /* No such device or address: missing decompressor */ | ||
| 119 | } | ||
| 120 | |||
| 121 | #if 0 | ||
| 122 | switch (pdev->type) | ||
| 123 | { | ||
| 124 | case 675: | ||
| 125 | case 680: | ||
| 126 | case 690: | ||
| 127 | case 720: | ||
| 128 | case 730: | ||
| 129 | case 740: | ||
| 130 | case 750: | ||
| 131 | pwc_dec23_decompress(&pdev->image, &pdev->view, | ||
| 132 | &pdev->offset, yuv, image, flags, | ||
| 133 | pdev->decompress_data, pdev->vbandlength); | ||
| 134 | break; | ||
| 135 | case 645: | ||
| 136 | case 646: | ||
| 137 | /* TODO & FIXME */ | ||
| 138 | return -ENXIO; /* Missing decompressor */ | ||
| 139 | break; | ||
| 140 | } | ||
| 141 | #endif | ||
| 142 | } | ||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
diff --git a/drivers/usb/media/pwc/pwc-uncompress.h b/drivers/usb/media/pwc/pwc-uncompress.h deleted file mode 100644 index d3b9250e4ed3..000000000000 --- a/drivers/usb/media/pwc/pwc-uncompress.h +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | /* (C) 1999-2003 Nemosoft Unv. | ||
| 2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 3 | |||
| 4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 5 | driver and thus may have bugs that are not present in the original version. | ||
| 6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 7 | The decompression routines have been implemented by reverse-engineering the | ||
| 8 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 9 | |||
| 10 | This program is free software; you can redistribute it and/or modify | ||
| 11 | it under the terms of the GNU General Public License as published by | ||
| 12 | the Free Software Foundation; either version 2 of the License, or | ||
| 13 | (at your option) any later version. | ||
| 14 | |||
| 15 | This program is distributed in the hope that it will be useful, | ||
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | GNU General Public License for more details. | ||
| 19 | |||
| 20 | You should have received a copy of the GNU General Public License | ||
| 21 | along with this program; if not, write to the Free Software | ||
| 22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* This file is the bridge between the kernel module and the plugin; it | ||
| 26 | describes the structures and datatypes used in both modules. Any | ||
| 27 | significant change should be reflected by increasing the | ||
| 28 | pwc_decompressor_version major number. | ||
| 29 | */ | ||
| 30 | #ifndef PWC_UNCOMPRESS_H | ||
| 31 | #define PWC_UNCOMPRESS_H | ||
| 32 | |||
| 33 | #include <linux/config.h> | ||
| 34 | |||
| 35 | #include "pwc-ioctl.h" | ||
| 36 | |||
| 37 | /* from pwc-dec.h */ | ||
| 38 | #define PWCX_FLAG_PLANAR 0x0001 | ||
| 39 | /* */ | ||
| 40 | |||
| 41 | #endif | ||
diff --git a/drivers/usb/media/pwc/pwc.h b/drivers/usb/media/pwc/pwc.h deleted file mode 100644 index 6dd76bb3dff1..000000000000 --- a/drivers/usb/media/pwc/pwc.h +++ /dev/null | |||
| @@ -1,272 +0,0 @@ | |||
| 1 | /* (C) 1999-2003 Nemosoft Unv. | ||
| 2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
| 3 | |||
| 4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
| 5 | driver and thus may have bugs that are not present in the original version. | ||
| 6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
| 7 | The decompression routines have been implemented by reverse-engineering the | ||
| 8 | Nemosoft binary pwcx module. Caveat emptor. | ||
| 9 | |||
| 10 | This program is free software; you can redistribute it and/or modify | ||
| 11 | it under the terms of the GNU General Public License as published by | ||
| 12 | the Free Software Foundation; either version 2 of the License, or | ||
| 13 | (at your option) any later version. | ||
| 14 | |||
| 15 | This program is distributed in the hope that it will be useful, | ||
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | GNU General Public License for more details. | ||
| 19 | |||
| 20 | You should have received a copy of the GNU General Public License | ||
| 21 | along with this program; if not, write to the Free Software | ||
| 22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 23 | */ | ||
| 24 | |||
| 25 | #ifndef PWC_H | ||
| 26 | #define PWC_H | ||
| 27 | |||
| 28 | #include <linux/config.h> | ||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/usb.h> | ||
| 31 | #include <linux/spinlock.h> | ||
| 32 | #include <linux/videodev.h> | ||
| 33 | #include <linux/wait.h> | ||
| 34 | #include <linux/smp_lock.h> | ||
| 35 | #include <asm/semaphore.h> | ||
| 36 | #include <asm/errno.h> | ||
| 37 | |||
| 38 | #include "pwc-uncompress.h" | ||
| 39 | #include "pwc-ioctl.h" | ||
| 40 | |||
| 41 | /* Defines and structures for the Philips webcam */ | ||
| 42 | /* Used for checking memory corruption/pointer validation */ | ||
| 43 | #define PWC_MAGIC 0x89DC10ABUL | ||
| 44 | #undef PWC_MAGIC | ||
| 45 | |||
| 46 | /* Turn some debugging options on/off */ | ||
| 47 | #define PWC_DEBUG 0 | ||
| 48 | |||
| 49 | /* Trace certain actions in the driver */ | ||
| 50 | #define TRACE_MODULE 0x0001 | ||
| 51 | #define TRACE_PROBE 0x0002 | ||
| 52 | #define TRACE_OPEN 0x0004 | ||
| 53 | #define TRACE_READ 0x0008 | ||
| 54 | #define TRACE_MEMORY 0x0010 | ||
| 55 | #define TRACE_FLOW 0x0020 | ||
| 56 | #define TRACE_SIZE 0x0040 | ||
| 57 | #define TRACE_PWCX 0x0080 | ||
| 58 | #define TRACE_SEQUENCE 0x1000 | ||
| 59 | |||
| 60 | #define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A) | ||
| 61 | #define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A) | ||
| 62 | #define Info(A...) printk(KERN_INFO PWC_NAME " " A) | ||
| 63 | #define Err(A...) printk(KERN_ERR PWC_NAME " " A) | ||
| 64 | |||
| 65 | |||
| 66 | /* Defines for ToUCam cameras */ | ||
| 67 | #define TOUCAM_HEADER_SIZE 8 | ||
| 68 | #define TOUCAM_TRAILER_SIZE 4 | ||
| 69 | |||
| 70 | #define FEATURE_MOTOR_PANTILT 0x0001 | ||
| 71 | |||
| 72 | /* Version block */ | ||
| 73 | #define PWC_MAJOR 9 | ||
| 74 | #define PWC_MINOR 0 | ||
| 75 | #define PWC_VERSION "9.0.2-unofficial" | ||
| 76 | #define PWC_NAME "pwc" | ||
| 77 | |||
| 78 | /* Turn certain features on/off */ | ||
| 79 | #define PWC_INT_PIPE 0 | ||
| 80 | |||
| 81 | /* Ignore errors in the first N frames, to allow for startup delays */ | ||
| 82 | #define FRAME_LOWMARK 5 | ||
| 83 | |||
| 84 | /* Size and number of buffers for the ISO pipe. */ | ||
| 85 | #define MAX_ISO_BUFS 2 | ||
| 86 | #define ISO_FRAMES_PER_DESC 10 | ||
| 87 | #define ISO_MAX_FRAME_SIZE 960 | ||
| 88 | #define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) | ||
| 89 | |||
| 90 | /* Frame buffers: contains compressed or uncompressed video data. */ | ||
| 91 | #define MAX_FRAMES 5 | ||
| 92 | /* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ | ||
| 93 | #define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) | ||
| 94 | |||
| 95 | /* Absolute maximum number of buffers available for mmap() */ | ||
| 96 | #define MAX_IMAGES 10 | ||
| 97 | |||
| 98 | /* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ | ||
| 99 | struct pwc_iso_buf | ||
| 100 | { | ||
| 101 | void *data; | ||
| 102 | int length; | ||
| 103 | int read; | ||
| 104 | struct urb *urb; | ||
| 105 | }; | ||
| 106 | |||
| 107 | /* intermediate buffers with raw data from the USB cam */ | ||
| 108 | struct pwc_frame_buf | ||
| 109 | { | ||
| 110 | void *data; | ||
| 111 | volatile int filled; /* number of bytes filled */ | ||
| 112 | struct pwc_frame_buf *next; /* list */ | ||
| 113 | #if PWC_DEBUG | ||
| 114 | int sequence; /* Sequence number */ | ||
| 115 | #endif | ||
| 116 | }; | ||
| 117 | |||
| 118 | struct pwc_device | ||
| 119 | { | ||
| 120 | struct video_device *vdev; | ||
| 121 | #ifdef PWC_MAGIC | ||
| 122 | int magic; | ||
| 123 | #endif | ||
| 124 | /* Pointer to our usb_device */ | ||
| 125 | struct usb_device *udev; | ||
| 126 | |||
| 127 | int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ | ||
| 128 | int release; /* release number */ | ||
| 129 | int features; /* feature bits */ | ||
| 130 | char serial[30]; /* serial number (string) */ | ||
| 131 | int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ | ||
| 132 | int usb_init; /* set when the cam has been initialized over USB */ | ||
| 133 | |||
| 134 | /*** Video data ***/ | ||
| 135 | int vopen; /* flag */ | ||
| 136 | int vendpoint; /* video isoc endpoint */ | ||
| 137 | int vcinterface; /* video control interface */ | ||
| 138 | int valternate; /* alternate interface needed */ | ||
| 139 | int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ | ||
| 140 | int vpalette; /* palette: 420P, RAW or RGBBAYER */ | ||
| 141 | int vframe_count; /* received frames */ | ||
| 142 | int vframes_dumped; /* counter for dumped frames */ | ||
| 143 | int vframes_error; /* frames received in error */ | ||
| 144 | int vmax_packet_size; /* USB maxpacket size */ | ||
| 145 | int vlast_packet_size; /* for frame synchronisation */ | ||
| 146 | int visoc_errors; /* number of contiguous ISOC errors */ | ||
| 147 | int vcompression; /* desired compression factor */ | ||
| 148 | int vbandlength; /* compressed band length; 0 is uncompressed */ | ||
| 149 | char vsnapshot; /* snapshot mode */ | ||
| 150 | char vsync; /* used by isoc handler */ | ||
| 151 | char vmirror; /* for ToUCaM series */ | ||
| 152 | |||
| 153 | int cmd_len; | ||
| 154 | unsigned char cmd_buf[13]; | ||
| 155 | |||
| 156 | /* The image acquisition requires 3 to 4 steps: | ||
| 157 | 1. data is gathered in short packets from the USB controller | ||
| 158 | 2. data is synchronized and packed into a frame buffer | ||
| 159 | 3a. in case data is compressed, decompress it directly into image buffer | ||
| 160 | 3b. in case data is uncompressed, copy into image buffer with viewport | ||
| 161 | 4. data is transferred to the user process | ||
| 162 | |||
| 163 | Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... | ||
| 164 | We have in effect a back-to-back-double-buffer system. | ||
| 165 | */ | ||
| 166 | /* 1: isoc */ | ||
| 167 | struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; | ||
| 168 | char iso_init; | ||
| 169 | |||
| 170 | /* 2: frame */ | ||
| 171 | struct pwc_frame_buf *fbuf; /* all frames */ | ||
| 172 | struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ | ||
| 173 | struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ | ||
| 174 | struct pwc_frame_buf *fill_frame; /* frame currently being filled */ | ||
| 175 | struct pwc_frame_buf *read_frame; /* frame currently read by user process */ | ||
| 176 | int frame_header_size, frame_trailer_size; | ||
| 177 | int frame_size; | ||
| 178 | int frame_total_size; /* including header & trailer */ | ||
| 179 | int drop_frames; | ||
| 180 | #if PWC_DEBUG | ||
| 181 | int sequence; /* Debugging aid */ | ||
| 182 | #endif | ||
| 183 | |||
| 184 | /* 3: decompression */ | ||
| 185 | struct pwc_decompressor *decompressor; /* function block with decompression routines */ | ||
| 186 | void *decompress_data; /* private data for decompression engine */ | ||
| 187 | |||
| 188 | /* 4: image */ | ||
| 189 | /* We have an 'image' and a 'view', where 'image' is the fixed-size image | ||
| 190 | as delivered by the camera, and 'view' is the size requested by the | ||
| 191 | program. The camera image is centered in this viewport, laced with | ||
| 192 | a gray or black border. view_min <= image <= view <= view_max; | ||
| 193 | */ | ||
| 194 | int image_mask; /* bitmask of supported sizes */ | ||
| 195 | struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ | ||
| 196 | struct pwc_coord abs_max; /* maximum supported size with compression */ | ||
| 197 | struct pwc_coord image, view; /* image and viewport size */ | ||
| 198 | struct pwc_coord offset; /* offset within the viewport */ | ||
| 199 | |||
| 200 | void *image_data; /* total buffer, which is subdivided into ... */ | ||
| 201 | void *image_ptr[MAX_IMAGES]; /* ...several images... */ | ||
| 202 | int fill_image; /* ...which are rotated. */ | ||
| 203 | int len_per_image; /* length per image */ | ||
| 204 | int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ | ||
| 205 | int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ | ||
| 206 | |||
| 207 | struct semaphore modlock; /* to prevent races in video_open(), etc */ | ||
| 208 | spinlock_t ptrlock; /* for manipulating the buffer pointers */ | ||
| 209 | |||
| 210 | /*** motorized pan/tilt feature */ | ||
| 211 | struct pwc_mpt_range angle_range; | ||
| 212 | int pan_angle; /* in degrees * 100 */ | ||
| 213 | int tilt_angle; /* absolute angle; 0,0 is home position */ | ||
| 214 | |||
| 215 | /*** Misc. data ***/ | ||
| 216 | wait_queue_head_t frameq; /* When waiting for a frame to finish... */ | ||
| 217 | #if PWC_INT_PIPE | ||
| 218 | void *usb_int_handler; /* for the interrupt endpoint */ | ||
| 219 | #endif | ||
| 220 | }; | ||
| 221 | |||
| 222 | |||
| 223 | #ifdef __cplusplus | ||
| 224 | extern "C" { | ||
| 225 | #endif | ||
| 226 | |||
| 227 | /* Global variable */ | ||
| 228 | extern int pwc_trace; | ||
| 229 | |||
| 230 | /** functions in pwc-if.c */ | ||
| 231 | int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); | ||
| 232 | |||
| 233 | /** Functions in pwc-misc.c */ | ||
| 234 | /* sizes in pixels */ | ||
| 235 | extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; | ||
| 236 | |||
| 237 | int pwc_decode_size(struct pwc_device *pdev, int width, int height); | ||
| 238 | void pwc_construct(struct pwc_device *pdev); | ||
| 239 | |||
| 240 | /** Functions in pwc-ctrl.c */ | ||
| 241 | /* Request a certain video mode. Returns < 0 if not possible */ | ||
| 242 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); | ||
| 243 | |||
| 244 | /* Various controls; should be obvious. Value 0..65535, or < 0 on error */ | ||
| 245 | extern int pwc_get_brightness(struct pwc_device *pdev); | ||
| 246 | extern int pwc_set_brightness(struct pwc_device *pdev, int value); | ||
| 247 | extern int pwc_get_contrast(struct pwc_device *pdev); | ||
| 248 | extern int pwc_set_contrast(struct pwc_device *pdev, int value); | ||
| 249 | extern int pwc_get_gamma(struct pwc_device *pdev); | ||
| 250 | extern int pwc_set_gamma(struct pwc_device *pdev, int value); | ||
| 251 | extern int pwc_get_saturation(struct pwc_device *pdev); | ||
| 252 | extern int pwc_set_saturation(struct pwc_device *pdev, int value); | ||
| 253 | extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); | ||
| 254 | extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); | ||
| 255 | |||
| 256 | /* Power down or up the camera; not supported by all models */ | ||
| 257 | extern int pwc_camera_power(struct pwc_device *pdev, int power); | ||
| 258 | |||
| 259 | /* Private ioctl()s; see pwc-ioctl.h */ | ||
| 260 | extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); | ||
| 261 | |||
| 262 | |||
| 263 | /** pwc-uncompress.c */ | ||
| 264 | /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ | ||
| 265 | extern int pwc_decompress(struct pwc_device *pdev); | ||
| 266 | |||
| 267 | #ifdef __cplusplus | ||
| 268 | } | ||
| 269 | #endif | ||
| 270 | |||
| 271 | |||
| 272 | #endif | ||
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c deleted file mode 100644 index f03ea7f89596..000000000000 --- a/drivers/usb/media/se401.c +++ /dev/null | |||
| @@ -1,1435 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Endpoints (formerly known as AOX) se401 USB Camera Driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) | ||
| 5 | * | ||
| 6 | * Still somewhat based on the Linux ov511 driver. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, but | ||
| 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 16 | * for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software Foundation, | ||
| 20 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | * | ||
| 22 | * | ||
| 23 | * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on | ||
| 24 | * their chipset available and supporting me while writing this driver. | ||
| 25 | * - Jeroen Vreeken | ||
| 26 | */ | ||
| 27 | |||
| 28 | static const char version[] = "0.24"; | ||
| 29 | |||
| 30 | #include <linux/config.h> | ||
| 31 | #include <linux/module.h> | ||
| 32 | #include <linux/init.h> | ||
| 33 | #include <linux/vmalloc.h> | ||
| 34 | #include <linux/slab.h> | ||
| 35 | #include <linux/pagemap.h> | ||
| 36 | #include <linux/usb.h> | ||
| 37 | #include "se401.h" | ||
| 38 | |||
| 39 | static int flickerless=0; | ||
| 40 | static int video_nr = -1; | ||
| 41 | |||
| 42 | static struct usb_device_id device_table [] = { | ||
| 43 | { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */ | ||
| 44 | { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */ | ||
| 45 | { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */ | ||
| 46 | { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */ | ||
| 47 | { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */ | ||
| 48 | { } | ||
| 49 | }; | ||
| 50 | |||
| 51 | MODULE_DEVICE_TABLE(usb, device_table); | ||
| 52 | |||
| 53 | MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>"); | ||
| 54 | MODULE_DESCRIPTION("SE401 USB Camera Driver"); | ||
| 55 | MODULE_LICENSE("GPL"); | ||
| 56 | module_param(flickerless, int, 0); | ||
| 57 | MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)"); | ||
| 58 | module_param(video_nr, int, 0); | ||
| 59 | |||
| 60 | static struct usb_driver se401_driver; | ||
| 61 | |||
| 62 | |||
| 63 | /********************************************************************** | ||
| 64 | * | ||
| 65 | * Memory management | ||
| 66 | * | ||
| 67 | **********************************************************************/ | ||
| 68 | static void *rvmalloc(unsigned long size) | ||
| 69 | { | ||
| 70 | void *mem; | ||
| 71 | unsigned long adr; | ||
| 72 | |||
| 73 | size = PAGE_ALIGN(size); | ||
| 74 | mem = vmalloc_32(size); | ||
| 75 | if (!mem) | ||
| 76 | return NULL; | ||
| 77 | |||
| 78 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
| 79 | adr = (unsigned long) mem; | ||
| 80 | while (size > 0) { | ||
| 81 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
| 82 | adr += PAGE_SIZE; | ||
| 83 | size -= PAGE_SIZE; | ||
| 84 | } | ||
| 85 | |||
| 86 | return mem; | ||
| 87 | } | ||
| 88 | |||
| 89 | static void rvfree(void *mem, unsigned long size) | ||
| 90 | { | ||
| 91 | unsigned long adr; | ||
| 92 | |||
| 93 | if (!mem) | ||
| 94 | return; | ||
| 95 | |||
| 96 | adr = (unsigned long) mem; | ||
| 97 | while ((long) size > 0) { | ||
| 98 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
| 99 | adr += PAGE_SIZE; | ||
| 100 | size -= PAGE_SIZE; | ||
| 101 | } | ||
| 102 | vfree(mem); | ||
| 103 | } | ||
| 104 | |||
| 105 | |||
| 106 | |||
| 107 | /**************************************************************************** | ||
| 108 | * | ||
| 109 | * se401 register read/write functions | ||
| 110 | * | ||
| 111 | ***************************************************************************/ | ||
| 112 | |||
| 113 | static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req, | ||
| 114 | unsigned short value, unsigned char *cp, int size) | ||
| 115 | { | ||
| 116 | return usb_control_msg ( | ||
| 117 | se401->dev, | ||
| 118 | set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0), | ||
| 119 | req, | ||
| 120 | (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 121 | value, | ||
| 122 | 0, | ||
| 123 | cp, | ||
| 124 | size, | ||
| 125 | 1000 | ||
| 126 | ); | ||
| 127 | } | ||
| 128 | |||
| 129 | static int se401_set_feature(struct usb_se401 *se401, unsigned short selector, | ||
| 130 | unsigned short param) | ||
| 131 | { | ||
| 132 | /* specs say that the selector (address) should go in the value field | ||
| 133 | and the param in index, but in the logs of the windows driver they do | ||
| 134 | this the other way around... | ||
| 135 | */ | ||
| 136 | return usb_control_msg ( | ||
| 137 | se401->dev, | ||
| 138 | usb_sndctrlpipe(se401->dev, 0), | ||
| 139 | SE401_REQ_SET_EXT_FEATURE, | ||
| 140 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 141 | param, | ||
| 142 | selector, | ||
| 143 | NULL, | ||
| 144 | 0, | ||
| 145 | 1000 | ||
| 146 | ); | ||
| 147 | } | ||
| 148 | |||
| 149 | static unsigned short se401_get_feature(struct usb_se401 *se401, | ||
| 150 | unsigned short selector) | ||
| 151 | { | ||
| 152 | /* For 'set' the selecetor should be in index, not sure if the spec is | ||
| 153 | wrong here to.... | ||
| 154 | */ | ||
| 155 | unsigned char cp[2]; | ||
| 156 | usb_control_msg ( | ||
| 157 | se401->dev, | ||
| 158 | usb_rcvctrlpipe(se401->dev, 0), | ||
| 159 | SE401_REQ_GET_EXT_FEATURE, | ||
| 160 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 161 | 0, | ||
| 162 | selector, | ||
| 163 | cp, | ||
| 164 | 2, | ||
| 165 | 1000 | ||
| 166 | ); | ||
| 167 | return cp[0]+cp[1]*256; | ||
| 168 | } | ||
| 169 | |||
| 170 | /**************************************************************************** | ||
| 171 | * | ||
| 172 | * Camera control | ||
| 173 | * | ||
| 174 | ***************************************************************************/ | ||
| 175 | |||
| 176 | |||
| 177 | static int se401_send_pict(struct usb_se401 *se401) | ||
| 178 | { | ||
| 179 | se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */ | ||
| 180 | se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */ | ||
| 181 | se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */ | ||
| 182 | se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */ | ||
| 183 | se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */ | ||
| 184 | se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */ | ||
| 185 | se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */ | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | static void se401_set_exposure(struct usb_se401 *se401, int brightness) | ||
| 191 | { | ||
| 192 | int integration=brightness<<5; | ||
| 193 | |||
| 194 | if (flickerless==50) { | ||
| 195 | integration=integration-integration%106667; | ||
| 196 | } | ||
| 197 | if (flickerless==60) { | ||
| 198 | integration=integration-integration%88889; | ||
| 199 | } | ||
| 200 | se401->brightness=integration>>5; | ||
| 201 | se401->expose_h=(integration>>16)&0xff; | ||
| 202 | se401->expose_m=(integration>>8)&0xff; | ||
| 203 | se401->expose_l=integration&0xff; | ||
| 204 | } | ||
| 205 | |||
| 206 | static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p) | ||
| 207 | { | ||
| 208 | p->brightness=se401->brightness; | ||
| 209 | if (se401->enhance) { | ||
| 210 | p->whiteness=32768; | ||
| 211 | } else { | ||
| 212 | p->whiteness=0; | ||
| 213 | } | ||
| 214 | p->colour=65535; | ||
| 215 | p->contrast=65535; | ||
| 216 | p->hue=se401->rgain<<10; | ||
| 217 | p->palette=se401->palette; | ||
| 218 | p->depth=3; /* rgb24 */ | ||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | |||
| 223 | static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p) | ||
| 224 | { | ||
| 225 | if (p->palette != VIDEO_PALETTE_RGB24) | ||
| 226 | return 1; | ||
| 227 | se401->palette=p->palette; | ||
| 228 | if (p->hue!=se401->hue) { | ||
| 229 | se401->rgain= p->hue>>10; | ||
| 230 | se401->bgain= 0x40-(p->hue>>10); | ||
| 231 | se401->hue=p->hue; | ||
| 232 | } | ||
| 233 | if (p->brightness!=se401->brightness) { | ||
| 234 | se401_set_exposure(se401, p->brightness); | ||
| 235 | } | ||
| 236 | if (p->whiteness>=32768) { | ||
| 237 | se401->enhance=1; | ||
| 238 | } else { | ||
| 239 | se401->enhance=0; | ||
| 240 | } | ||
| 241 | se401_send_pict(se401); | ||
| 242 | se401_send_pict(se401); | ||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | /* | ||
| 247 | Hyundai have some really nice docs about this and other sensor related | ||
| 248 | stuff on their homepage: www.hei.co.kr | ||
| 249 | */ | ||
| 250 | static void se401_auto_resetlevel(struct usb_se401 *se401) | ||
| 251 | { | ||
| 252 | unsigned int ahrc, alrc; | ||
| 253 | int oldreset=se401->resetlevel; | ||
| 254 | |||
| 255 | /* For some reason this normally read-only register doesn't get reset | ||
| 256 | to zero after reading them just once... | ||
| 257 | */ | ||
| 258 | se401_get_feature(se401, HV7131_REG_HIREFNOH); | ||
| 259 | se401_get_feature(se401, HV7131_REG_HIREFNOL); | ||
| 260 | se401_get_feature(se401, HV7131_REG_LOREFNOH); | ||
| 261 | se401_get_feature(se401, HV7131_REG_LOREFNOL); | ||
| 262 | ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + | ||
| 263 | se401_get_feature(se401, HV7131_REG_HIREFNOL); | ||
| 264 | alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) + | ||
| 265 | se401_get_feature(se401, HV7131_REG_LOREFNOL); | ||
| 266 | |||
| 267 | /* Not an exact science, but it seems to work pretty well... */ | ||
| 268 | if (alrc > 10) { | ||
| 269 | while (alrc>=10 && se401->resetlevel < 63) { | ||
| 270 | se401->resetlevel++; | ||
| 271 | alrc /=2; | ||
| 272 | } | ||
| 273 | } else if (ahrc > 20) { | ||
| 274 | while (ahrc>=20 && se401->resetlevel > 0) { | ||
| 275 | se401->resetlevel--; | ||
| 276 | ahrc /=2; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | if (se401->resetlevel!=oldreset) | ||
| 280 | se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel); | ||
| 281 | |||
| 282 | return; | ||
| 283 | } | ||
| 284 | |||
| 285 | /* irq handler for snapshot button */ | ||
| 286 | static void se401_button_irq(struct urb *urb, struct pt_regs *regs) | ||
| 287 | { | ||
| 288 | struct usb_se401 *se401 = urb->context; | ||
| 289 | int status; | ||
| 290 | |||
| 291 | if (!se401->dev) { | ||
| 292 | info("ohoh: device vapourished"); | ||
| 293 | return; | ||
| 294 | } | ||
| 295 | |||
| 296 | switch (urb->status) { | ||
| 297 | case 0: | ||
| 298 | /* success */ | ||
| 299 | break; | ||
| 300 | case -ECONNRESET: | ||
| 301 | case -ENOENT: | ||
| 302 | case -ESHUTDOWN: | ||
| 303 | /* this urb is terminated, clean up */ | ||
| 304 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); | ||
| 305 | return; | ||
| 306 | default: | ||
| 307 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); | ||
| 308 | goto exit; | ||
| 309 | } | ||
| 310 | |||
| 311 | if (urb->actual_length >=2) { | ||
| 312 | if (se401->button) | ||
| 313 | se401->buttonpressed=1; | ||
| 314 | } | ||
| 315 | exit: | ||
| 316 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
| 317 | if (status) | ||
| 318 | err ("%s - usb_submit_urb failed with result %d", | ||
| 319 | __FUNCTION__, status); | ||
| 320 | } | ||
| 321 | |||
| 322 | static void se401_video_irq(struct urb *urb, struct pt_regs *regs) | ||
| 323 | { | ||
| 324 | struct usb_se401 *se401 = urb->context; | ||
| 325 | int length = urb->actual_length; | ||
| 326 | |||
| 327 | /* ohoh... */ | ||
| 328 | if (!se401->streaming) | ||
| 329 | return; | ||
| 330 | |||
| 331 | if (!se401->dev) { | ||
| 332 | info ("ohoh: device vapourished"); | ||
| 333 | return; | ||
| 334 | } | ||
| 335 | |||
| 336 | /* 0 sized packets happen if we are to fast, but sometimes the camera | ||
| 337 | keeps sending them forever... | ||
| 338 | */ | ||
| 339 | if (length && !urb->status) { | ||
| 340 | se401->nullpackets=0; | ||
| 341 | switch(se401->scratch[se401->scratch_next].state) { | ||
| 342 | case BUFFER_READY: | ||
| 343 | case BUFFER_BUSY: { | ||
| 344 | se401->dropped++; | ||
| 345 | break; | ||
| 346 | } | ||
| 347 | case BUFFER_UNUSED: { | ||
| 348 | memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length); | ||
| 349 | se401->scratch[se401->scratch_next].state=BUFFER_READY; | ||
| 350 | se401->scratch[se401->scratch_next].offset=se401->bayeroffset; | ||
| 351 | se401->scratch[se401->scratch_next].length=length; | ||
| 352 | if (waitqueue_active(&se401->wq)) { | ||
| 353 | wake_up_interruptible(&se401->wq); | ||
| 354 | } | ||
| 355 | se401->scratch_overflow=0; | ||
| 356 | se401->scratch_next++; | ||
| 357 | if (se401->scratch_next>=SE401_NUMSCRATCH) | ||
| 358 | se401->scratch_next=0; | ||
| 359 | break; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | se401->bayeroffset+=length; | ||
| 363 | if (se401->bayeroffset>=se401->cheight*se401->cwidth) { | ||
| 364 | se401->bayeroffset=0; | ||
| 365 | } | ||
| 366 | } else { | ||
| 367 | se401->nullpackets++; | ||
| 368 | if (se401->nullpackets > SE401_MAX_NULLPACKETS) { | ||
| 369 | if (waitqueue_active(&se401->wq)) { | ||
| 370 | wake_up_interruptible(&se401->wq); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | /* Resubmit urb for new data */ | ||
| 376 | urb->status=0; | ||
| 377 | urb->dev=se401->dev; | ||
| 378 | if(usb_submit_urb(urb, GFP_KERNEL)) | ||
| 379 | info("urb burned down"); | ||
| 380 | return; | ||
| 381 | } | ||
| 382 | |||
| 383 | static void se401_send_size(struct usb_se401 *se401, int width, int height) | ||
| 384 | { | ||
| 385 | int i=0; | ||
| 386 | int mode=0x03; /* No compression */ | ||
| 387 | int sendheight=height; | ||
| 388 | int sendwidth=width; | ||
| 389 | |||
| 390 | /* JangGu compression can only be used with the camera supported sizes, | ||
| 391 | but bayer seems to work with any size that fits on the sensor. | ||
| 392 | We check if we can use compression with the current size with either | ||
| 393 | 4 or 16 times subcapturing, if not we use uncompressed bayer data | ||
| 394 | but this will result in cutouts of the maximum size.... | ||
| 395 | */ | ||
| 396 | while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height)) | ||
| 397 | i++; | ||
| 398 | while (i<se401->sizes) { | ||
| 399 | if (se401->width[i]==width*2 && se401->height[i]==height*2) { | ||
| 400 | sendheight=se401->height[i]; | ||
| 401 | sendwidth=se401->width[i]; | ||
| 402 | mode=0x40; | ||
| 403 | } | ||
| 404 | if (se401->width[i]==width*4 && se401->height[i]==height*4) { | ||
| 405 | sendheight=se401->height[i]; | ||
| 406 | sendwidth=se401->width[i]; | ||
| 407 | mode=0x42; | ||
| 408 | } | ||
| 409 | i++; | ||
| 410 | } | ||
| 411 | |||
| 412 | se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0); | ||
| 413 | se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0); | ||
| 414 | se401_set_feature(se401, SE401_OPERATINGMODE, mode); | ||
| 415 | |||
| 416 | if (mode==0x03) { | ||
| 417 | se401->format=FMT_BAYER; | ||
| 418 | } else { | ||
| 419 | se401->format=FMT_JANGGU; | ||
| 420 | } | ||
| 421 | |||
| 422 | return; | ||
| 423 | } | ||
| 424 | |||
| 425 | /* | ||
| 426 | In this function se401_send_pict is called several times, | ||
| 427 | for some reason (depending on the state of the sensor and the phase of | ||
| 428 | the moon :) doing this only in either place doesn't always work... | ||
| 429 | */ | ||
| 430 | static int se401_start_stream(struct usb_se401 *se401) | ||
| 431 | { | ||
| 432 | struct urb *urb; | ||
| 433 | int err=0, i; | ||
| 434 | se401->streaming=1; | ||
| 435 | |||
| 436 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); | ||
| 437 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); | ||
| 438 | |||
| 439 | /* Set picture settings */ | ||
| 440 | se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */ | ||
| 441 | se401_send_pict(se401); | ||
| 442 | |||
| 443 | se401_send_size(se401, se401->cwidth, se401->cheight); | ||
| 444 | |||
| 445 | se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0); | ||
| 446 | |||
| 447 | /* Do some memory allocation */ | ||
| 448 | for (i=0; i<SE401_NUMFRAMES; i++) { | ||
| 449 | se401->frame[i].data=se401->fbuf + i * se401->maxframesize; | ||
| 450 | se401->frame[i].curpix=0; | ||
| 451 | } | ||
| 452 | for (i=0; i<SE401_NUMSBUF; i++) { | ||
| 453 | se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); | ||
| 454 | } | ||
| 455 | |||
| 456 | se401->bayeroffset=0; | ||
| 457 | se401->scratch_next=0; | ||
| 458 | se401->scratch_use=0; | ||
| 459 | se401->scratch_overflow=0; | ||
| 460 | for (i=0; i<SE401_NUMSCRATCH; i++) { | ||
| 461 | se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); | ||
| 462 | se401->scratch[i].state=BUFFER_UNUSED; | ||
| 463 | } | ||
| 464 | |||
| 465 | for (i=0; i<SE401_NUMSBUF; i++) { | ||
| 466 | urb=usb_alloc_urb(0, GFP_KERNEL); | ||
| 467 | if(!urb) | ||
| 468 | return -ENOMEM; | ||
| 469 | |||
| 470 | usb_fill_bulk_urb(urb, se401->dev, | ||
| 471 | usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT), | ||
| 472 | se401->sbuf[i].data, SE401_PACKETSIZE, | ||
| 473 | se401_video_irq, | ||
| 474 | se401); | ||
| 475 | |||
| 476 | se401->urb[i]=urb; | ||
| 477 | |||
| 478 | err=usb_submit_urb(se401->urb[i], GFP_KERNEL); | ||
| 479 | if(err) | ||
| 480 | err("urb burned down"); | ||
| 481 | } | ||
| 482 | |||
| 483 | se401->framecount=0; | ||
| 484 | |||
| 485 | return 0; | ||
| 486 | } | ||
| 487 | |||
| 488 | static int se401_stop_stream(struct usb_se401 *se401) | ||
| 489 | { | ||
| 490 | int i; | ||
| 491 | |||
| 492 | if (!se401->streaming || !se401->dev) | ||
| 493 | return 1; | ||
| 494 | |||
| 495 | se401->streaming=0; | ||
| 496 | |||
| 497 | se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0); | ||
| 498 | |||
| 499 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); | ||
| 500 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); | ||
| 501 | |||
| 502 | for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) { | ||
| 503 | usb_kill_urb(se401->urb[i]); | ||
| 504 | usb_free_urb(se401->urb[i]); | ||
| 505 | se401->urb[i]=NULL; | ||
| 506 | kfree(se401->sbuf[i].data); | ||
| 507 | } | ||
| 508 | for (i=0; i<SE401_NUMSCRATCH; i++) { | ||
| 509 | kfree(se401->scratch[i].data); | ||
| 510 | se401->scratch[i].data=NULL; | ||
| 511 | } | ||
| 512 | |||
| 513 | return 0; | ||
| 514 | } | ||
| 515 | |||
| 516 | static int se401_set_size(struct usb_se401 *se401, int width, int height) | ||
| 517 | { | ||
| 518 | int wasstreaming=se401->streaming; | ||
| 519 | /* Check to see if we need to change */ | ||
| 520 | if (se401->cwidth==width && se401->cheight==height) | ||
| 521 | return 0; | ||
| 522 | |||
| 523 | /* Check for a valid mode */ | ||
| 524 | if (!width || !height) | ||
| 525 | return 1; | ||
| 526 | if ((width & 1) || (height & 1)) | ||
| 527 | return 1; | ||
| 528 | if (width>se401->width[se401->sizes-1]) | ||
| 529 | return 1; | ||
| 530 | if (height>se401->height[se401->sizes-1]) | ||
| 531 | return 1; | ||
| 532 | |||
| 533 | /* Stop a current stream and start it again at the new size */ | ||
| 534 | if (wasstreaming) | ||
| 535 | se401_stop_stream(se401); | ||
| 536 | se401->cwidth=width; | ||
| 537 | se401->cheight=height; | ||
| 538 | if (wasstreaming) | ||
| 539 | se401_start_stream(se401); | ||
| 540 | return 0; | ||
| 541 | } | ||
| 542 | |||
| 543 | |||
| 544 | /**************************************************************************** | ||
| 545 | * | ||
| 546 | * Video Decoding | ||
| 547 | * | ||
| 548 | ***************************************************************************/ | ||
| 549 | |||
| 550 | /* | ||
| 551 | This shouldn't really be done in a v4l driver.... | ||
| 552 | But it does make the image look a lot more usable. | ||
| 553 | Basically it lifts the dark pixels more than the light pixels. | ||
| 554 | */ | ||
| 555 | static inline void enhance_picture(unsigned char *frame, int len) | ||
| 556 | { | ||
| 557 | while (len--) { | ||
| 558 | *frame=(((*frame^255)*(*frame^255))/255)^255; | ||
| 559 | frame++; | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data) | ||
| 564 | { | ||
| 565 | struct se401_frame *frame=&se401->frame[se401->curframe]; | ||
| 566 | int linelength=se401->cwidth*3; | ||
| 567 | |||
| 568 | if (frame->curlinepix >= linelength) { | ||
| 569 | frame->curlinepix=0; | ||
| 570 | frame->curline+=linelength; | ||
| 571 | } | ||
| 572 | |||
| 573 | /* First three are absolute, all others relative. | ||
| 574 | * Format is rgb from right to left (mirrorred image), | ||
| 575 | * we flip it to get bgr from left to right. */ | ||
| 576 | if (frame->curlinepix < 3) { | ||
| 577 | *(frame->curline-frame->curlinepix)=1+data*4; | ||
| 578 | } else { | ||
| 579 | *(frame->curline-frame->curlinepix)= | ||
| 580 | *(frame->curline-frame->curlinepix+3)+data*4; | ||
| 581 | } | ||
| 582 | frame->curlinepix++; | ||
| 583 | } | ||
| 584 | |||
| 585 | static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength) | ||
| 586 | { | ||
| 587 | int pos=0; | ||
| 588 | int vlc_cod=0; | ||
| 589 | int vlc_size=0; | ||
| 590 | int vlc_data=0; | ||
| 591 | int bit_cur; | ||
| 592 | int bit; | ||
| 593 | data+=4; | ||
| 594 | while (pos < packetlength) { | ||
| 595 | bit_cur=8; | ||
| 596 | while (bit_cur && bit_exp) { | ||
| 597 | bit=((*data)>>(bit_cur-1))&1; | ||
| 598 | if (!vlc_cod) { | ||
| 599 | if (bit) { | ||
| 600 | vlc_size++; | ||
| 601 | } else { | ||
| 602 | if (!vlc_size) { | ||
| 603 | decode_JangGu_integrate(se401, 0); | ||
| 604 | } else { | ||
| 605 | vlc_cod=2; | ||
| 606 | vlc_data=0; | ||
| 607 | } | ||
| 608 | } | ||
| 609 | } else { | ||
| 610 | if (vlc_cod==2) { | ||
| 611 | if (!bit) | ||
| 612 | vlc_data = -(1<<vlc_size) + 1; | ||
| 613 | vlc_cod--; | ||
| 614 | } | ||
| 615 | vlc_size--; | ||
| 616 | vlc_data+=bit<<vlc_size; | ||
| 617 | if (!vlc_size) { | ||
| 618 | decode_JangGu_integrate(se401, vlc_data); | ||
| 619 | vlc_cod=0; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | bit_cur--; | ||
| 623 | bit_exp--; | ||
| 624 | } | ||
| 625 | pos++; | ||
| 626 | data++; | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer) | ||
| 631 | { | ||
| 632 | unsigned char *data=buffer->data; | ||
| 633 | int len=buffer->length; | ||
| 634 | int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size; | ||
| 635 | int datapos=0; | ||
| 636 | |||
| 637 | /* New image? */ | ||
| 638 | if (!se401->frame[se401->curframe].curpix) { | ||
| 639 | se401->frame[se401->curframe].curlinepix=0; | ||
| 640 | se401->frame[se401->curframe].curline= | ||
| 641 | se401->frame[se401->curframe].data+ | ||
| 642 | se401->cwidth*3-1; | ||
| 643 | if (se401->frame[se401->curframe].grabstate==FRAME_READY) | ||
| 644 | se401->frame[se401->curframe].grabstate=FRAME_GRABBING; | ||
| 645 | se401->vlcdatapos=0; | ||
| 646 | } | ||
| 647 | while (datapos < len) { | ||
| 648 | size=1024-se401->vlcdatapos; | ||
| 649 | if (size+datapos > len) | ||
| 650 | size=len-datapos; | ||
| 651 | memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size); | ||
| 652 | se401->vlcdatapos+=size; | ||
| 653 | packetlength=0; | ||
| 654 | if (se401->vlcdatapos >= 4) { | ||
| 655 | bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8); | ||
| 656 | pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8); | ||
| 657 | frameinfo=se401->vlcdata[0]&0xc0; | ||
| 658 | packetlength=((bit_exp+47)>>4)<<1; | ||
| 659 | if (packetlength > 1024) { | ||
| 660 | se401->vlcdatapos=0; | ||
| 661 | datapos=len; | ||
| 662 | packetlength=0; | ||
| 663 | se401->error++; | ||
| 664 | se401->frame[se401->curframe].curpix=0; | ||
| 665 | } | ||
| 666 | } | ||
| 667 | if (packetlength && se401->vlcdatapos >= packetlength) { | ||
| 668 | decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength); | ||
| 669 | se401->frame[se401->curframe].curpix+=pix_exp*3; | ||
| 670 | datapos+=size-(se401->vlcdatapos-packetlength); | ||
| 671 | se401->vlcdatapos=0; | ||
| 672 | if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) { | ||
| 673 | if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) { | ||
| 674 | if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) { | ||
| 675 | se401->frame[se401->curframe].grabstate=FRAME_DONE; | ||
| 676 | se401->framecount++; | ||
| 677 | se401->readcount++; | ||
| 678 | } | ||
| 679 | if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) { | ||
| 680 | se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1); | ||
| 681 | } | ||
| 682 | } else { | ||
| 683 | se401->error++; | ||
| 684 | } | ||
| 685 | se401->frame[se401->curframe].curpix=0; | ||
| 686 | datapos=len; | ||
| 687 | } | ||
| 688 | } else { | ||
| 689 | datapos+=size; | ||
| 690 | } | ||
| 691 | } | ||
| 692 | } | ||
| 693 | |||
| 694 | static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer) | ||
| 695 | { | ||
| 696 | unsigned char *data=buffer->data; | ||
| 697 | int len=buffer->length; | ||
| 698 | int offset=buffer->offset; | ||
| 699 | int datasize=se401->cwidth*se401->cheight; | ||
| 700 | struct se401_frame *frame=&se401->frame[se401->curframe]; | ||
| 701 | |||
| 702 | unsigned char *framedata=frame->data, *curline, *nextline; | ||
| 703 | int width=se401->cwidth; | ||
| 704 | int blineoffset=0, bline; | ||
| 705 | int linelength=width*3, i; | ||
| 706 | |||
| 707 | |||
| 708 | if (frame->curpix==0) { | ||
| 709 | if (frame->grabstate==FRAME_READY) { | ||
| 710 | frame->grabstate=FRAME_GRABBING; | ||
| 711 | } | ||
| 712 | frame->curline=framedata+linelength; | ||
| 713 | frame->curlinepix=0; | ||
| 714 | } | ||
| 715 | |||
| 716 | if (offset!=frame->curpix) { | ||
| 717 | /* Regard frame as lost :( */ | ||
| 718 | frame->curpix=0; | ||
| 719 | se401->error++; | ||
| 720 | return; | ||
| 721 | } | ||
| 722 | |||
| 723 | /* Check if we have to much data */ | ||
| 724 | if (frame->curpix+len > datasize) { | ||
| 725 | len=datasize-frame->curpix; | ||
| 726 | } | ||
| 727 | if (se401->cheight%4) | ||
| 728 | blineoffset=1; | ||
| 729 | bline=frame->curpix/se401->cwidth+blineoffset; | ||
| 730 | |||
| 731 | curline=frame->curline; | ||
| 732 | nextline=curline+linelength; | ||
| 733 | if (nextline >= framedata+datasize*3) | ||
| 734 | nextline=curline; | ||
| 735 | while (len) { | ||
| 736 | if (frame->curlinepix>=width) { | ||
| 737 | frame->curlinepix-=width; | ||
| 738 | bline=frame->curpix/width+blineoffset; | ||
| 739 | curline+=linelength*2; | ||
| 740 | nextline+=linelength*2; | ||
| 741 | if (curline >= framedata+datasize*3) { | ||
| 742 | frame->curlinepix++; | ||
| 743 | curline-=3; | ||
| 744 | nextline-=3; | ||
| 745 | len--; | ||
| 746 | data++; | ||
| 747 | frame->curpix++; | ||
| 748 | } | ||
| 749 | if (nextline >= framedata+datasize*3) | ||
| 750 | nextline=curline; | ||
| 751 | } | ||
| 752 | if ((bline&1)) { | ||
| 753 | if ((frame->curlinepix&1)) { | ||
| 754 | *(curline+2)=*data; | ||
| 755 | *(curline-1)=*data; | ||
| 756 | *(nextline+2)=*data; | ||
| 757 | *(nextline-1)=*data; | ||
| 758 | } else { | ||
| 759 | *(curline+1)= | ||
| 760 | (*(curline+1)+*data)/2; | ||
| 761 | *(curline-2)= | ||
| 762 | (*(curline-2)+*data)/2; | ||
| 763 | *(nextline+1)=*data; | ||
| 764 | *(nextline-2)=*data; | ||
| 765 | } | ||
| 766 | } else { | ||
| 767 | if ((frame->curlinepix&1)) { | ||
| 768 | *(curline+1)= | ||
| 769 | (*(curline+1)+*data)/2; | ||
| 770 | *(curline-2)= | ||
| 771 | (*(curline-2)+*data)/2; | ||
| 772 | *(nextline+1)=*data; | ||
| 773 | *(nextline-2)=*data; | ||
| 774 | } else { | ||
| 775 | *curline=*data; | ||
| 776 | *(curline-3)=*data; | ||
| 777 | *nextline=*data; | ||
| 778 | *(nextline-3)=*data; | ||
| 779 | } | ||
| 780 | } | ||
| 781 | frame->curlinepix++; | ||
| 782 | curline-=3; | ||
| 783 | nextline-=3; | ||
| 784 | len--; | ||
| 785 | data++; | ||
| 786 | frame->curpix++; | ||
| 787 | } | ||
| 788 | frame->curline=curline; | ||
| 789 | |||
| 790 | if (frame->curpix>=datasize) { | ||
| 791 | /* Fix the top line */ | ||
| 792 | framedata+=linelength; | ||
| 793 | for (i=0; i<linelength; i++) { | ||
| 794 | framedata--; | ||
| 795 | *framedata=*(framedata+linelength); | ||
| 796 | } | ||
| 797 | /* Fix the left side (green is already present) */ | ||
| 798 | for (i=0; i<se401->cheight; i++) { | ||
| 799 | *framedata=*(framedata+3); | ||
| 800 | *(framedata+1)=*(framedata+4); | ||
| 801 | *(framedata+2)=*(framedata+5); | ||
| 802 | framedata+=linelength; | ||
| 803 | } | ||
| 804 | frame->curpix=0; | ||
| 805 | frame->grabstate=FRAME_DONE; | ||
| 806 | se401->framecount++; | ||
| 807 | se401->readcount++; | ||
| 808 | if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) { | ||
| 809 | se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1); | ||
| 810 | } | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | static int se401_newframe(struct usb_se401 *se401, int framenr) | ||
| 815 | { | ||
| 816 | DECLARE_WAITQUEUE(wait, current); | ||
| 817 | int errors=0; | ||
| 818 | |||
| 819 | while (se401->streaming && | ||
| 820 | (se401->frame[framenr].grabstate==FRAME_READY || | ||
| 821 | se401->frame[framenr].grabstate==FRAME_GRABBING) ) { | ||
| 822 | if(!se401->frame[framenr].curpix) { | ||
| 823 | errors++; | ||
| 824 | } | ||
| 825 | wait_interruptible( | ||
| 826 | se401->scratch[se401->scratch_use].state!=BUFFER_READY, | ||
| 827 | &se401->wq, | ||
| 828 | &wait | ||
| 829 | ); | ||
| 830 | if (se401->nullpackets > SE401_MAX_NULLPACKETS) { | ||
| 831 | se401->nullpackets=0; | ||
| 832 | info("to many null length packets, restarting capture"); | ||
| 833 | se401_stop_stream(se401); | ||
| 834 | se401_start_stream(se401); | ||
| 835 | } else { | ||
| 836 | if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) { | ||
| 837 | se401->frame[framenr].grabstate=FRAME_ERROR; | ||
| 838 | return -EIO; | ||
| 839 | } | ||
| 840 | se401->scratch[se401->scratch_use].state=BUFFER_BUSY; | ||
| 841 | if (se401->format==FMT_JANGGU) { | ||
| 842 | decode_JangGu(se401, &se401->scratch[se401->scratch_use]); | ||
| 843 | } else { | ||
| 844 | decode_bayer(se401, &se401->scratch[se401->scratch_use]); | ||
| 845 | } | ||
| 846 | se401->scratch[se401->scratch_use].state=BUFFER_UNUSED; | ||
| 847 | se401->scratch_use++; | ||
| 848 | if (se401->scratch_use>=SE401_NUMSCRATCH) | ||
| 849 | se401->scratch_use=0; | ||
| 850 | if (errors > SE401_MAX_ERRORS) { | ||
| 851 | errors=0; | ||
| 852 | info("to much errors, restarting capture"); | ||
| 853 | se401_stop_stream(se401); | ||
| 854 | se401_start_stream(se401); | ||
| 855 | } | ||
| 856 | } | ||
| 857 | } | ||
| 858 | |||
| 859 | if (se401->frame[framenr].grabstate==FRAME_DONE) | ||
| 860 | if (se401->enhance) | ||
| 861 | enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3); | ||
| 862 | return 0; | ||
| 863 | } | ||
| 864 | |||
| 865 | static void usb_se401_remove_disconnected (struct usb_se401 *se401) | ||
| 866 | { | ||
| 867 | int i; | ||
| 868 | |||
| 869 | se401->dev = NULL; | ||
| 870 | |||
| 871 | for (i=0; i<SE401_NUMSBUF; i++) | ||
| 872 | if (se401->urb[i]) { | ||
| 873 | usb_kill_urb(se401->urb[i]); | ||
| 874 | usb_free_urb(se401->urb[i]); | ||
| 875 | se401->urb[i] = NULL; | ||
| 876 | kfree(se401->sbuf[i].data); | ||
| 877 | } | ||
| 878 | for (i=0; i<SE401_NUMSCRATCH; i++) { | ||
| 879 | kfree(se401->scratch[i].data); | ||
| 880 | } | ||
| 881 | if (se401->inturb) { | ||
| 882 | usb_kill_urb(se401->inturb); | ||
| 883 | usb_free_urb(se401->inturb); | ||
| 884 | } | ||
| 885 | info("%s disconnected", se401->camera_name); | ||
| 886 | |||
| 887 | /* Free the memory */ | ||
| 888 | kfree(se401->width); | ||
| 889 | kfree(se401->height); | ||
| 890 | kfree(se401); | ||
| 891 | } | ||
| 892 | |||
| 893 | |||
| 894 | |||
| 895 | /**************************************************************************** | ||
| 896 | * | ||
| 897 | * Video4Linux | ||
| 898 | * | ||
| 899 | ***************************************************************************/ | ||
| 900 | |||
| 901 | |||
| 902 | static int se401_open(struct inode *inode, struct file *file) | ||
| 903 | { | ||
| 904 | struct video_device *dev = video_devdata(file); | ||
| 905 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
| 906 | int err = 0; | ||
| 907 | |||
| 908 | if (se401->user) | ||
| 909 | return -EBUSY; | ||
| 910 | se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES); | ||
| 911 | if (se401->fbuf) | ||
| 912 | file->private_data = dev; | ||
| 913 | else | ||
| 914 | err = -ENOMEM; | ||
| 915 | se401->user = !err; | ||
| 916 | |||
| 917 | return err; | ||
| 918 | } | ||
| 919 | |||
| 920 | static int se401_close(struct inode *inode, struct file *file) | ||
| 921 | { | ||
| 922 | struct video_device *dev = file->private_data; | ||
| 923 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
| 924 | int i; | ||
| 925 | |||
| 926 | rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES); | ||
| 927 | if (se401->removed) { | ||
| 928 | usb_se401_remove_disconnected(se401); | ||
| 929 | info("device unregistered"); | ||
| 930 | } else { | ||
| 931 | for (i=0; i<SE401_NUMFRAMES; i++) | ||
| 932 | se401->frame[i].grabstate=FRAME_UNUSED; | ||
| 933 | if (se401->streaming) | ||
| 934 | se401_stop_stream(se401); | ||
| 935 | se401->user=0; | ||
| 936 | } | ||
| 937 | file->private_data = NULL; | ||
| 938 | return 0; | ||
| 939 | } | ||
| 940 | |||
| 941 | static int se401_do_ioctl(struct inode *inode, struct file *file, | ||
| 942 | unsigned int cmd, void *arg) | ||
| 943 | { | ||
| 944 | struct video_device *vdev = file->private_data; | ||
| 945 | struct usb_se401 *se401 = (struct usb_se401 *)vdev; | ||
| 946 | |||
| 947 | if (!se401->dev) | ||
| 948 | return -EIO; | ||
| 949 | |||
| 950 | switch (cmd) { | ||
| 951 | case VIDIOCGCAP: | ||
| 952 | { | ||
| 953 | struct video_capability *b = arg; | ||
| 954 | strcpy(b->name, se401->camera_name); | ||
| 955 | b->type = VID_TYPE_CAPTURE; | ||
| 956 | b->channels = 1; | ||
| 957 | b->audios = 0; | ||
| 958 | b->maxwidth = se401->width[se401->sizes-1]; | ||
| 959 | b->maxheight = se401->height[se401->sizes-1]; | ||
| 960 | b->minwidth = se401->width[0]; | ||
| 961 | b->minheight = se401->height[0]; | ||
| 962 | return 0; | ||
| 963 | } | ||
| 964 | case VIDIOCGCHAN: | ||
| 965 | { | ||
| 966 | struct video_channel *v = arg; | ||
| 967 | |||
| 968 | if (v->channel != 0) | ||
| 969 | return -EINVAL; | ||
| 970 | v->flags = 0; | ||
| 971 | v->tuners = 0; | ||
| 972 | v->type = VIDEO_TYPE_CAMERA; | ||
| 973 | strcpy(v->name, "Camera"); | ||
| 974 | return 0; | ||
| 975 | } | ||
| 976 | case VIDIOCSCHAN: | ||
| 977 | { | ||
| 978 | struct video_channel *v = arg; | ||
| 979 | |||
| 980 | if (v->channel != 0) | ||
| 981 | return -EINVAL; | ||
| 982 | return 0; | ||
| 983 | } | ||
| 984 | case VIDIOCGPICT: | ||
| 985 | { | ||
| 986 | struct video_picture *p = arg; | ||
| 987 | |||
| 988 | se401_get_pict(se401, p); | ||
| 989 | return 0; | ||
| 990 | } | ||
| 991 | case VIDIOCSPICT: | ||
| 992 | { | ||
| 993 | struct video_picture *p = arg; | ||
| 994 | |||
| 995 | if (se401_set_pict(se401, p)) | ||
| 996 | return -EINVAL; | ||
| 997 | return 0; | ||
| 998 | } | ||
| 999 | case VIDIOCSWIN: | ||
| 1000 | { | ||
| 1001 | struct video_window *vw = arg; | ||
| 1002 | |||
| 1003 | if (vw->flags) | ||
| 1004 | return -EINVAL; | ||
| 1005 | if (vw->clipcount) | ||
| 1006 | return -EINVAL; | ||
| 1007 | if (se401_set_size(se401, vw->width, vw->height)) | ||
| 1008 | return -EINVAL; | ||
| 1009 | return 0; | ||
| 1010 | } | ||
| 1011 | case VIDIOCGWIN: | ||
| 1012 | { | ||
| 1013 | struct video_window *vw = arg; | ||
| 1014 | |||
| 1015 | vw->x = 0; /* FIXME */ | ||
| 1016 | vw->y = 0; | ||
| 1017 | vw->chromakey = 0; | ||
| 1018 | vw->flags = 0; | ||
| 1019 | vw->clipcount = 0; | ||
| 1020 | vw->width = se401->cwidth; | ||
| 1021 | vw->height = se401->cheight; | ||
| 1022 | return 0; | ||
| 1023 | } | ||
| 1024 | case VIDIOCGMBUF: | ||
| 1025 | { | ||
| 1026 | struct video_mbuf *vm = arg; | ||
| 1027 | int i; | ||
| 1028 | |||
| 1029 | memset(vm, 0, sizeof(*vm)); | ||
| 1030 | vm->size = SE401_NUMFRAMES * se401->maxframesize; | ||
| 1031 | vm->frames = SE401_NUMFRAMES; | ||
| 1032 | for (i=0; i<SE401_NUMFRAMES; i++) | ||
| 1033 | vm->offsets[i] = se401->maxframesize * i; | ||
| 1034 | return 0; | ||
| 1035 | } | ||
| 1036 | case VIDIOCMCAPTURE: | ||
| 1037 | { | ||
| 1038 | struct video_mmap *vm = arg; | ||
| 1039 | |||
| 1040 | if (vm->format != VIDEO_PALETTE_RGB24) | ||
| 1041 | return -EINVAL; | ||
| 1042 | if (vm->frame >= SE401_NUMFRAMES) | ||
| 1043 | return -EINVAL; | ||
| 1044 | if (se401->frame[vm->frame].grabstate != FRAME_UNUSED) | ||
| 1045 | return -EBUSY; | ||
| 1046 | |||
| 1047 | /* Is this according to the v4l spec??? */ | ||
| 1048 | if (se401_set_size(se401, vm->width, vm->height)) | ||
| 1049 | return -EINVAL; | ||
| 1050 | se401->frame[vm->frame].grabstate=FRAME_READY; | ||
| 1051 | |||
| 1052 | if (!se401->streaming) | ||
| 1053 | se401_start_stream(se401); | ||
| 1054 | |||
| 1055 | /* Set the picture properties */ | ||
| 1056 | if (se401->framecount==0) | ||
| 1057 | se401_send_pict(se401); | ||
| 1058 | /* Calibrate the reset level after a few frames. */ | ||
| 1059 | if (se401->framecount%20==1) | ||
| 1060 | se401_auto_resetlevel(se401); | ||
| 1061 | |||
| 1062 | return 0; | ||
| 1063 | } | ||
| 1064 | case VIDIOCSYNC: | ||
| 1065 | { | ||
| 1066 | int *frame = arg; | ||
| 1067 | int ret=0; | ||
| 1068 | |||
| 1069 | if(*frame <0 || *frame >= SE401_NUMFRAMES) | ||
| 1070 | return -EINVAL; | ||
| 1071 | |||
| 1072 | ret=se401_newframe(se401, *frame); | ||
| 1073 | se401->frame[*frame].grabstate=FRAME_UNUSED; | ||
| 1074 | return ret; | ||
| 1075 | } | ||
| 1076 | case VIDIOCGFBUF: | ||
| 1077 | { | ||
| 1078 | struct video_buffer *vb = arg; | ||
| 1079 | |||
| 1080 | memset(vb, 0, sizeof(*vb)); | ||
| 1081 | return 0; | ||
| 1082 | } | ||
| 1083 | case VIDIOCKEY: | ||
| 1084 | return 0; | ||
| 1085 | case VIDIOCCAPTURE: | ||
| 1086 | return -EINVAL; | ||
| 1087 | case VIDIOCSFBUF: | ||
| 1088 | return -EINVAL; | ||
| 1089 | case VIDIOCGTUNER: | ||
| 1090 | case VIDIOCSTUNER: | ||
| 1091 | return -EINVAL; | ||
| 1092 | case VIDIOCGFREQ: | ||
| 1093 | case VIDIOCSFREQ: | ||
| 1094 | return -EINVAL; | ||
| 1095 | case VIDIOCGAUDIO: | ||
| 1096 | case VIDIOCSAUDIO: | ||
| 1097 | return -EINVAL; | ||
| 1098 | default: | ||
| 1099 | return -ENOIOCTLCMD; | ||
| 1100 | } /* end switch */ | ||
| 1101 | |||
| 1102 | return 0; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | static int se401_ioctl(struct inode *inode, struct file *file, | ||
| 1106 | unsigned int cmd, unsigned long arg) | ||
| 1107 | { | ||
| 1108 | return video_usercopy(inode, file, cmd, arg, se401_do_ioctl); | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | static ssize_t se401_read(struct file *file, char __user *buf, | ||
| 1112 | size_t count, loff_t *ppos) | ||
| 1113 | { | ||
| 1114 | int realcount=count, ret=0; | ||
| 1115 | struct video_device *dev = file->private_data; | ||
| 1116 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
| 1117 | |||
| 1118 | |||
| 1119 | if (se401->dev == NULL) | ||
| 1120 | return -EIO; | ||
| 1121 | if (realcount > se401->cwidth*se401->cheight*3) | ||
| 1122 | realcount=se401->cwidth*se401->cheight*3; | ||
| 1123 | |||
| 1124 | /* Shouldn't happen: */ | ||
| 1125 | if (se401->frame[0].grabstate==FRAME_GRABBING) | ||
| 1126 | return -EBUSY; | ||
| 1127 | se401->frame[0].grabstate=FRAME_READY; | ||
| 1128 | se401->frame[1].grabstate=FRAME_UNUSED; | ||
| 1129 | se401->curframe=0; | ||
| 1130 | |||
| 1131 | if (!se401->streaming) | ||
| 1132 | se401_start_stream(se401); | ||
| 1133 | |||
| 1134 | /* Set the picture properties */ | ||
| 1135 | if (se401->framecount==0) | ||
| 1136 | se401_send_pict(se401); | ||
| 1137 | /* Calibrate the reset level after a few frames. */ | ||
| 1138 | if (se401->framecount%20==1) | ||
| 1139 | se401_auto_resetlevel(se401); | ||
| 1140 | |||
| 1141 | ret=se401_newframe(se401, 0); | ||
| 1142 | |||
| 1143 | se401->frame[0].grabstate=FRAME_UNUSED; | ||
| 1144 | if (ret) | ||
| 1145 | return ret; | ||
| 1146 | if (copy_to_user(buf, se401->frame[0].data, realcount)) | ||
| 1147 | return -EFAULT; | ||
| 1148 | |||
| 1149 | return realcount; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | static int se401_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 1153 | { | ||
| 1154 | struct video_device *dev = file->private_data; | ||
| 1155 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
| 1156 | unsigned long start = vma->vm_start; | ||
| 1157 | unsigned long size = vma->vm_end-vma->vm_start; | ||
| 1158 | unsigned long page, pos; | ||
| 1159 | |||
| 1160 | mutex_lock(&se401->lock); | ||
| 1161 | |||
| 1162 | if (se401->dev == NULL) { | ||
| 1163 | mutex_unlock(&se401->lock); | ||
| 1164 | return -EIO; | ||
| 1165 | } | ||
| 1166 | if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { | ||
| 1167 | mutex_unlock(&se401->lock); | ||
| 1168 | return -EINVAL; | ||
| 1169 | } | ||
| 1170 | pos = (unsigned long)se401->fbuf; | ||
| 1171 | while (size > 0) { | ||
| 1172 | page = vmalloc_to_pfn((void *)pos); | ||
| 1173 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | ||
| 1174 | mutex_unlock(&se401->lock); | ||
| 1175 | return -EAGAIN; | ||
| 1176 | } | ||
| 1177 | start += PAGE_SIZE; | ||
| 1178 | pos += PAGE_SIZE; | ||
| 1179 | if (size > PAGE_SIZE) | ||
| 1180 | size -= PAGE_SIZE; | ||
| 1181 | else | ||
| 1182 | size = 0; | ||
| 1183 | } | ||
| 1184 | mutex_unlock(&se401->lock); | ||
| 1185 | |||
| 1186 | return 0; | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | static struct file_operations se401_fops = { | ||
| 1190 | .owner = THIS_MODULE, | ||
| 1191 | .open = se401_open, | ||
| 1192 | .release = se401_close, | ||
| 1193 | .read = se401_read, | ||
| 1194 | .mmap = se401_mmap, | ||
| 1195 | .ioctl = se401_ioctl, | ||
| 1196 | .compat_ioctl = v4l_compat_ioctl32, | ||
| 1197 | .llseek = no_llseek, | ||
| 1198 | }; | ||
| 1199 | static struct video_device se401_template = { | ||
| 1200 | .owner = THIS_MODULE, | ||
| 1201 | .name = "se401 USB camera", | ||
| 1202 | .type = VID_TYPE_CAPTURE, | ||
| 1203 | .hardware = VID_HARDWARE_SE401, | ||
| 1204 | .fops = &se401_fops, | ||
| 1205 | }; | ||
| 1206 | |||
| 1207 | |||
| 1208 | |||
| 1209 | /***************************/ | ||
| 1210 | static int se401_init(struct usb_se401 *se401, int button) | ||
| 1211 | { | ||
| 1212 | int i=0, rc; | ||
| 1213 | unsigned char cp[0x40]; | ||
| 1214 | char temp[200]; | ||
| 1215 | |||
| 1216 | /* led on */ | ||
| 1217 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); | ||
| 1218 | |||
| 1219 | /* get camera descriptor */ | ||
| 1220 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp)); | ||
| 1221 | if (cp[1]!=0x41) { | ||
| 1222 | err("Wrong descriptor type"); | ||
| 1223 | return 1; | ||
| 1224 | } | ||
| 1225 | sprintf (temp, "ExtraFeatures: %d", cp[3]); | ||
| 1226 | |||
| 1227 | se401->sizes=cp[4]+cp[5]*256; | ||
| 1228 | se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); | ||
| 1229 | if (!se401->width) | ||
| 1230 | return 1; | ||
| 1231 | se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); | ||
| 1232 | if (!se401->height) { | ||
| 1233 | kfree(se401->width); | ||
| 1234 | return 1; | ||
| 1235 | } | ||
| 1236 | for (i=0; i<se401->sizes; i++) { | ||
| 1237 | se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256; | ||
| 1238 | se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256; | ||
| 1239 | } | ||
| 1240 | sprintf (temp, "%s Sizes:", temp); | ||
| 1241 | for (i=0; i<se401->sizes; i++) { | ||
| 1242 | sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]); | ||
| 1243 | } | ||
| 1244 | info("%s", temp); | ||
| 1245 | se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3; | ||
| 1246 | |||
| 1247 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp)); | ||
| 1248 | se401->cwidth=cp[0]+cp[1]*256; | ||
| 1249 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp)); | ||
| 1250 | se401->cheight=cp[0]+cp[1]*256; | ||
| 1251 | |||
| 1252 | if (!cp[2] && SE401_FORMAT_BAYER) { | ||
| 1253 | err("Bayer format not supported!"); | ||
| 1254 | return 1; | ||
| 1255 | } | ||
| 1256 | /* set output mode (BAYER) */ | ||
| 1257 | se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0); | ||
| 1258 | |||
| 1259 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp)); | ||
| 1260 | se401->brightness=cp[0]+cp[1]*256; | ||
| 1261 | /* some default values */ | ||
| 1262 | se401->resetlevel=0x2d; | ||
| 1263 | se401->rgain=0x20; | ||
| 1264 | se401->ggain=0x20; | ||
| 1265 | se401->bgain=0x20; | ||
| 1266 | se401_set_exposure(se401, 20000); | ||
| 1267 | se401->palette=VIDEO_PALETTE_RGB24; | ||
| 1268 | se401->enhance=1; | ||
| 1269 | se401->dropped=0; | ||
| 1270 | se401->error=0; | ||
| 1271 | se401->framecount=0; | ||
| 1272 | se401->readcount=0; | ||
| 1273 | |||
| 1274 | /* Start interrupt transfers for snapshot button */ | ||
| 1275 | if (button) { | ||
| 1276 | se401->inturb=usb_alloc_urb(0, GFP_KERNEL); | ||
| 1277 | if (!se401->inturb) { | ||
| 1278 | info("Allocation of inturb failed"); | ||
| 1279 | return 1; | ||
| 1280 | } | ||
| 1281 | usb_fill_int_urb(se401->inturb, se401->dev, | ||
| 1282 | usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT), | ||
| 1283 | &se401->button, sizeof(se401->button), | ||
| 1284 | se401_button_irq, | ||
| 1285 | se401, | ||
| 1286 | 8 | ||
| 1287 | ); | ||
| 1288 | if (usb_submit_urb(se401->inturb, GFP_KERNEL)) { | ||
| 1289 | info("int urb burned down"); | ||
| 1290 | return 1; | ||
| 1291 | } | ||
| 1292 | } else | ||
| 1293 | se401->inturb=NULL; | ||
| 1294 | |||
| 1295 | /* Flash the led */ | ||
| 1296 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); | ||
| 1297 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); | ||
| 1298 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); | ||
| 1299 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); | ||
| 1300 | |||
| 1301 | return 0; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | static int se401_probe(struct usb_interface *intf, | ||
| 1305 | const struct usb_device_id *id) | ||
| 1306 | { | ||
| 1307 | struct usb_device *dev = interface_to_usbdev(intf); | ||
| 1308 | struct usb_interface_descriptor *interface; | ||
| 1309 | struct usb_se401 *se401; | ||
| 1310 | char *camera_name=NULL; | ||
| 1311 | int button=1; | ||
| 1312 | |||
| 1313 | /* We don't handle multi-config cameras */ | ||
| 1314 | if (dev->descriptor.bNumConfigurations != 1) | ||
| 1315 | return -ENODEV; | ||
| 1316 | |||
| 1317 | interface = &intf->cur_altsetting->desc; | ||
| 1318 | |||
| 1319 | /* Is it an se401? */ | ||
| 1320 | if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 && | ||
| 1321 | le16_to_cpu(dev->descriptor.idProduct) == 0x0004) { | ||
| 1322 | camera_name="Endpoints/Aox SE401"; | ||
| 1323 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 && | ||
| 1324 | le16_to_cpu(dev->descriptor.idProduct) == 0x030b) { | ||
| 1325 | camera_name="Philips PCVC665K"; | ||
| 1326 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && | ||
| 1327 | le16_to_cpu(dev->descriptor.idProduct) == 0x5001) { | ||
| 1328 | camera_name="Kensington VideoCAM 67014"; | ||
| 1329 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && | ||
| 1330 | le16_to_cpu(dev->descriptor.idProduct) == 0x5002) { | ||
| 1331 | camera_name="Kensington VideoCAM 6701(5/7)"; | ||
| 1332 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && | ||
| 1333 | le16_to_cpu(dev->descriptor.idProduct) == 0x5003) { | ||
| 1334 | camera_name="Kensington VideoCAM 67016"; | ||
| 1335 | button=0; | ||
| 1336 | } else | ||
| 1337 | return -ENODEV; | ||
| 1338 | |||
| 1339 | /* Checking vendor/product should be enough, but what the hell */ | ||
| 1340 | if (interface->bInterfaceClass != 0x00) | ||
| 1341 | return -ENODEV; | ||
| 1342 | if (interface->bInterfaceSubClass != 0x00) | ||
| 1343 | return -ENODEV; | ||
| 1344 | |||
| 1345 | /* We found one */ | ||
| 1346 | info("SE401 camera found: %s", camera_name); | ||
| 1347 | |||
| 1348 | if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) { | ||
| 1349 | err("couldn't kmalloc se401 struct"); | ||
| 1350 | return -ENOMEM; | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | se401->dev = dev; | ||
| 1354 | se401->iface = interface->bInterfaceNumber; | ||
| 1355 | se401->camera_name = camera_name; | ||
| 1356 | |||
| 1357 | info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255); | ||
| 1358 | |||
| 1359 | if (se401_init(se401, button)) { | ||
| 1360 | kfree(se401); | ||
| 1361 | return -EIO; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | memcpy(&se401->vdev, &se401_template, sizeof(se401_template)); | ||
| 1365 | memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name)); | ||
| 1366 | init_waitqueue_head(&se401->wq); | ||
| 1367 | mutex_init(&se401->lock); | ||
| 1368 | wmb(); | ||
| 1369 | |||
| 1370 | if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { | ||
| 1371 | kfree(se401); | ||
| 1372 | err("video_register_device failed"); | ||
| 1373 | return -EIO; | ||
| 1374 | } | ||
| 1375 | info("registered new video device: video%d", se401->vdev.minor); | ||
| 1376 | |||
| 1377 | usb_set_intfdata (intf, se401); | ||
| 1378 | return 0; | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | static void se401_disconnect(struct usb_interface *intf) | ||
| 1382 | { | ||
| 1383 | struct usb_se401 *se401 = usb_get_intfdata (intf); | ||
| 1384 | |||
| 1385 | usb_set_intfdata (intf, NULL); | ||
| 1386 | if (se401) { | ||
| 1387 | video_unregister_device(&se401->vdev); | ||
| 1388 | if (!se401->user){ | ||
| 1389 | usb_se401_remove_disconnected(se401); | ||
| 1390 | } else { | ||
| 1391 | se401->frame[0].grabstate = FRAME_ERROR; | ||
| 1392 | se401->frame[0].grabstate = FRAME_ERROR; | ||
| 1393 | |||
| 1394 | se401->streaming = 0; | ||
| 1395 | |||
| 1396 | wake_up_interruptible(&se401->wq); | ||
| 1397 | se401->removed = 1; | ||
| 1398 | } | ||
| 1399 | } | ||
| 1400 | } | ||
| 1401 | |||
| 1402 | static struct usb_driver se401_driver = { | ||
| 1403 | .name = "se401", | ||
| 1404 | .id_table = device_table, | ||
| 1405 | .probe = se401_probe, | ||
| 1406 | .disconnect = se401_disconnect, | ||
| 1407 | }; | ||
| 1408 | |||
| 1409 | |||
| 1410 | |||
| 1411 | /**************************************************************************** | ||
| 1412 | * | ||
| 1413 | * Module routines | ||
| 1414 | * | ||
| 1415 | ***************************************************************************/ | ||
| 1416 | |||
| 1417 | static int __init usb_se401_init(void) | ||
| 1418 | { | ||
| 1419 | info("SE401 usb camera driver version %s registering", version); | ||
| 1420 | if (flickerless) | ||
| 1421 | if (flickerless!=50 && flickerless!=60) { | ||
| 1422 | info("Invallid flickerless value, use 0, 50 or 60."); | ||
| 1423 | return -1; | ||
| 1424 | } | ||
| 1425 | return usb_register(&se401_driver); | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | static void __exit usb_se401_exit(void) | ||
| 1429 | { | ||
| 1430 | usb_deregister(&se401_driver); | ||
| 1431 | info("SE401 driver deregistered"); | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | module_init(usb_se401_init); | ||
| 1435 | module_exit(usb_se401_exit); | ||
diff --git a/drivers/usb/media/se401.h b/drivers/usb/media/se401.h deleted file mode 100644 index e88a40d4c86a..000000000000 --- a/drivers/usb/media/se401.h +++ /dev/null | |||
| @@ -1,234 +0,0 @@ | |||
| 1 | |||
| 2 | #ifndef __LINUX_se401_H | ||
| 3 | #define __LINUX_se401_H | ||
| 4 | |||
| 5 | #include <asm/uaccess.h> | ||
| 6 | #include <linux/videodev.h> | ||
| 7 | #include <linux/smp_lock.h> | ||
| 8 | #include <linux/mutex.h> | ||
| 9 | |||
| 10 | #define se401_DEBUG /* Turn on debug messages */ | ||
| 11 | |||
| 12 | #ifdef se401_DEBUG | ||
| 13 | # define PDEBUG(level, fmt, args...) \ | ||
| 14 | if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args) | ||
| 15 | #else | ||
| 16 | # define PDEBUG(level, fmt, args...) do {} while(0) | ||
| 17 | #endif | ||
| 18 | |||
| 19 | /* An almost drop-in replacement for sleep_on_interruptible */ | ||
| 20 | #define wait_interruptible(test, queue, wait) \ | ||
| 21 | { \ | ||
| 22 | add_wait_queue(queue, wait); \ | ||
| 23 | set_current_state(TASK_INTERRUPTIBLE); \ | ||
| 24 | if (test) \ | ||
| 25 | schedule(); \ | ||
| 26 | remove_wait_queue(queue, wait); \ | ||
| 27 | set_current_state(TASK_RUNNING); \ | ||
| 28 | if (signal_pending(current)) \ | ||
| 29 | break; \ | ||
| 30 | } | ||
| 31 | |||
| 32 | #define SE401_REQ_GET_CAMERA_DESCRIPTOR 0x06 | ||
| 33 | #define SE401_REQ_START_CONTINUOUS_CAPTURE 0x41 | ||
| 34 | #define SE401_REQ_STOP_CONTINUOUS_CAPTURE 0x42 | ||
| 35 | #define SE401_REQ_CAPTURE_FRAME 0x43 | ||
| 36 | #define SE401_REQ_GET_BRT 0x44 | ||
| 37 | #define SE401_REQ_SET_BRT 0x45 | ||
| 38 | #define SE401_REQ_GET_WIDTH 0x4c | ||
| 39 | #define SE401_REQ_SET_WIDTH 0x4d | ||
| 40 | #define SE401_REQ_GET_HEIGHT 0x4e | ||
| 41 | #define SE401_REQ_SET_HEIGHT 0x4f | ||
| 42 | #define SE401_REQ_GET_OUTPUT_MODE 0x50 | ||
| 43 | #define SE401_REQ_SET_OUTPUT_MODE 0x51 | ||
| 44 | #define SE401_REQ_GET_EXT_FEATURE 0x52 | ||
| 45 | #define SE401_REQ_SET_EXT_FEATURE 0x53 | ||
| 46 | #define SE401_REQ_CAMERA_POWER 0x56 | ||
| 47 | #define SE401_REQ_LED_CONTROL 0x57 | ||
| 48 | #define SE401_REQ_BIOS 0xff | ||
| 49 | |||
| 50 | #define SE401_BIOS_READ 0x07 | ||
| 51 | |||
| 52 | #define SE401_FORMAT_BAYER 0x40 | ||
| 53 | |||
| 54 | /* Hyundai hv7131b registers | ||
| 55 | 7121 and 7141 should be the same (haven't really checked...) */ | ||
| 56 | /* Mode registers: */ | ||
| 57 | #define HV7131_REG_MODE_A 0x00 | ||
| 58 | #define HV7131_REG_MODE_B 0x01 | ||
| 59 | #define HV7131_REG_MODE_C 0x02 | ||
| 60 | /* Frame registers: */ | ||
| 61 | #define HV7131_REG_FRSU 0x10 | ||
| 62 | #define HV7131_REG_FRSL 0x11 | ||
| 63 | #define HV7131_REG_FCSU 0x12 | ||
| 64 | #define HV7131_REG_FCSL 0x13 | ||
| 65 | #define HV7131_REG_FWHU 0x14 | ||
| 66 | #define HV7131_REG_FWHL 0x15 | ||
| 67 | #define HV7131_REG_FWWU 0x16 | ||
| 68 | #define HV7131_REG_FWWL 0x17 | ||
| 69 | /* Timing registers: */ | ||
| 70 | #define HV7131_REG_THBU 0x20 | ||
| 71 | #define HV7131_REG_THBL 0x21 | ||
| 72 | #define HV7131_REG_TVBU 0x22 | ||
| 73 | #define HV7131_REG_TVBL 0x23 | ||
| 74 | #define HV7131_REG_TITU 0x25 | ||
| 75 | #define HV7131_REG_TITM 0x26 | ||
| 76 | #define HV7131_REG_TITL 0x27 | ||
| 77 | #define HV7131_REG_TMCD 0x28 | ||
| 78 | /* Adjust Registers: */ | ||
| 79 | #define HV7131_REG_ARLV 0x30 | ||
| 80 | #define HV7131_REG_ARCG 0x31 | ||
| 81 | #define HV7131_REG_AGCG 0x32 | ||
| 82 | #define HV7131_REG_ABCG 0x33 | ||
| 83 | #define HV7131_REG_APBV 0x34 | ||
| 84 | #define HV7131_REG_ASLP 0x54 | ||
| 85 | /* Offset Registers: */ | ||
| 86 | #define HV7131_REG_OFSR 0x50 | ||
| 87 | #define HV7131_REG_OFSG 0x51 | ||
| 88 | #define HV7131_REG_OFSB 0x52 | ||
| 89 | /* REset level statistics registers: */ | ||
| 90 | #define HV7131_REG_LOREFNOH 0x57 | ||
| 91 | #define HV7131_REG_LOREFNOL 0x58 | ||
| 92 | #define HV7131_REG_HIREFNOH 0x59 | ||
| 93 | #define HV7131_REG_HIREFNOL 0x5a | ||
| 94 | |||
| 95 | /* se401 registers */ | ||
| 96 | #define SE401_OPERATINGMODE 0x2000 | ||
| 97 | |||
| 98 | |||
| 99 | /* size of usb transfers */ | ||
| 100 | #define SE401_PACKETSIZE 4096 | ||
| 101 | /* number of queued bulk transfers to use, should be about 8 */ | ||
| 102 | #define SE401_NUMSBUF 1 | ||
| 103 | /* read the usb specs for this one :) */ | ||
| 104 | #define SE401_VIDEO_ENDPOINT 1 | ||
| 105 | #define SE401_BUTTON_ENDPOINT 2 | ||
| 106 | /* number of frames supported by the v4l part */ | ||
| 107 | #define SE401_NUMFRAMES 2 | ||
| 108 | /* scratch buffers for passing data to the decoders */ | ||
| 109 | #define SE401_NUMSCRATCH 32 | ||
| 110 | /* maximum amount of data in a JangGu packet */ | ||
| 111 | #define SE401_VLCDATALEN 1024 | ||
| 112 | /* number of nul sized packets to receive before kicking the camera */ | ||
| 113 | #define SE401_MAX_NULLPACKETS 4000 | ||
| 114 | /* number of decoding errors before kicking the camera */ | ||
| 115 | #define SE401_MAX_ERRORS 200 | ||
| 116 | |||
| 117 | struct usb_device; | ||
| 118 | |||
| 119 | struct se401_sbuf { | ||
| 120 | unsigned char *data; | ||
| 121 | }; | ||
| 122 | |||
| 123 | enum { | ||
| 124 | FRAME_UNUSED, /* Unused (no MCAPTURE) */ | ||
| 125 | FRAME_READY, /* Ready to start grabbing */ | ||
| 126 | FRAME_GRABBING, /* In the process of being grabbed into */ | ||
| 127 | FRAME_DONE, /* Finished grabbing, but not been synced yet */ | ||
| 128 | FRAME_ERROR, /* Something bad happened while processing */ | ||
| 129 | }; | ||
| 130 | |||
| 131 | enum { | ||
| 132 | FMT_BAYER, | ||
| 133 | FMT_JANGGU, | ||
| 134 | }; | ||
| 135 | |||
| 136 | enum { | ||
| 137 | BUFFER_UNUSED, | ||
| 138 | BUFFER_READY, | ||
| 139 | BUFFER_BUSY, | ||
| 140 | BUFFER_DONE, | ||
| 141 | }; | ||
| 142 | |||
| 143 | struct se401_scratch { | ||
| 144 | unsigned char *data; | ||
| 145 | volatile int state; | ||
| 146 | int offset; | ||
| 147 | int length; | ||
| 148 | }; | ||
| 149 | |||
| 150 | struct se401_frame { | ||
| 151 | unsigned char *data; /* Frame buffer */ | ||
| 152 | |||
| 153 | volatile int grabstate; /* State of grabbing */ | ||
| 154 | |||
| 155 | unsigned char *curline; | ||
| 156 | int curlinepix; | ||
| 157 | int curpix; | ||
| 158 | }; | ||
| 159 | |||
| 160 | struct usb_se401 { | ||
| 161 | struct video_device vdev; | ||
| 162 | |||
| 163 | /* Device structure */ | ||
| 164 | struct usb_device *dev; | ||
| 165 | |||
| 166 | unsigned char iface; | ||
| 167 | |||
| 168 | char *camera_name; | ||
| 169 | |||
| 170 | int change; | ||
| 171 | int brightness; | ||
| 172 | int hue; | ||
| 173 | int rgain; | ||
| 174 | int ggain; | ||
| 175 | int bgain; | ||
| 176 | int expose_h; | ||
| 177 | int expose_m; | ||
| 178 | int expose_l; | ||
| 179 | int resetlevel; | ||
| 180 | |||
| 181 | int enhance; | ||
| 182 | |||
| 183 | int format; | ||
| 184 | int sizes; | ||
| 185 | int *width; | ||
| 186 | int *height; | ||
| 187 | int cwidth; /* current width */ | ||
| 188 | int cheight; /* current height */ | ||
| 189 | int palette; | ||
| 190 | int maxframesize; | ||
| 191 | int cframesize; /* current framesize */ | ||
| 192 | |||
| 193 | struct mutex lock; | ||
| 194 | int user; /* user count for exclusive use */ | ||
| 195 | int removed; /* device disconnected */ | ||
| 196 | |||
| 197 | int streaming; /* Are we streaming video? */ | ||
| 198 | |||
| 199 | char *fbuf; /* Videodev buffer area */ | ||
| 200 | |||
| 201 | struct urb *urb[SE401_NUMSBUF]; | ||
| 202 | struct urb *inturb; | ||
| 203 | |||
| 204 | int button; | ||
| 205 | int buttonpressed; | ||
| 206 | |||
| 207 | int curframe; /* Current receiving frame */ | ||
| 208 | struct se401_frame frame[SE401_NUMFRAMES]; | ||
| 209 | int readcount; | ||
| 210 | int framecount; | ||
| 211 | int error; | ||
| 212 | int dropped; | ||
| 213 | |||
| 214 | int scratch_next; | ||
| 215 | int scratch_use; | ||
| 216 | int scratch_overflow; | ||
| 217 | struct se401_scratch scratch[SE401_NUMSCRATCH]; | ||
| 218 | |||
| 219 | /* Decoder specific data: */ | ||
| 220 | unsigned char vlcdata[SE401_VLCDATALEN]; | ||
| 221 | int vlcdatapos; | ||
| 222 | int bayeroffset; | ||
| 223 | |||
| 224 | struct se401_sbuf sbuf[SE401_NUMSBUF]; | ||
| 225 | |||
| 226 | wait_queue_head_t wq; /* Processes waiting */ | ||
| 227 | |||
| 228 | int nullpackets; | ||
| 229 | }; | ||
| 230 | |||
| 231 | |||
| 232 | |||
| 233 | #endif | ||
| 234 | |||
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h deleted file mode 100644 index 1d70a62b9f23..000000000000 --- a/drivers/usb/media/sn9c102.h +++ /dev/null | |||
| @@ -1,218 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * V4L2 driver for SN9C10x PC Camera Controllers * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2004-2006 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_H_ | ||
| 22 | #define _SN9C102_H_ | ||
| 23 | |||
| 24 | #include <linux/version.h> | ||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <linux/videodev2.h> | ||
| 27 | #include <media/v4l2-common.h> | ||
| 28 | #include <linux/device.h> | ||
| 29 | #include <linux/list.h> | ||
| 30 | #include <linux/spinlock.h> | ||
| 31 | #include <linux/time.h> | ||
| 32 | #include <linux/wait.h> | ||
| 33 | #include <linux/types.h> | ||
| 34 | #include <linux/param.h> | ||
| 35 | #include <linux/rwsem.h> | ||
| 36 | #include <linux/mutex.h> | ||
| 37 | #include <linux/string.h> | ||
| 38 | #include <linux/stddef.h> | ||
| 39 | |||
| 40 | #include "sn9c102_sensor.h" | ||
| 41 | |||
| 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 | |||
| 68 | enum sn9c102_frame_state { | ||
| 69 | F_UNUSED, | ||
| 70 | F_QUEUED, | ||
| 71 | F_GRABBING, | ||
| 72 | F_DONE, | ||
| 73 | F_ERROR, | ||
| 74 | }; | ||
| 75 | |||
| 76 | struct sn9c102_frame_t { | ||
| 77 | void* bufmem; | ||
| 78 | struct v4l2_buffer buf; | ||
| 79 | enum sn9c102_frame_state state; | ||
| 80 | struct list_head frame; | ||
| 81 | unsigned long vma_use_count; | ||
| 82 | }; | ||
| 83 | |||
| 84 | enum sn9c102_dev_state { | ||
| 85 | DEV_INITIALIZED = 0x01, | ||
| 86 | DEV_DISCONNECTED = 0x02, | ||
| 87 | DEV_MISCONFIGURED = 0x04, | ||
| 88 | }; | ||
| 89 | |||
| 90 | enum sn9c102_io_method { | ||
| 91 | IO_NONE, | ||
| 92 | IO_READ, | ||
| 93 | IO_MMAP, | ||
| 94 | }; | ||
| 95 | |||
| 96 | enum sn9c102_stream_state { | ||
| 97 | STREAM_OFF, | ||
| 98 | STREAM_INTERRUPT, | ||
| 99 | STREAM_ON, | ||
| 100 | }; | ||
| 101 | |||
| 102 | typedef char sn9c103_sof_header_t[18]; | ||
| 103 | typedef char sn9c102_sof_header_t[12]; | ||
| 104 | typedef char sn9c102_eof_header_t[4]; | ||
| 105 | |||
| 106 | struct sn9c102_sysfs_attr { | ||
| 107 | u8 reg, i2c_reg; | ||
| 108 | sn9c103_sof_header_t frame_header; | ||
| 109 | }; | ||
| 110 | |||
| 111 | struct sn9c102_module_param { | ||
| 112 | u8 force_munmap; | ||
| 113 | u16 frame_timeout; | ||
| 114 | }; | ||
| 115 | |||
| 116 | static DEFINE_MUTEX(sn9c102_sysfs_lock); | ||
| 117 | static DECLARE_RWSEM(sn9c102_disconnect); | ||
| 118 | |||
| 119 | struct sn9c102_device { | ||
| 120 | struct video_device* v4ldev; | ||
| 121 | |||
| 122 | enum sn9c102_bridge bridge; | ||
| 123 | struct sn9c102_sensor sensor; | ||
| 124 | |||
| 125 | struct usb_device* usbdev; | ||
| 126 | struct urb* urb[SN9C102_URBS]; | ||
| 127 | void* transfer_buffer[SN9C102_URBS]; | ||
| 128 | u8* control_buffer; | ||
| 129 | |||
| 130 | struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES]; | ||
| 131 | struct list_head inqueue, outqueue; | ||
| 132 | u32 frame_count, nbuffers, nreadbuffers; | ||
| 133 | |||
| 134 | enum sn9c102_io_method io; | ||
| 135 | enum sn9c102_stream_state stream; | ||
| 136 | |||
| 137 | struct v4l2_jpegcompression compression; | ||
| 138 | |||
| 139 | struct sn9c102_sysfs_attr sysfs; | ||
| 140 | sn9c103_sof_header_t sof_header; | ||
| 141 | u16 reg[63]; | ||
| 142 | |||
| 143 | struct sn9c102_module_param module_param; | ||
| 144 | |||
| 145 | enum sn9c102_dev_state state; | ||
| 146 | u8 users; | ||
| 147 | |||
| 148 | struct mutex dev_mutex, fileop_mutex; | ||
| 149 | spinlock_t queue_lock; | ||
| 150 | wait_queue_head_t open, wait_frame, wait_stream; | ||
| 151 | }; | ||
| 152 | |||
| 153 | /*****************************************************************************/ | ||
| 154 | |||
| 155 | struct sn9c102_device* | ||
| 156 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id) | ||
| 157 | { | ||
| 158 | if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) | ||
| 159 | return cam; | ||
| 160 | |||
| 161 | return NULL; | ||
| 162 | } | ||
| 163 | |||
| 164 | |||
| 165 | void | ||
| 166 | sn9c102_attach_sensor(struct sn9c102_device* cam, | ||
| 167 | struct sn9c102_sensor* sensor) | ||
| 168 | { | ||
| 169 | memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor)); | ||
| 170 | } | ||
| 171 | |||
| 172 | /*****************************************************************************/ | ||
| 173 | |||
| 174 | #undef DBG | ||
| 175 | #undef KDBG | ||
| 176 | #ifdef SN9C102_DEBUG | ||
| 177 | # define DBG(level, fmt, args...) \ | ||
| 178 | do { \ | ||
| 179 | if (debug >= (level)) { \ | ||
| 180 | if ((level) == 1) \ | ||
| 181 | dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
| 182 | else if ((level) == 2) \ | ||
| 183 | dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
| 184 | else if ((level) >= 3) \ | ||
| 185 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
| 186 | __FUNCTION__, __LINE__ , ## args); \ | ||
| 187 | } \ | ||
| 188 | } while (0) | ||
| 189 | # define V4LDBG(level, name, cmd) \ | ||
| 190 | do { \ | ||
| 191 | if (debug >= (level)) \ | ||
| 192 | v4l_print_ioctl(name, cmd); \ | ||
| 193 | } while (0) | ||
| 194 | # define KDBG(level, fmt, args...) \ | ||
| 195 | do { \ | ||
| 196 | if (debug >= (level)) { \ | ||
| 197 | if ((level) == 1 || (level) == 2) \ | ||
| 198 | pr_info("sn9c102: " fmt "\n", ## args); \ | ||
| 199 | else if ((level) == 3) \ | ||
| 200 | pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
| 201 | __LINE__ , ## args); \ | ||
| 202 | } \ | ||
| 203 | } while (0) | ||
| 204 | #else | ||
| 205 | # define DBG(level, fmt, args...) do {;} while(0) | ||
| 206 | # define V4LDBG(level, name, cmd) do {;} while(0) | ||
| 207 | # define KDBG(level, fmt, args...) do {;} while(0) | ||
| 208 | #endif | ||
| 209 | |||
| 210 | #undef PDBG | ||
| 211 | #define PDBG(fmt, args...) \ | ||
| 212 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
| 213 | __FUNCTION__, __LINE__ , ## args) | ||
| 214 | |||
| 215 | #undef PDBGG | ||
| 216 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ | ||
| 217 | |||
| 218 | #endif /* _SN9C102_H_ */ | ||
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c deleted file mode 100644 index 4c6cc6395723..000000000000 --- a/drivers/usb/media/sn9c102_core.c +++ /dev/null | |||
| @@ -1,2919 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * V4L2 driver for SN9C10x PC Camera Controllers * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2004-2006 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 | #include <linux/module.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/param.h> | ||
| 25 | #include <linux/moduleparam.h> | ||
| 26 | #include <linux/errno.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/device.h> | ||
| 29 | #include <linux/fs.h> | ||
| 30 | #include <linux/delay.h> | ||
| 31 | #include <linux/compiler.h> | ||
| 32 | #include <linux/ioctl.h> | ||
| 33 | #include <linux/poll.h> | ||
| 34 | #include <linux/stat.h> | ||
| 35 | #include <linux/mm.h> | ||
| 36 | #include <linux/vmalloc.h> | ||
| 37 | #include <linux/page-flags.h> | ||
| 38 | #include <linux/byteorder/generic.h> | ||
| 39 | #include <asm/page.h> | ||
| 40 | #include <asm/uaccess.h> | ||
| 41 | |||
| 42 | #include "sn9c102.h" | ||
| 43 | |||
| 44 | /*****************************************************************************/ | ||
| 45 | |||
| 46 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers" | ||
| 47 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" | ||
| 48 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
| 49 | #define SN9C102_MODULE_LICENSE "GPL" | ||
| 50 | #define SN9C102_MODULE_VERSION "1:1.27" | ||
| 51 | #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 27) | ||
| 52 | |||
| 53 | /*****************************************************************************/ | ||
| 54 | |||
| 55 | MODULE_DEVICE_TABLE(usb, sn9c102_id_table); | ||
| 56 | |||
| 57 | MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); | ||
| 58 | MODULE_DESCRIPTION(SN9C102_MODULE_NAME); | ||
| 59 | MODULE_VERSION(SN9C102_MODULE_VERSION); | ||
| 60 | MODULE_LICENSE(SN9C102_MODULE_LICENSE); | ||
| 61 | |||
| 62 | static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1}; | ||
| 63 | module_param_array(video_nr, short, NULL, 0444); | ||
| 64 | MODULE_PARM_DESC(video_nr, | ||
| 65 | "\n<-1|n[,...]> Specify V4L2 minor mode number." | ||
| 66 | "\n -1 = use next available (default)" | ||
| 67 | "\n n = use minor number n (integer >= 0)" | ||
| 68 | "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES) | ||
| 69 | " cameras this way." | ||
| 70 | "\nFor example:" | ||
| 71 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
| 72 | "\nthe second camera and use auto for the first" | ||
| 73 | "\none and for every other camera." | ||
| 74 | "\n"); | ||
| 75 | |||
| 76 | static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = | ||
| 77 | SN9C102_FORCE_MUNMAP}; | ||
| 78 | module_param_array(force_munmap, bool, NULL, 0444); | ||
| 79 | MODULE_PARM_DESC(force_munmap, | ||
| 80 | "\n<0|1[,...]> Force the application to unmap previously" | ||
| 81 | "\nmapped buffer memory before calling any VIDIOC_S_CROP or" | ||
| 82 | "\nVIDIOC_S_FMT ioctl's. Not all the applications support" | ||
| 83 | "\nthis feature. This parameter is specific for each" | ||
| 84 | "\ndetected camera." | ||
| 85 | "\n 0 = do not force memory unmapping" | ||
| 86 | "\n 1 = force memory unmapping (save memory)" | ||
| 87 | "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." | ||
| 88 | "\n"); | ||
| 89 | |||
| 90 | static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] = | ||
| 91 | SN9C102_FRAME_TIMEOUT}; | ||
| 92 | module_param_array(frame_timeout, uint, NULL, 0644); | ||
| 93 | MODULE_PARM_DESC(frame_timeout, | ||
| 94 | "\n<n[,...]> Timeout for a video frame in seconds." | ||
| 95 | "\nThis parameter is specific for each detected camera." | ||
| 96 | "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." | ||
| 97 | "\n"); | ||
| 98 | |||
| 99 | #ifdef SN9C102_DEBUG | ||
| 100 | static unsigned short debug = SN9C102_DEBUG_LEVEL; | ||
| 101 | module_param(debug, ushort, 0644); | ||
| 102 | MODULE_PARM_DESC(debug, | ||
| 103 | "\n<n> Debugging information level, from 0 to 3:" | ||
| 104 | "\n0 = none (use carefully)" | ||
| 105 | "\n1 = critical errors" | ||
| 106 | "\n2 = significant informations" | ||
| 107 | "\n3 = more verbose messages" | ||
| 108 | "\nLevel 3 is useful for testing only, when only " | ||
| 109 | "one device is used." | ||
| 110 | "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." | ||
| 111 | "\n"); | ||
| 112 | #endif | ||
| 113 | |||
| 114 | /*****************************************************************************/ | ||
| 115 | |||
| 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 | ||
| 135 | sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, | ||
| 136 | enum sn9c102_io_method io) | ||
| 137 | { | ||
| 138 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | ||
| 139 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | ||
| 140 | const size_t imagesize = cam->module_param.force_munmap || | ||
| 141 | io == IO_READ ? | ||
| 142 | (p->width * p->height * p->priv) / 8 : | ||
| 143 | (r->width * r->height * p->priv) / 8; | ||
| 144 | void* buff = NULL; | ||
| 145 | u32 i; | ||
| 146 | |||
| 147 | if (count > SN9C102_MAX_FRAMES) | ||
| 148 | count = SN9C102_MAX_FRAMES; | ||
| 149 | |||
| 150 | cam->nbuffers = count; | ||
| 151 | while (cam->nbuffers > 0) { | ||
| 152 | if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) | ||
| 153 | break; | ||
| 154 | cam->nbuffers--; | ||
| 155 | } | ||
| 156 | |||
| 157 | for (i = 0; i < cam->nbuffers; i++) { | ||
| 158 | cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); | ||
| 159 | cam->frame[i].buf.index = i; | ||
| 160 | cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); | ||
| 161 | cam->frame[i].buf.length = imagesize; | ||
| 162 | cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 163 | cam->frame[i].buf.sequence = 0; | ||
| 164 | cam->frame[i].buf.field = V4L2_FIELD_NONE; | ||
| 165 | cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; | ||
| 166 | cam->frame[i].buf.flags = 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | return cam->nbuffers; | ||
| 170 | } | ||
| 171 | |||
| 172 | |||
| 173 | static void sn9c102_release_buffers(struct sn9c102_device* cam) | ||
| 174 | { | ||
| 175 | if (cam->nbuffers) { | ||
| 176 | vfree(cam->frame[0].bufmem); | ||
| 177 | cam->nbuffers = 0; | ||
| 178 | } | ||
| 179 | cam->frame_current = NULL; | ||
| 180 | } | ||
| 181 | |||
| 182 | |||
| 183 | static void sn9c102_empty_framequeues(struct sn9c102_device* cam) | ||
| 184 | { | ||
| 185 | u32 i; | ||
| 186 | |||
| 187 | INIT_LIST_HEAD(&cam->inqueue); | ||
| 188 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 189 | |||
| 190 | for (i = 0; i < SN9C102_MAX_FRAMES; i++) { | ||
| 191 | cam->frame[i].state = F_UNUSED; | ||
| 192 | cam->frame[i].buf.bytesused = 0; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | static void sn9c102_requeue_outqueue(struct sn9c102_device* cam) | ||
| 198 | { | ||
| 199 | struct sn9c102_frame_t *i; | ||
| 200 | |||
| 201 | list_for_each_entry(i, &cam->outqueue, frame) { | ||
| 202 | i->state = F_QUEUED; | ||
| 203 | list_add(&i->frame, &cam->inqueue); | ||
| 204 | } | ||
| 205 | |||
| 206 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 207 | } | ||
| 208 | |||
| 209 | |||
| 210 | static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) | ||
| 211 | { | ||
| 212 | unsigned long lock_flags; | ||
| 213 | u32 i; | ||
| 214 | |||
| 215 | for (i = 0; i < cam->nbuffers; i++) | ||
| 216 | if (cam->frame[i].state == F_UNUSED) { | ||
| 217 | cam->frame[i].state = F_QUEUED; | ||
| 218 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 219 | list_add_tail(&cam->frame[i].frame, &cam->inqueue); | ||
| 220 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | /*****************************************************************************/ | ||
| 225 | |||
| 226 | int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index) | ||
| 227 | { | ||
| 228 | struct usb_device* udev = cam->usbdev; | ||
| 229 | int i, res; | ||
| 230 | |||
| 231 | if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg)) | ||
| 232 | return -1; | ||
| 233 | |||
| 234 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
| 235 | index, 0, buff, sizeof(buff), | ||
| 236 | SN9C102_CTRL_TIMEOUT*sizeof(buff)); | ||
| 237 | if (res < 0) { | ||
| 238 | DBG(3, "Failed to write registers (index 0x%02X, error %d)", | ||
| 239 | index, res); | ||
| 240 | return -1; | ||
| 241 | } | ||
| 242 | |||
| 243 | for (i = 0; i < sizeof(buff); i++) | ||
| 244 | cam->reg[index+i] = buff[i]; | ||
| 245 | |||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | |||
| 250 | int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index) | ||
| 251 | { | ||
| 252 | struct usb_device* udev = cam->usbdev; | ||
| 253 | u8* buff = cam->control_buffer; | ||
| 254 | int res; | ||
| 255 | |||
| 256 | if (index >= ARRAY_SIZE(cam->reg)) | ||
| 257 | return -1; | ||
| 258 | |||
| 259 | *buff = value; | ||
| 260 | |||
| 261 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
| 262 | index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); | ||
| 263 | if (res < 0) { | ||
| 264 | DBG(3, "Failed to write a register (value 0x%02X, index " | ||
| 265 | "0x%02X, error %d)", value, index, res); | ||
| 266 | return -1; | ||
| 267 | } | ||
| 268 | |||
| 269 | cam->reg[index] = value; | ||
| 270 | |||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | |||
| 275 | /* NOTE: reading some registers always returns 0 */ | ||
| 276 | static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index) | ||
| 277 | { | ||
| 278 | struct usb_device* udev = cam->usbdev; | ||
| 279 | u8* buff = cam->control_buffer; | ||
| 280 | int res; | ||
| 281 | |||
| 282 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
| 283 | index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); | ||
| 284 | if (res < 0) | ||
| 285 | DBG(3, "Failed to read a register (index 0x%02X, error %d)", | ||
| 286 | index, res); | ||
| 287 | |||
| 288 | return (res >= 0) ? (int)(*buff) : -1; | ||
| 289 | } | ||
| 290 | |||
| 291 | |||
| 292 | int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index) | ||
| 293 | { | ||
| 294 | if (index >= ARRAY_SIZE(cam->reg)) | ||
| 295 | return -1; | ||
| 296 | |||
| 297 | return cam->reg[index]; | ||
| 298 | } | ||
| 299 | |||
| 300 | |||
| 301 | static int | ||
| 302 | sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor) | ||
| 303 | { | ||
| 304 | int i, r; | ||
| 305 | |||
| 306 | for (i = 1; i <= 5; i++) { | ||
| 307 | r = sn9c102_read_reg(cam, 0x08); | ||
| 308 | if (r < 0) | ||
| 309 | return -EIO; | ||
| 310 | if (r & 0x04) | ||
| 311 | return 0; | ||
| 312 | if (sensor->frequency & SN9C102_I2C_400KHZ) | ||
| 313 | udelay(5*16); | ||
| 314 | else | ||
| 315 | udelay(16*16); | ||
| 316 | } | ||
| 317 | return -EBUSY; | ||
| 318 | } | ||
| 319 | |||
| 320 | |||
| 321 | static int | ||
| 322 | sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, | ||
| 323 | struct sn9c102_sensor* sensor) | ||
| 324 | { | ||
| 325 | int r; | ||
| 326 | r = sn9c102_read_reg(cam, 0x08); | ||
| 327 | return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0; | ||
| 328 | } | ||
| 329 | |||
| 330 | |||
| 331 | static int | ||
| 332 | sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, | ||
| 333 | struct sn9c102_sensor* sensor) | ||
| 334 | { | ||
| 335 | int r; | ||
| 336 | r = sn9c102_read_reg(cam, 0x08); | ||
| 337 | return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | |||
| 341 | int | ||
| 342 | sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, | ||
| 343 | struct sn9c102_sensor* sensor, u8 data0, u8 data1, | ||
| 344 | u8 n, u8 buffer[]) | ||
| 345 | { | ||
| 346 | struct usb_device* udev = cam->usbdev; | ||
| 347 | u8* data = cam->control_buffer; | ||
| 348 | int err = 0, res; | ||
| 349 | |||
| 350 | /* Write cycle */ | ||
| 351 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
| 352 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10; | ||
| 353 | data[1] = data0; /* I2C slave id */ | ||
| 354 | data[2] = data1; /* address */ | ||
| 355 | data[7] = 0x10; | ||
| 356 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
| 357 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
| 358 | if (res < 0) | ||
| 359 | err += res; | ||
| 360 | |||
| 361 | err += sn9c102_i2c_wait(cam, sensor); | ||
| 362 | |||
| 363 | /* Read cycle - n bytes */ | ||
| 364 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
| 365 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | | ||
| 366 | (n << 4) | 0x02; | ||
| 367 | data[1] = data0; | ||
| 368 | data[7] = 0x10; | ||
| 369 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
| 370 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
| 371 | if (res < 0) | ||
| 372 | err += res; | ||
| 373 | |||
| 374 | err += sn9c102_i2c_wait(cam, sensor); | ||
| 375 | |||
| 376 | /* The first read byte will be placed in data[4] */ | ||
| 377 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
| 378 | 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT); | ||
| 379 | if (res < 0) | ||
| 380 | err += res; | ||
| 381 | |||
| 382 | err += sn9c102_i2c_detect_read_error(cam, sensor); | ||
| 383 | |||
| 384 | PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1, | ||
| 385 | data[4]); | ||
| 386 | |||
| 387 | if (err) { | ||
| 388 | DBG(3, "I2C read failed for %s image sensor", sensor->name); | ||
| 389 | return -1; | ||
| 390 | } | ||
| 391 | |||
| 392 | if (buffer) | ||
| 393 | memcpy(buffer, data, sizeof(buffer)); | ||
| 394 | |||
| 395 | return (int)data[4]; | ||
| 396 | } | ||
| 397 | |||
| 398 | |||
| 399 | int | ||
| 400 | sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, | ||
| 401 | struct sn9c102_sensor* sensor, u8 n, u8 data0, | ||
| 402 | u8 data1, u8 data2, u8 data3, u8 data4, u8 data5) | ||
| 403 | { | ||
| 404 | struct usb_device* udev = cam->usbdev; | ||
| 405 | u8* data = cam->control_buffer; | ||
| 406 | int err = 0, res; | ||
| 407 | |||
| 408 | /* Write cycle. It usually is address + value */ | ||
| 409 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
| 410 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | ||
| 411 | | ((n - 1) << 4); | ||
| 412 | data[1] = data0; | ||
| 413 | data[2] = data1; | ||
| 414 | data[3] = data2; | ||
| 415 | data[4] = data3; | ||
| 416 | data[5] = data4; | ||
| 417 | data[6] = data5; | ||
| 418 | data[7] = 0x14; | ||
| 419 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
| 420 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
| 421 | if (res < 0) | ||
| 422 | err += res; | ||
| 423 | |||
| 424 | err += sn9c102_i2c_wait(cam, sensor); | ||
| 425 | err += sn9c102_i2c_detect_write_error(cam, sensor); | ||
| 426 | |||
| 427 | if (err) | ||
| 428 | DBG(3, "I2C write failed for %s image sensor", sensor->name); | ||
| 429 | |||
| 430 | PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " | ||
| 431 | "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X", | ||
| 432 | n, data0, data1, data2, data3, data4, data5); | ||
| 433 | |||
| 434 | return err ? -1 : 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | |||
| 438 | int | ||
| 439 | sn9c102_i2c_try_read(struct sn9c102_device* cam, | ||
| 440 | struct sn9c102_sensor* sensor, u8 address) | ||
| 441 | { | ||
| 442 | return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id, | ||
| 443 | address, 1, NULL); | ||
| 444 | } | ||
| 445 | |||
| 446 | |||
| 447 | int | ||
| 448 | sn9c102_i2c_try_write(struct sn9c102_device* cam, | ||
| 449 | struct sn9c102_sensor* sensor, u8 address, u8 value) | ||
| 450 | { | ||
| 451 | return sn9c102_i2c_try_raw_write(cam, sensor, 3, | ||
| 452 | sensor->i2c_slave_id, address, | ||
| 453 | value, 0, 0, 0); | ||
| 454 | } | ||
| 455 | |||
| 456 | |||
| 457 | int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address) | ||
| 458 | { | ||
| 459 | return sn9c102_i2c_try_read(cam, &cam->sensor, address); | ||
| 460 | } | ||
| 461 | |||
| 462 | |||
| 463 | int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) | ||
| 464 | { | ||
| 465 | return sn9c102_i2c_try_write(cam, &cam->sensor, address, value); | ||
| 466 | } | ||
| 467 | |||
| 468 | /*****************************************************************************/ | ||
| 469 | |||
| 470 | static void* | ||
| 471 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
| 472 | { | ||
| 473 | size_t soflen = 0, i; | ||
| 474 | u8 j, n = 0; | ||
| 475 | |||
| 476 | switch (cam->bridge) { | ||
| 477 | case BRIDGE_SN9C101: | ||
| 478 | case BRIDGE_SN9C102: | ||
| 479 | soflen = sizeof(sn9c102_sof_header_t); | ||
| 480 | n = sizeof(sn9c102_sof_header) / soflen; | ||
| 481 | break; | ||
| 482 | case BRIDGE_SN9C103: | ||
| 483 | soflen = sizeof(sn9c103_sof_header_t); | ||
| 484 | n = sizeof(sn9c103_sof_header) / soflen; | ||
| 485 | } | ||
| 486 | |||
| 487 | for (i = 0; (len >= soflen) && (i <= len - soflen); i++) | ||
| 488 | for (j = 0; j < n; j++) | ||
| 489 | /* The invariable part of the header is 6 bytes long */ | ||
| 490 | if ((cam->bridge != BRIDGE_SN9C103 && | ||
| 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 */ | ||
| 496 | return mem + i + soflen; | ||
| 497 | } | ||
| 498 | |||
| 499 | return NULL; | ||
| 500 | } | ||
| 501 | |||
| 502 | |||
| 503 | static void* | ||
| 504 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
| 505 | { | ||
| 506 | size_t eoflen = sizeof(sn9c102_eof_header_t), i; | ||
| 507 | unsigned j, n = sizeof(sn9c102_eof_header) / eoflen; | ||
| 508 | |||
| 509 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 510 | return NULL; /* EOF header does not exist in compressed data */ | ||
| 511 | |||
| 512 | for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++) | ||
| 513 | for (j = 0; j < n; j++) | ||
| 514 | if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen)) | ||
| 515 | return mem + i; | ||
| 516 | |||
| 517 | return NULL; | ||
| 518 | } | ||
| 519 | |||
| 520 | |||
| 521 | static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) | ||
| 522 | { | ||
| 523 | struct sn9c102_device* cam = urb->context; | ||
| 524 | struct sn9c102_frame_t** f; | ||
| 525 | size_t imagesize, soflen; | ||
| 526 | u8 i; | ||
| 527 | int err = 0; | ||
| 528 | |||
| 529 | if (urb->status == -ENOENT) | ||
| 530 | return; | ||
| 531 | |||
| 532 | f = &cam->frame_current; | ||
| 533 | |||
| 534 | if (cam->stream == STREAM_INTERRUPT) { | ||
| 535 | cam->stream = STREAM_OFF; | ||
| 536 | if ((*f)) | ||
| 537 | (*f)->state = F_QUEUED; | ||
| 538 | DBG(3, "Stream interrupted"); | ||
| 539 | wake_up(&cam->wait_stream); | ||
| 540 | } | ||
| 541 | |||
| 542 | if (cam->state & DEV_DISCONNECTED) | ||
| 543 | return; | ||
| 544 | |||
| 545 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 546 | wake_up_interruptible(&cam->wait_frame); | ||
| 547 | return; | ||
| 548 | } | ||
| 549 | |||
| 550 | if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) | ||
| 551 | goto resubmit_urb; | ||
| 552 | |||
| 553 | if (!(*f)) | ||
| 554 | (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t, | ||
| 555 | frame); | ||
| 556 | |||
| 557 | imagesize = (cam->sensor.pix_format.width * | ||
| 558 | cam->sensor.pix_format.height * | ||
| 559 | cam->sensor.pix_format.priv) / 8; | ||
| 560 | |||
| 561 | soflen = (cam->bridge) == BRIDGE_SN9C103 ? | ||
| 562 | sizeof(sn9c103_sof_header_t) : | ||
| 563 | sizeof(sn9c102_sof_header_t); | ||
| 564 | |||
| 565 | for (i = 0; i < urb->number_of_packets; i++) { | ||
| 566 | unsigned int img, len, status; | ||
| 567 | void *pos, *sof, *eof; | ||
| 568 | |||
| 569 | len = urb->iso_frame_desc[i].actual_length; | ||
| 570 | status = urb->iso_frame_desc[i].status; | ||
| 571 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
| 572 | |||
| 573 | if (status) { | ||
| 574 | DBG(3, "Error in isochronous frame"); | ||
| 575 | (*f)->state = F_ERROR; | ||
| 576 | continue; | ||
| 577 | } | ||
| 578 | |||
| 579 | PDBGG("Isochrnous frame: length %u, #%u i", len, i); | ||
| 580 | |||
| 581 | redo: | ||
| 582 | sof = sn9c102_find_sof_header(cam, pos, len); | ||
| 583 | if (likely(!sof)) { | ||
| 584 | eof = sn9c102_find_eof_header(cam, pos, len); | ||
| 585 | if ((*f)->state == F_GRABBING) { | ||
| 586 | end_of_frame: | ||
| 587 | img = len; | ||
| 588 | |||
| 589 | if (eof) | ||
| 590 | img = (eof > pos) ? eof - pos - 1 : 0; | ||
| 591 | |||
| 592 | if ((*f)->buf.bytesused+img > imagesize) { | ||
| 593 | u32 b; | ||
| 594 | b = (*f)->buf.bytesused + img - | ||
| 595 | imagesize; | ||
| 596 | img = imagesize - (*f)->buf.bytesused; | ||
| 597 | DBG(3, "Expected EOF not found: " | ||
| 598 | "video frame cut"); | ||
| 599 | if (eof) | ||
| 600 | DBG(3, "Exceeded limit: +%u " | ||
| 601 | "bytes", (unsigned)(b)); | ||
| 602 | } | ||
| 603 | |||
| 604 | memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, | ||
| 605 | img); | ||
| 606 | |||
| 607 | if ((*f)->buf.bytesused == 0) | ||
| 608 | do_gettimeofday(&(*f)->buf.timestamp); | ||
| 609 | |||
| 610 | (*f)->buf.bytesused += img; | ||
| 611 | |||
| 612 | if ((*f)->buf.bytesused == imagesize || | ||
| 613 | (cam->sensor.pix_format.pixelformat == | ||
| 614 | V4L2_PIX_FMT_SN9C10X && eof)) { | ||
| 615 | u32 b; | ||
| 616 | b = (*f)->buf.bytesused; | ||
| 617 | (*f)->state = F_DONE; | ||
| 618 | (*f)->buf.sequence= ++cam->frame_count; | ||
| 619 | spin_lock(&cam->queue_lock); | ||
| 620 | list_move_tail(&(*f)->frame, | ||
| 621 | &cam->outqueue); | ||
| 622 | if (!list_empty(&cam->inqueue)) | ||
| 623 | (*f) = list_entry( | ||
| 624 | cam->inqueue.next, | ||
| 625 | struct sn9c102_frame_t, | ||
| 626 | frame ); | ||
| 627 | else | ||
| 628 | (*f) = NULL; | ||
| 629 | spin_unlock(&cam->queue_lock); | ||
| 630 | memcpy(cam->sysfs.frame_header, | ||
| 631 | cam->sof_header, soflen); | ||
| 632 | DBG(3, "Video frame captured: %lu " | ||
| 633 | "bytes", (unsigned long)(b)); | ||
| 634 | |||
| 635 | if (!(*f)) | ||
| 636 | goto resubmit_urb; | ||
| 637 | |||
| 638 | } else if (eof) { | ||
| 639 | (*f)->state = F_ERROR; | ||
| 640 | DBG(3, "Not expected EOF after %lu " | ||
| 641 | "bytes of image data", | ||
| 642 | (unsigned long) | ||
| 643 | ((*f)->buf.bytesused)); | ||
| 644 | } | ||
| 645 | |||
| 646 | if (sof) /* (1) */ | ||
| 647 | goto start_of_frame; | ||
| 648 | |||
| 649 | } else if (eof) { | ||
| 650 | DBG(3, "EOF without SOF"); | ||
| 651 | continue; | ||
| 652 | |||
| 653 | } else { | ||
| 654 | PDBGG("Ignoring pointless isochronous frame"); | ||
| 655 | continue; | ||
| 656 | } | ||
| 657 | |||
| 658 | } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) { | ||
| 659 | start_of_frame: | ||
| 660 | (*f)->state = F_GRABBING; | ||
| 661 | (*f)->buf.bytesused = 0; | ||
| 662 | len -= (sof - pos); | ||
| 663 | pos = sof; | ||
| 664 | DBG(3, "SOF detected: new video frame"); | ||
| 665 | if (len) | ||
| 666 | goto redo; | ||
| 667 | |||
| 668 | } else if ((*f)->state == F_GRABBING) { | ||
| 669 | eof = sn9c102_find_eof_header(cam, pos, len); | ||
| 670 | if (eof && eof < sof) | ||
| 671 | goto end_of_frame; /* (1) */ | ||
| 672 | else { | ||
| 673 | if (cam->sensor.pix_format.pixelformat == | ||
| 674 | V4L2_PIX_FMT_SN9C10X) { | ||
| 675 | eof = sof - soflen; | ||
| 676 | goto end_of_frame; | ||
| 677 | } else { | ||
| 678 | DBG(3, "SOF before expected EOF after " | ||
| 679 | "%lu bytes of image data", | ||
| 680 | (unsigned long) | ||
| 681 | ((*f)->buf.bytesused)); | ||
| 682 | goto start_of_frame; | ||
| 683 | } | ||
| 684 | } | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | resubmit_urb: | ||
| 689 | urb->dev = cam->usbdev; | ||
| 690 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 691 | if (err < 0 && err != -EPERM) { | ||
| 692 | cam->state |= DEV_MISCONFIGURED; | ||
| 693 | DBG(1, "usb_submit_urb() failed"); | ||
| 694 | } | ||
| 695 | |||
| 696 | wake_up_interruptible(&cam->wait_frame); | ||
| 697 | } | ||
| 698 | |||
| 699 | |||
| 700 | static int sn9c102_start_transfer(struct sn9c102_device* cam) | ||
| 701 | { | ||
| 702 | struct usb_device *udev = cam->usbdev; | ||
| 703 | struct urb* urb; | ||
| 704 | const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512, | ||
| 705 | 680, 800, 900, 1023}; | ||
| 706 | const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512, | ||
| 707 | 680, 800, 900, 1003}; | ||
| 708 | const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ? | ||
| 709 | sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] : | ||
| 710 | sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING]; | ||
| 711 | s8 i, j; | ||
| 712 | int err = 0; | ||
| 713 | |||
| 714 | for (i = 0; i < SN9C102_URBS; i++) { | ||
| 715 | cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz, | ||
| 716 | GFP_KERNEL); | ||
| 717 | if (!cam->transfer_buffer[i]) { | ||
| 718 | err = -ENOMEM; | ||
| 719 | DBG(1, "Not enough memory"); | ||
| 720 | goto free_buffers; | ||
| 721 | } | ||
| 722 | } | ||
| 723 | |||
| 724 | for (i = 0; i < SN9C102_URBS; i++) { | ||
| 725 | urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL); | ||
| 726 | cam->urb[i] = urb; | ||
| 727 | if (!urb) { | ||
| 728 | err = -ENOMEM; | ||
| 729 | DBG(1, "usb_alloc_urb() failed"); | ||
| 730 | goto free_urbs; | ||
| 731 | } | ||
| 732 | urb->dev = udev; | ||
| 733 | urb->context = cam; | ||
| 734 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
| 735 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 736 | urb->number_of_packets = SN9C102_ISO_PACKETS; | ||
| 737 | urb->complete = sn9c102_urb_complete; | ||
| 738 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
| 739 | urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS; | ||
| 740 | urb->interval = 1; | ||
| 741 | for (j = 0; j < SN9C102_ISO_PACKETS; j++) { | ||
| 742 | urb->iso_frame_desc[j].offset = psz * j; | ||
| 743 | urb->iso_frame_desc[j].length = psz; | ||
| 744 | } | ||
| 745 | } | ||
| 746 | |||
| 747 | /* Enable video */ | ||
| 748 | if (!(cam->reg[0x01] & 0x04)) { | ||
| 749 | err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01); | ||
| 750 | if (err) { | ||
| 751 | err = -EIO; | ||
| 752 | DBG(1, "I/O hardware error"); | ||
| 753 | goto free_urbs; | ||
| 754 | } | ||
| 755 | } | ||
| 756 | |||
| 757 | err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING); | ||
| 758 | if (err) { | ||
| 759 | DBG(1, "usb_set_interface() failed"); | ||
| 760 | goto free_urbs; | ||
| 761 | } | ||
| 762 | |||
| 763 | cam->frame_current = NULL; | ||
| 764 | |||
| 765 | for (i = 0; i < SN9C102_URBS; i++) { | ||
| 766 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
| 767 | if (err) { | ||
| 768 | for (j = i-1; j >= 0; j--) | ||
| 769 | usb_kill_urb(cam->urb[j]); | ||
| 770 | DBG(1, "usb_submit_urb() failed, error %d", err); | ||
| 771 | goto free_urbs; | ||
| 772 | } | ||
| 773 | } | ||
| 774 | |||
| 775 | return 0; | ||
| 776 | |||
| 777 | free_urbs: | ||
| 778 | for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) | ||
| 779 | usb_free_urb(cam->urb[i]); | ||
| 780 | |||
| 781 | free_buffers: | ||
| 782 | for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++) | ||
| 783 | kfree(cam->transfer_buffer[i]); | ||
| 784 | |||
| 785 | return err; | ||
| 786 | } | ||
| 787 | |||
| 788 | |||
| 789 | static int sn9c102_stop_transfer(struct sn9c102_device* cam) | ||
| 790 | { | ||
| 791 | struct usb_device *udev = cam->usbdev; | ||
| 792 | s8 i; | ||
| 793 | int err = 0; | ||
| 794 | |||
| 795 | if (cam->state & DEV_DISCONNECTED) | ||
| 796 | return 0; | ||
| 797 | |||
| 798 | for (i = SN9C102_URBS-1; i >= 0; i--) { | ||
| 799 | usb_kill_urb(cam->urb[i]); | ||
| 800 | usb_free_urb(cam->urb[i]); | ||
| 801 | kfree(cam->transfer_buffer[i]); | ||
| 802 | } | ||
| 803 | |||
| 804 | err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
| 805 | if (err) | ||
| 806 | DBG(3, "usb_set_interface() failed"); | ||
| 807 | |||
| 808 | return err; | ||
| 809 | } | ||
| 810 | |||
| 811 | |||
| 812 | static int sn9c102_stream_interrupt(struct sn9c102_device* cam) | ||
| 813 | { | ||
| 814 | long timeout; | ||
| 815 | |||
| 816 | cam->stream = STREAM_INTERRUPT; | ||
| 817 | timeout = wait_event_timeout(cam->wait_stream, | ||
| 818 | (cam->stream == STREAM_OFF) || | ||
| 819 | (cam->state & DEV_DISCONNECTED), | ||
| 820 | SN9C102_URB_TIMEOUT); | ||
| 821 | if (cam->state & DEV_DISCONNECTED) | ||
| 822 | return -ENODEV; | ||
| 823 | else if (cam->stream != STREAM_OFF) { | ||
| 824 | cam->state |= DEV_MISCONFIGURED; | ||
| 825 | DBG(1, "URB timeout reached. The camera is misconfigured. " | ||
| 826 | "To use it, close and open /dev/video%d again.", | ||
| 827 | cam->v4ldev->minor); | ||
| 828 | return -EIO; | ||
| 829 | } | ||
| 830 | |||
| 831 | return 0; | ||
| 832 | } | ||
| 833 | |||
| 834 | /*****************************************************************************/ | ||
| 835 | |||
| 836 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
| 837 | static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count) | ||
| 838 | { | ||
| 839 | char str[5]; | ||
| 840 | char* endp; | ||
| 841 | unsigned long val; | ||
| 842 | |||
| 843 | if (len < 4) { | ||
| 844 | strncpy(str, buff, len); | ||
| 845 | str[len+1] = '\0'; | ||
| 846 | } else { | ||
| 847 | strncpy(str, buff, 4); | ||
| 848 | str[4] = '\0'; | ||
| 849 | } | ||
| 850 | |||
| 851 | val = simple_strtoul(str, &endp, 0); | ||
| 852 | |||
| 853 | *count = 0; | ||
| 854 | if (val <= 0xff) | ||
| 855 | *count = (ssize_t)(endp - str); | ||
| 856 | if ((*count) && (len == *count+1) && (buff[*count] == '\n')) | ||
| 857 | *count += 1; | ||
| 858 | |||
| 859 | return (u8)val; | ||
| 860 | } | ||
| 861 | |||
| 862 | /* | ||
| 863 | NOTE 1: being inside one of the following methods implies that the v4l | ||
| 864 | device exists for sure (see kobjects and reference counters) | ||
| 865 | NOTE 2: buffers are PAGE_SIZE long | ||
| 866 | */ | ||
| 867 | |||
| 868 | static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) | ||
| 869 | { | ||
| 870 | struct sn9c102_device* cam; | ||
| 871 | ssize_t count; | ||
| 872 | |||
| 873 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
| 874 | return -ERESTARTSYS; | ||
| 875 | |||
| 876 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 877 | if (!cam) { | ||
| 878 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 879 | return -ENODEV; | ||
| 880 | } | ||
| 881 | |||
| 882 | count = sprintf(buf, "%u\n", cam->sysfs.reg); | ||
| 883 | |||
| 884 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 885 | |||
| 886 | return count; | ||
| 887 | } | ||
| 888 | |||
| 889 | |||
| 890 | static ssize_t | ||
| 891 | sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) | ||
| 892 | { | ||
| 893 | struct sn9c102_device* cam; | ||
| 894 | u8 index; | ||
| 895 | ssize_t count; | ||
| 896 | |||
| 897 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
| 898 | return -ERESTARTSYS; | ||
| 899 | |||
| 900 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 901 | if (!cam) { | ||
| 902 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 903 | return -ENODEV; | ||
| 904 | } | ||
| 905 | |||
| 906 | index = sn9c102_strtou8(buf, len, &count); | ||
| 907 | if (index > 0x1f || !count) { | ||
| 908 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 909 | return -EINVAL; | ||
| 910 | } | ||
| 911 | |||
| 912 | cam->sysfs.reg = index; | ||
| 913 | |||
| 914 | DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg); | ||
| 915 | DBG(3, "Written bytes: %zd", count); | ||
| 916 | |||
| 917 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 918 | |||
| 919 | return count; | ||
| 920 | } | ||
| 921 | |||
| 922 | |||
| 923 | static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) | ||
| 924 | { | ||
| 925 | struct sn9c102_device* cam; | ||
| 926 | ssize_t count; | ||
| 927 | int val; | ||
| 928 | |||
| 929 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
| 930 | return -ERESTARTSYS; | ||
| 931 | |||
| 932 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 933 | if (!cam) { | ||
| 934 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 935 | return -ENODEV; | ||
| 936 | } | ||
| 937 | |||
| 938 | if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { | ||
| 939 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 940 | return -EIO; | ||
| 941 | } | ||
| 942 | |||
| 943 | count = sprintf(buf, "%d\n", val); | ||
| 944 | |||
| 945 | DBG(3, "Read bytes: %zd", count); | ||
| 946 | |||
| 947 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 948 | |||
| 949 | return count; | ||
| 950 | } | ||
| 951 | |||
| 952 | |||
| 953 | static ssize_t | ||
| 954 | sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) | ||
| 955 | { | ||
| 956 | struct sn9c102_device* cam; | ||
| 957 | u8 value; | ||
| 958 | ssize_t count; | ||
| 959 | int err; | ||
| 960 | |||
| 961 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
| 962 | return -ERESTARTSYS; | ||
| 963 | |||
| 964 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 965 | if (!cam) { | ||
| 966 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 967 | return -ENODEV; | ||
| 968 | } | ||
| 969 | |||
| 970 | value = sn9c102_strtou8(buf, len, &count); | ||
| 971 | if (!count) { | ||
| 972 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 973 | return -EINVAL; | ||
| 974 | } | ||
| 975 | |||
| 976 | err = sn9c102_write_reg(cam, value, cam->sysfs.reg); | ||
| 977 | if (err) { | ||
| 978 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 979 | return -EIO; | ||
| 980 | } | ||
| 981 | |||
| 982 | DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X", | ||
| 983 | cam->sysfs.reg, value); | ||
| 984 | DBG(3, "Written bytes: %zd", count); | ||
| 985 | |||
| 986 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 987 | |||
| 988 | return count; | ||
| 989 | } | ||
| 990 | |||
| 991 | |||
| 992 | static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) | ||
| 993 | { | ||
| 994 | struct sn9c102_device* cam; | ||
| 995 | ssize_t count; | ||
| 996 | |||
| 997 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
| 998 | return -ERESTARTSYS; | ||
| 999 | |||
| 1000 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 1001 | if (!cam) { | ||
| 1002 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1003 | return -ENODEV; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); | ||
| 1007 | |||
| 1008 | DBG(3, "Read bytes: %zd", count); | ||
| 1009 | |||
| 1010 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1011 | |||
| 1012 | return count; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | |||
| 1016 | static ssize_t | ||
| 1017 | sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) | ||
| 1018 | { | ||
| 1019 | struct sn9c102_device* cam; | ||
| 1020 | u8 index; | ||
| 1021 | ssize_t count; | ||
| 1022 | |||
| 1023 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
| 1024 | return -ERESTARTSYS; | ||
| 1025 | |||
| 1026 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 1027 | if (!cam) { | ||
| 1028 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1029 | return -ENODEV; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | index = sn9c102_strtou8(buf, len, &count); | ||
| 1033 | if (!count) { | ||
| 1034 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1035 | return -EINVAL; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | cam->sysfs.i2c_reg = index; | ||
| 1039 | |||
| 1040 | DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); | ||
| 1041 | DBG(3, "Written bytes: %zd", count); | ||
| 1042 | |||
| 1043 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1044 | |||
| 1045 | return count; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | |||
| 1049 | static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) | ||
| 1050 | { | ||
| 1051 | struct sn9c102_device* cam; | ||
| 1052 | ssize_t count; | ||
| 1053 | int val; | ||
| 1054 | |||
| 1055 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
| 1056 | return -ERESTARTSYS; | ||
| 1057 | |||
| 1058 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 1059 | if (!cam) { | ||
| 1060 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1061 | return -ENODEV; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) { | ||
| 1065 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1066 | return -ENOSYS; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { | ||
| 1070 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1071 | return -EIO; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | count = sprintf(buf, "%d\n", val); | ||
| 1075 | |||
| 1076 | DBG(3, "Read bytes: %zd", count); | ||
| 1077 | |||
| 1078 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1079 | |||
| 1080 | return count; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | |||
| 1084 | static ssize_t | ||
| 1085 | sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) | ||
| 1086 | { | ||
| 1087 | struct sn9c102_device* cam; | ||
| 1088 | u8 value; | ||
| 1089 | ssize_t count; | ||
| 1090 | int err; | ||
| 1091 | |||
| 1092 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
| 1093 | return -ERESTARTSYS; | ||
| 1094 | |||
| 1095 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 1096 | if (!cam) { | ||
| 1097 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1098 | return -ENODEV; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) { | ||
| 1102 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1103 | return -ENOSYS; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | value = sn9c102_strtou8(buf, len, &count); | ||
| 1107 | if (!count) { | ||
| 1108 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1109 | return -EINVAL; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); | ||
| 1113 | if (err) { | ||
| 1114 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1115 | return -EIO; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", | ||
| 1119 | cam->sysfs.i2c_reg, value); | ||
| 1120 | DBG(3, "Written bytes: %zd", count); | ||
| 1121 | |||
| 1122 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1123 | |||
| 1124 | return count; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | |||
| 1128 | static ssize_t | ||
| 1129 | sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) | ||
| 1130 | { | ||
| 1131 | struct sn9c102_device* cam; | ||
| 1132 | enum sn9c102_bridge bridge; | ||
| 1133 | ssize_t res = 0; | ||
| 1134 | u8 value; | ||
| 1135 | ssize_t count; | ||
| 1136 | |||
| 1137 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
| 1138 | return -ERESTARTSYS; | ||
| 1139 | |||
| 1140 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 1141 | if (!cam) { | ||
| 1142 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1143 | return -ENODEV; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | bridge = cam->bridge; | ||
| 1147 | |||
| 1148 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1149 | |||
| 1150 | value = sn9c102_strtou8(buf, len, &count); | ||
| 1151 | if (!count) | ||
| 1152 | return -EINVAL; | ||
| 1153 | |||
| 1154 | switch (bridge) { | ||
| 1155 | case BRIDGE_SN9C101: | ||
| 1156 | case BRIDGE_SN9C102: | ||
| 1157 | if (value > 0x0f) | ||
| 1158 | return -EINVAL; | ||
| 1159 | if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) | ||
| 1160 | res = sn9c102_store_val(cd, buf, len); | ||
| 1161 | break; | ||
| 1162 | case BRIDGE_SN9C103: | ||
| 1163 | if (value > 0x7f) | ||
| 1164 | return -EINVAL; | ||
| 1165 | if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0) | ||
| 1166 | res = sn9c102_store_val(cd, buf, len); | ||
| 1167 | break; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | return res; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | |||
| 1174 | static ssize_t | ||
| 1175 | sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) | ||
| 1176 | { | ||
| 1177 | ssize_t res = 0; | ||
| 1178 | u8 value; | ||
| 1179 | ssize_t count; | ||
| 1180 | |||
| 1181 | value = sn9c102_strtou8(buf, len, &count); | ||
| 1182 | if (!count || value > 0x7f) | ||
| 1183 | return -EINVAL; | ||
| 1184 | |||
| 1185 | if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0) | ||
| 1186 | res = sn9c102_store_val(cd, buf, len); | ||
| 1187 | |||
| 1188 | return res; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | |||
| 1192 | static ssize_t | ||
| 1193 | sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) | ||
| 1194 | { | ||
| 1195 | ssize_t res = 0; | ||
| 1196 | u8 value; | ||
| 1197 | ssize_t count; | ||
| 1198 | |||
| 1199 | value = sn9c102_strtou8(buf, len, &count); | ||
| 1200 | if (!count || value > 0x7f) | ||
| 1201 | return -EINVAL; | ||
| 1202 | |||
| 1203 | if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0) | ||
| 1204 | res = sn9c102_store_val(cd, buf, len); | ||
| 1205 | |||
| 1206 | return res; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | |||
| 1210 | static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) | ||
| 1211 | { | ||
| 1212 | struct sn9c102_device* cam; | ||
| 1213 | ssize_t count; | ||
| 1214 | |||
| 1215 | cam = video_get_drvdata(to_video_device(cd)); | ||
| 1216 | if (!cam) | ||
| 1217 | return -ENODEV; | ||
| 1218 | |||
| 1219 | count = sizeof(cam->sysfs.frame_header); | ||
| 1220 | memcpy(buf, cam->sysfs.frame_header, count); | ||
| 1221 | |||
| 1222 | DBG(3, "Frame header, read bytes: %zd", count); | ||
| 1223 | |||
| 1224 | return count; | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | |||
| 1228 | static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, | ||
| 1229 | sn9c102_show_reg, sn9c102_store_reg); | ||
| 1230 | static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, | ||
| 1231 | sn9c102_show_val, sn9c102_store_val); | ||
| 1232 | static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, | ||
| 1233 | sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); | ||
| 1234 | static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, | ||
| 1235 | sn9c102_show_i2c_val, sn9c102_store_i2c_val); | ||
| 1236 | static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); | ||
| 1237 | static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); | ||
| 1238 | static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); | ||
| 1239 | static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, | ||
| 1240 | sn9c102_show_frame_header, NULL); | ||
| 1241 | |||
| 1242 | |||
| 1243 | static void sn9c102_create_sysfs(struct sn9c102_device* cam) | ||
| 1244 | { | ||
| 1245 | struct video_device *v4ldev = cam->v4ldev; | ||
| 1246 | |||
| 1247 | video_device_create_file(v4ldev, &class_device_attr_reg); | ||
| 1248 | video_device_create_file(v4ldev, &class_device_attr_val); | ||
| 1249 | video_device_create_file(v4ldev, &class_device_attr_frame_header); | ||
| 1250 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) | ||
| 1251 | video_device_create_file(v4ldev, &class_device_attr_green); | ||
| 1252 | else if (cam->bridge == BRIDGE_SN9C103) { | ||
| 1253 | video_device_create_file(v4ldev, &class_device_attr_blue); | ||
| 1254 | video_device_create_file(v4ldev, &class_device_attr_red); | ||
| 1255 | } | ||
| 1256 | if (cam->sensor.sysfs_ops) { | ||
| 1257 | video_device_create_file(v4ldev, &class_device_attr_i2c_reg); | ||
| 1258 | video_device_create_file(v4ldev, &class_device_attr_i2c_val); | ||
| 1259 | } | ||
| 1260 | } | ||
| 1261 | #endif /* CONFIG_VIDEO_ADV_DEBUG */ | ||
| 1262 | |||
| 1263 | /*****************************************************************************/ | ||
| 1264 | |||
| 1265 | static int | ||
| 1266 | sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix) | ||
| 1267 | { | ||
| 1268 | int err = 0; | ||
| 1269 | |||
| 1270 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 1271 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18); | ||
| 1272 | else | ||
| 1273 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18); | ||
| 1274 | |||
| 1275 | return err ? -EIO : 0; | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | |||
| 1279 | static int | ||
| 1280 | sn9c102_set_compression(struct sn9c102_device* cam, | ||
| 1281 | struct v4l2_jpegcompression* compression) | ||
| 1282 | { | ||
| 1283 | int err = 0; | ||
| 1284 | |||
| 1285 | if (compression->quality == 0) | ||
| 1286 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17); | ||
| 1287 | else if (compression->quality == 1) | ||
| 1288 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17); | ||
| 1289 | |||
| 1290 | return err ? -EIO : 0; | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | |||
| 1294 | static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale) | ||
| 1295 | { | ||
| 1296 | u8 r = 0; | ||
| 1297 | int err = 0; | ||
| 1298 | |||
| 1299 | if (scale == 1) | ||
| 1300 | r = cam->reg[0x18] & 0xcf; | ||
| 1301 | else if (scale == 2) { | ||
| 1302 | r = cam->reg[0x18] & 0xcf; | ||
| 1303 | r |= 0x10; | ||
| 1304 | } else if (scale == 4) | ||
| 1305 | r = cam->reg[0x18] | 0x20; | ||
| 1306 | |||
| 1307 | err += sn9c102_write_reg(cam, r, 0x18); | ||
| 1308 | if (err) | ||
| 1309 | return -EIO; | ||
| 1310 | |||
| 1311 | PDBGG("Scaling factor: %u", scale); | ||
| 1312 | |||
| 1313 | return 0; | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | |||
| 1317 | static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) | ||
| 1318 | { | ||
| 1319 | struct sn9c102_sensor* s = &cam->sensor; | ||
| 1320 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), | ||
| 1321 | v_start = (u8)(rect->top - s->cropcap.bounds.top), | ||
| 1322 | h_size = (u8)(rect->width / 16), | ||
| 1323 | v_size = (u8)(rect->height / 16); | ||
| 1324 | int err = 0; | ||
| 1325 | |||
| 1326 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
| 1327 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
| 1328 | err += sn9c102_write_reg(cam, h_size, 0x15); | ||
| 1329 | err += sn9c102_write_reg(cam, v_size, 0x16); | ||
| 1330 | if (err) | ||
| 1331 | return -EIO; | ||
| 1332 | |||
| 1333 | PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " | ||
| 1334 | "%u %u %u %u", h_start, v_start, h_size, v_size); | ||
| 1335 | |||
| 1336 | return 0; | ||
| 1337 | } | ||
| 1338 | |||
| 1339 | |||
| 1340 | static int sn9c102_init(struct sn9c102_device* cam) | ||
| 1341 | { | ||
| 1342 | struct sn9c102_sensor* s = &cam->sensor; | ||
| 1343 | struct v4l2_control ctrl; | ||
| 1344 | struct v4l2_queryctrl *qctrl; | ||
| 1345 | struct v4l2_rect* rect; | ||
| 1346 | u8 i = 0; | ||
| 1347 | int err = 0; | ||
| 1348 | |||
| 1349 | if (!(cam->state & DEV_INITIALIZED)) { | ||
| 1350 | init_waitqueue_head(&cam->open); | ||
| 1351 | qctrl = s->qctrl; | ||
| 1352 | rect = &(s->cropcap.defrect); | ||
| 1353 | } else { /* use current values */ | ||
| 1354 | qctrl = s->_qctrl; | ||
| 1355 | rect = &(s->_rect); | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); | ||
| 1359 | err += sn9c102_set_crop(cam, rect); | ||
| 1360 | if (err) | ||
| 1361 | return err; | ||
| 1362 | |||
| 1363 | if (s->init) { | ||
| 1364 | err = s->init(cam); | ||
| 1365 | if (err) { | ||
| 1366 | DBG(3, "Sensor initialization failed"); | ||
| 1367 | return err; | ||
| 1368 | } | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | if (!(cam->state & DEV_INITIALIZED)) | ||
| 1372 | cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1; | ||
| 1373 | else | ||
| 1374 | err += sn9c102_set_compression(cam, &cam->compression); | ||
| 1375 | err += sn9c102_set_pix_format(cam, &s->pix_format); | ||
| 1376 | if (s->set_pix_format) | ||
| 1377 | err += s->set_pix_format(cam, &s->pix_format); | ||
| 1378 | if (err) | ||
| 1379 | return err; | ||
| 1380 | |||
| 1381 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 1382 | DBG(3, "Compressed video format is active, quality %d", | ||
| 1383 | cam->compression.quality); | ||
| 1384 | else | ||
| 1385 | DBG(3, "Uncompressed video format is active"); | ||
| 1386 | |||
| 1387 | if (s->set_crop) | ||
| 1388 | if ((err = s->set_crop(cam, rect))) { | ||
| 1389 | DBG(3, "set_crop() failed"); | ||
| 1390 | return err; | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | if (s->set_ctrl) { | ||
| 1394 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1395 | if (s->qctrl[i].id != 0 && | ||
| 1396 | !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { | ||
| 1397 | ctrl.id = s->qctrl[i].id; | ||
| 1398 | ctrl.value = qctrl[i].default_value; | ||
| 1399 | err = s->set_ctrl(cam, &ctrl); | ||
| 1400 | if (err) { | ||
| 1401 | DBG(3, "Set %s control failed", | ||
| 1402 | s->qctrl[i].name); | ||
| 1403 | return err; | ||
| 1404 | } | ||
| 1405 | DBG(3, "Image sensor supports '%s' control", | ||
| 1406 | s->qctrl[i].name); | ||
| 1407 | } | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | if (!(cam->state & DEV_INITIALIZED)) { | ||
| 1411 | mutex_init(&cam->fileop_mutex); | ||
| 1412 | spin_lock_init(&cam->queue_lock); | ||
| 1413 | init_waitqueue_head(&cam->wait_frame); | ||
| 1414 | init_waitqueue_head(&cam->wait_stream); | ||
| 1415 | cam->nreadbuffers = 2; | ||
| 1416 | memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); | ||
| 1417 | memcpy(&(s->_rect), &(s->cropcap.defrect), | ||
| 1418 | sizeof(struct v4l2_rect)); | ||
| 1419 | cam->state |= DEV_INITIALIZED; | ||
| 1420 | } | ||
| 1421 | |||
| 1422 | DBG(2, "Initialization succeeded"); | ||
| 1423 | return 0; | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | |||
| 1427 | static void sn9c102_release_resources(struct sn9c102_device* cam) | ||
| 1428 | { | ||
| 1429 | mutex_lock(&sn9c102_sysfs_lock); | ||
| 1430 | |||
| 1431 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); | ||
| 1432 | video_set_drvdata(cam->v4ldev, NULL); | ||
| 1433 | video_unregister_device(cam->v4ldev); | ||
| 1434 | |||
| 1435 | usb_put_dev(cam->usbdev); | ||
| 1436 | |||
| 1437 | mutex_unlock(&sn9c102_sysfs_lock); | ||
| 1438 | |||
| 1439 | kfree(cam->control_buffer); | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | /*****************************************************************************/ | ||
| 1443 | |||
| 1444 | static int sn9c102_open(struct inode* inode, struct file* filp) | ||
| 1445 | { | ||
| 1446 | struct sn9c102_device* cam; | ||
| 1447 | int err = 0; | ||
| 1448 | |||
| 1449 | /* | ||
| 1450 | This is the only safe way to prevent race conditions with | ||
| 1451 | disconnect | ||
| 1452 | */ | ||
| 1453 | if (!down_read_trylock(&sn9c102_disconnect)) | ||
| 1454 | return -ERESTARTSYS; | ||
| 1455 | |||
| 1456 | cam = video_get_drvdata(video_devdata(filp)); | ||
| 1457 | |||
| 1458 | if (mutex_lock_interruptible(&cam->dev_mutex)) { | ||
| 1459 | up_read(&sn9c102_disconnect); | ||
| 1460 | return -ERESTARTSYS; | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | if (cam->users) { | ||
| 1464 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); | ||
| 1465 | if ((filp->f_flags & O_NONBLOCK) || | ||
| 1466 | (filp->f_flags & O_NDELAY)) { | ||
| 1467 | err = -EWOULDBLOCK; | ||
| 1468 | goto out; | ||
| 1469 | } | ||
| 1470 | mutex_unlock(&cam->dev_mutex); | ||
| 1471 | err = wait_event_interruptible_exclusive(cam->open, | ||
| 1472 | cam->state & DEV_DISCONNECTED | ||
| 1473 | || !cam->users); | ||
| 1474 | if (err) { | ||
| 1475 | up_read(&sn9c102_disconnect); | ||
| 1476 | return err; | ||
| 1477 | } | ||
| 1478 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1479 | up_read(&sn9c102_disconnect); | ||
| 1480 | return -ENODEV; | ||
| 1481 | } | ||
| 1482 | mutex_lock(&cam->dev_mutex); | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | |||
| 1486 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 1487 | err = sn9c102_init(cam); | ||
| 1488 | if (err) { | ||
| 1489 | DBG(1, "Initialization failed again. " | ||
| 1490 | "I will retry on next open()."); | ||
| 1491 | goto out; | ||
| 1492 | } | ||
| 1493 | cam->state &= ~DEV_MISCONFIGURED; | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | if ((err = sn9c102_start_transfer(cam))) | ||
| 1497 | goto out; | ||
| 1498 | |||
| 1499 | filp->private_data = cam; | ||
| 1500 | cam->users++; | ||
| 1501 | cam->io = IO_NONE; | ||
| 1502 | cam->stream = STREAM_OFF; | ||
| 1503 | cam->nbuffers = 0; | ||
| 1504 | cam->frame_count = 0; | ||
| 1505 | sn9c102_empty_framequeues(cam); | ||
| 1506 | |||
| 1507 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); | ||
| 1508 | |||
| 1509 | out: | ||
| 1510 | mutex_unlock(&cam->dev_mutex); | ||
| 1511 | up_read(&sn9c102_disconnect); | ||
| 1512 | return err; | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | |||
| 1516 | static int sn9c102_release(struct inode* inode, struct file* filp) | ||
| 1517 | { | ||
| 1518 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1519 | |||
| 1520 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ | ||
| 1521 | |||
| 1522 | sn9c102_stop_transfer(cam); | ||
| 1523 | |||
| 1524 | sn9c102_release_buffers(cam); | ||
| 1525 | |||
| 1526 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1527 | sn9c102_release_resources(cam); | ||
| 1528 | mutex_unlock(&cam->dev_mutex); | ||
| 1529 | kfree(cam); | ||
| 1530 | return 0; | ||
| 1531 | } | ||
| 1532 | |||
| 1533 | cam->users--; | ||
| 1534 | wake_up_interruptible_nr(&cam->open, 1); | ||
| 1535 | |||
| 1536 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); | ||
| 1537 | |||
| 1538 | mutex_unlock(&cam->dev_mutex); | ||
| 1539 | |||
| 1540 | return 0; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | |||
| 1544 | static ssize_t | ||
| 1545 | sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | ||
| 1546 | { | ||
| 1547 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1548 | struct sn9c102_frame_t* f, * i; | ||
| 1549 | unsigned long lock_flags; | ||
| 1550 | long timeout; | ||
| 1551 | int err = 0; | ||
| 1552 | |||
| 1553 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 1554 | return -ERESTARTSYS; | ||
| 1555 | |||
| 1556 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1557 | DBG(1, "Device not present"); | ||
| 1558 | mutex_unlock(&cam->fileop_mutex); | ||
| 1559 | return -ENODEV; | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 1563 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 1564 | "again."); | ||
| 1565 | mutex_unlock(&cam->fileop_mutex); | ||
| 1566 | return -EIO; | ||
| 1567 | } | ||
| 1568 | |||
| 1569 | if (cam->io == IO_MMAP) { | ||
| 1570 | DBG(3, "Close and open the device again to choose " | ||
| 1571 | "the read method"); | ||
| 1572 | mutex_unlock(&cam->fileop_mutex); | ||
| 1573 | return -EINVAL; | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | if (cam->io == IO_NONE) { | ||
| 1577 | if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { | ||
| 1578 | DBG(1, "read() failed, not enough memory"); | ||
| 1579 | mutex_unlock(&cam->fileop_mutex); | ||
| 1580 | return -ENOMEM; | ||
| 1581 | } | ||
| 1582 | cam->io = IO_READ; | ||
| 1583 | cam->stream = STREAM_ON; | ||
| 1584 | } | ||
| 1585 | |||
| 1586 | if (list_empty(&cam->inqueue)) { | ||
| 1587 | if (!list_empty(&cam->outqueue)) | ||
| 1588 | sn9c102_empty_framequeues(cam); | ||
| 1589 | sn9c102_queue_unusedframes(cam); | ||
| 1590 | } | ||
| 1591 | |||
| 1592 | if (!count) { | ||
| 1593 | mutex_unlock(&cam->fileop_mutex); | ||
| 1594 | return 0; | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | if (list_empty(&cam->outqueue)) { | ||
| 1598 | if (filp->f_flags & O_NONBLOCK) { | ||
| 1599 | mutex_unlock(&cam->fileop_mutex); | ||
| 1600 | return -EAGAIN; | ||
| 1601 | } | ||
| 1602 | timeout = wait_event_interruptible_timeout | ||
| 1603 | ( cam->wait_frame, | ||
| 1604 | (!list_empty(&cam->outqueue)) || | ||
| 1605 | (cam->state & DEV_DISCONNECTED) || | ||
| 1606 | (cam->state & DEV_MISCONFIGURED), | ||
| 1607 | cam->module_param.frame_timeout * | ||
| 1608 | 1000 * msecs_to_jiffies(1) ); | ||
| 1609 | if (timeout < 0) { | ||
| 1610 | mutex_unlock(&cam->fileop_mutex); | ||
| 1611 | return timeout; | ||
| 1612 | } | ||
| 1613 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1614 | mutex_unlock(&cam->fileop_mutex); | ||
| 1615 | return -ENODEV; | ||
| 1616 | } | ||
| 1617 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) { | ||
| 1618 | mutex_unlock(&cam->fileop_mutex); | ||
| 1619 | return -EIO; | ||
| 1620 | } | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); | ||
| 1624 | |||
| 1625 | if (count > f->buf.bytesused) | ||
| 1626 | count = f->buf.bytesused; | ||
| 1627 | |||
| 1628 | if (copy_to_user(buf, f->bufmem, count)) { | ||
| 1629 | err = -EFAULT; | ||
| 1630 | goto exit; | ||
| 1631 | } | ||
| 1632 | *f_pos += count; | ||
| 1633 | |||
| 1634 | exit: | ||
| 1635 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 1636 | list_for_each_entry(i, &cam->outqueue, frame) | ||
| 1637 | i->state = F_UNUSED; | ||
| 1638 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 1639 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 1640 | |||
| 1641 | sn9c102_queue_unusedframes(cam); | ||
| 1642 | |||
| 1643 | PDBGG("Frame #%lu, bytes read: %zu", | ||
| 1644 | (unsigned long)f->buf.index, count); | ||
| 1645 | |||
| 1646 | mutex_unlock(&cam->fileop_mutex); | ||
| 1647 | |||
| 1648 | return count; | ||
| 1649 | } | ||
| 1650 | |||
| 1651 | |||
| 1652 | static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) | ||
| 1653 | { | ||
| 1654 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1655 | struct sn9c102_frame_t* f; | ||
| 1656 | unsigned long lock_flags; | ||
| 1657 | unsigned int mask = 0; | ||
| 1658 | |||
| 1659 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 1660 | return POLLERR; | ||
| 1661 | |||
| 1662 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1663 | DBG(1, "Device not present"); | ||
| 1664 | goto error; | ||
| 1665 | } | ||
| 1666 | |||
| 1667 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 1668 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 1669 | "again."); | ||
| 1670 | goto error; | ||
| 1671 | } | ||
| 1672 | |||
| 1673 | if (cam->io == IO_NONE) { | ||
| 1674 | if (!sn9c102_request_buffers(cam, cam->nreadbuffers, | ||
| 1675 | IO_READ)) { | ||
| 1676 | DBG(1, "poll() failed, not enough memory"); | ||
| 1677 | goto error; | ||
| 1678 | } | ||
| 1679 | cam->io = IO_READ; | ||
| 1680 | cam->stream = STREAM_ON; | ||
| 1681 | } | ||
| 1682 | |||
| 1683 | if (cam->io == IO_READ) { | ||
| 1684 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 1685 | list_for_each_entry(f, &cam->outqueue, frame) | ||
| 1686 | f->state = F_UNUSED; | ||
| 1687 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 1688 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 1689 | sn9c102_queue_unusedframes(cam); | ||
| 1690 | } | ||
| 1691 | |||
| 1692 | poll_wait(filp, &cam->wait_frame, wait); | ||
| 1693 | |||
| 1694 | if (!list_empty(&cam->outqueue)) | ||
| 1695 | mask |= POLLIN | POLLRDNORM; | ||
| 1696 | |||
| 1697 | mutex_unlock(&cam->fileop_mutex); | ||
| 1698 | |||
| 1699 | return mask; | ||
| 1700 | |||
| 1701 | error: | ||
| 1702 | mutex_unlock(&cam->fileop_mutex); | ||
| 1703 | return POLLERR; | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | |||
| 1707 | static void sn9c102_vm_open(struct vm_area_struct* vma) | ||
| 1708 | { | ||
| 1709 | struct sn9c102_frame_t* f = vma->vm_private_data; | ||
| 1710 | f->vma_use_count++; | ||
| 1711 | } | ||
| 1712 | |||
| 1713 | |||
| 1714 | static void sn9c102_vm_close(struct vm_area_struct* vma) | ||
| 1715 | { | ||
| 1716 | /* NOTE: buffers are not freed here */ | ||
| 1717 | struct sn9c102_frame_t* f = vma->vm_private_data; | ||
| 1718 | f->vma_use_count--; | ||
| 1719 | } | ||
| 1720 | |||
| 1721 | |||
| 1722 | static struct vm_operations_struct sn9c102_vm_ops = { | ||
| 1723 | .open = sn9c102_vm_open, | ||
| 1724 | .close = sn9c102_vm_close, | ||
| 1725 | }; | ||
| 1726 | |||
| 1727 | |||
| 1728 | static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) | ||
| 1729 | { | ||
| 1730 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1731 | unsigned long size = vma->vm_end - vma->vm_start, | ||
| 1732 | start = vma->vm_start; | ||
| 1733 | void *pos; | ||
| 1734 | u32 i; | ||
| 1735 | |||
| 1736 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 1737 | return -ERESTARTSYS; | ||
| 1738 | |||
| 1739 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1740 | DBG(1, "Device not present"); | ||
| 1741 | mutex_unlock(&cam->fileop_mutex); | ||
| 1742 | return -ENODEV; | ||
| 1743 | } | ||
| 1744 | |||
| 1745 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 1746 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 1747 | "again."); | ||
| 1748 | mutex_unlock(&cam->fileop_mutex); | ||
| 1749 | return -EIO; | ||
| 1750 | } | ||
| 1751 | |||
| 1752 | if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | ||
| 1753 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | ||
| 1754 | mutex_unlock(&cam->fileop_mutex); | ||
| 1755 | return -EINVAL; | ||
| 1756 | } | ||
| 1757 | |||
| 1758 | for (i = 0; i < cam->nbuffers; i++) { | ||
| 1759 | if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) | ||
| 1760 | break; | ||
| 1761 | } | ||
| 1762 | if (i == cam->nbuffers) { | ||
| 1763 | mutex_unlock(&cam->fileop_mutex); | ||
| 1764 | return -EINVAL; | ||
| 1765 | } | ||
| 1766 | |||
| 1767 | vma->vm_flags |= VM_IO; | ||
| 1768 | vma->vm_flags |= VM_RESERVED; | ||
| 1769 | |||
| 1770 | pos = cam->frame[i].bufmem; | ||
| 1771 | while (size > 0) { /* size is page-aligned */ | ||
| 1772 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { | ||
| 1773 | mutex_unlock(&cam->fileop_mutex); | ||
| 1774 | return -EAGAIN; | ||
| 1775 | } | ||
| 1776 | start += PAGE_SIZE; | ||
| 1777 | pos += PAGE_SIZE; | ||
| 1778 | size -= PAGE_SIZE; | ||
| 1779 | } | ||
| 1780 | |||
| 1781 | vma->vm_ops = &sn9c102_vm_ops; | ||
| 1782 | vma->vm_private_data = &cam->frame[i]; | ||
| 1783 | |||
| 1784 | sn9c102_vm_open(vma); | ||
| 1785 | |||
| 1786 | mutex_unlock(&cam->fileop_mutex); | ||
| 1787 | |||
| 1788 | return 0; | ||
| 1789 | } | ||
| 1790 | |||
| 1791 | /*****************************************************************************/ | ||
| 1792 | |||
| 1793 | static int | ||
| 1794 | sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg) | ||
| 1795 | { | ||
| 1796 | struct v4l2_capability cap = { | ||
| 1797 | .driver = "sn9c102", | ||
| 1798 | .version = SN9C102_MODULE_VERSION_CODE, | ||
| 1799 | .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
| 1800 | V4L2_CAP_STREAMING, | ||
| 1801 | }; | ||
| 1802 | |||
| 1803 | strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); | ||
| 1804 | if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) | ||
| 1805 | strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, | ||
| 1806 | sizeof(cap.bus_info)); | ||
| 1807 | |||
| 1808 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
| 1809 | return -EFAULT; | ||
| 1810 | |||
| 1811 | return 0; | ||
| 1812 | } | ||
| 1813 | |||
| 1814 | |||
| 1815 | static int | ||
| 1816 | sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg) | ||
| 1817 | { | ||
| 1818 | struct v4l2_input i; | ||
| 1819 | |||
| 1820 | if (copy_from_user(&i, arg, sizeof(i))) | ||
| 1821 | return -EFAULT; | ||
| 1822 | |||
| 1823 | if (i.index) | ||
| 1824 | return -EINVAL; | ||
| 1825 | |||
| 1826 | memset(&i, 0, sizeof(i)); | ||
| 1827 | strcpy(i.name, "Camera"); | ||
| 1828 | i.type = V4L2_INPUT_TYPE_CAMERA; | ||
| 1829 | |||
| 1830 | if (copy_to_user(arg, &i, sizeof(i))) | ||
| 1831 | return -EFAULT; | ||
| 1832 | |||
| 1833 | return 0; | ||
| 1834 | } | ||
| 1835 | |||
| 1836 | |||
| 1837 | static int | ||
| 1838 | sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg) | ||
| 1839 | { | ||
| 1840 | int index = 0; | ||
| 1841 | |||
| 1842 | if (copy_to_user(arg, &index, sizeof(index))) | ||
| 1843 | return -EFAULT; | ||
| 1844 | |||
| 1845 | return 0; | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | |||
| 1849 | static int | ||
| 1850 | sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg) | ||
| 1851 | { | ||
| 1852 | int index; | ||
| 1853 | |||
| 1854 | if (copy_from_user(&index, arg, sizeof(index))) | ||
| 1855 | return -EFAULT; | ||
| 1856 | |||
| 1857 | if (index != 0) | ||
| 1858 | return -EINVAL; | ||
| 1859 | |||
| 1860 | return 0; | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | |||
| 1864 | static int | ||
| 1865 | sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg) | ||
| 1866 | { | ||
| 1867 | struct sn9c102_sensor* s = &cam->sensor; | ||
| 1868 | struct v4l2_queryctrl qc; | ||
| 1869 | u8 i; | ||
| 1870 | |||
| 1871 | if (copy_from_user(&qc, arg, sizeof(qc))) | ||
| 1872 | return -EFAULT; | ||
| 1873 | |||
| 1874 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1875 | if (qc.id && qc.id == s->qctrl[i].id) { | ||
| 1876 | memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); | ||
| 1877 | if (copy_to_user(arg, &qc, sizeof(qc))) | ||
| 1878 | return -EFAULT; | ||
| 1879 | return 0; | ||
| 1880 | } | ||
| 1881 | |||
| 1882 | return -EINVAL; | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | |||
| 1886 | static int | ||
| 1887 | sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg) | ||
| 1888 | { | ||
| 1889 | struct sn9c102_sensor* s = &cam->sensor; | ||
| 1890 | struct v4l2_control ctrl; | ||
| 1891 | int err = 0; | ||
| 1892 | u8 i; | ||
| 1893 | |||
| 1894 | if (!s->get_ctrl && !s->set_ctrl) | ||
| 1895 | return -EINVAL; | ||
| 1896 | |||
| 1897 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
| 1898 | return -EFAULT; | ||
| 1899 | |||
| 1900 | if (!s->get_ctrl) { | ||
| 1901 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1902 | if (ctrl.id && ctrl.id == s->qctrl[i].id) { | ||
| 1903 | ctrl.value = s->_qctrl[i].default_value; | ||
| 1904 | goto exit; | ||
| 1905 | } | ||
| 1906 | return -EINVAL; | ||
| 1907 | } else | ||
| 1908 | err = s->get_ctrl(cam, &ctrl); | ||
| 1909 | |||
| 1910 | exit: | ||
| 1911 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) | ||
| 1912 | return -EFAULT; | ||
| 1913 | |||
| 1914 | return err; | ||
| 1915 | } | ||
| 1916 | |||
| 1917 | |||
| 1918 | static int | ||
| 1919 | sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg) | ||
| 1920 | { | ||
| 1921 | struct sn9c102_sensor* s = &cam->sensor; | ||
| 1922 | struct v4l2_control ctrl; | ||
| 1923 | u8 i; | ||
| 1924 | int err = 0; | ||
| 1925 | |||
| 1926 | if (!s->set_ctrl) | ||
| 1927 | return -EINVAL; | ||
| 1928 | |||
| 1929 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
| 1930 | return -EFAULT; | ||
| 1931 | |||
| 1932 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1933 | if (ctrl.id == s->qctrl[i].id) { | ||
| 1934 | if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) | ||
| 1935 | return -EINVAL; | ||
| 1936 | if (ctrl.value < s->qctrl[i].minimum || | ||
| 1937 | ctrl.value > s->qctrl[i].maximum) | ||
| 1938 | return -ERANGE; | ||
| 1939 | ctrl.value -= ctrl.value % s->qctrl[i].step; | ||
| 1940 | break; | ||
| 1941 | } | ||
| 1942 | |||
| 1943 | if ((err = s->set_ctrl(cam, &ctrl))) | ||
| 1944 | return err; | ||
| 1945 | |||
| 1946 | s->_qctrl[i].default_value = ctrl.value; | ||
| 1947 | |||
| 1948 | PDBGG("VIDIOC_S_CTRL: id %lu, value %lu", | ||
| 1949 | (unsigned long)ctrl.id, (unsigned long)ctrl.value); | ||
| 1950 | |||
| 1951 | return 0; | ||
| 1952 | } | ||
| 1953 | |||
| 1954 | |||
| 1955 | static int | ||
| 1956 | sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg) | ||
| 1957 | { | ||
| 1958 | struct v4l2_cropcap* cc = &(cam->sensor.cropcap); | ||
| 1959 | |||
| 1960 | cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 1961 | cc->pixelaspect.numerator = 1; | ||
| 1962 | cc->pixelaspect.denominator = 1; | ||
| 1963 | |||
| 1964 | if (copy_to_user(arg, cc, sizeof(*cc))) | ||
| 1965 | return -EFAULT; | ||
| 1966 | |||
| 1967 | return 0; | ||
| 1968 | } | ||
| 1969 | |||
| 1970 | |||
| 1971 | static int | ||
| 1972 | sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg) | ||
| 1973 | { | ||
| 1974 | struct sn9c102_sensor* s = &cam->sensor; | ||
| 1975 | struct v4l2_crop crop = { | ||
| 1976 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
| 1977 | }; | ||
| 1978 | |||
| 1979 | memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); | ||
| 1980 | |||
| 1981 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
| 1982 | return -EFAULT; | ||
| 1983 | |||
| 1984 | return 0; | ||
| 1985 | } | ||
| 1986 | |||
| 1987 | |||
| 1988 | static int | ||
| 1989 | sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) | ||
| 1990 | { | ||
| 1991 | struct sn9c102_sensor* s = &cam->sensor; | ||
| 1992 | struct v4l2_crop crop; | ||
| 1993 | struct v4l2_rect* rect; | ||
| 1994 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
| 1995 | struct v4l2_pix_format* pix_format = &(s->pix_format); | ||
| 1996 | u8 scale; | ||
| 1997 | const enum sn9c102_stream_state stream = cam->stream; | ||
| 1998 | const u32 nbuffers = cam->nbuffers; | ||
| 1999 | u32 i; | ||
| 2000 | int err = 0; | ||
| 2001 | |||
| 2002 | if (copy_from_user(&crop, arg, sizeof(crop))) | ||
| 2003 | return -EFAULT; | ||
| 2004 | |||
| 2005 | rect = &(crop.c); | ||
| 2006 | |||
| 2007 | if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 2008 | return -EINVAL; | ||
| 2009 | |||
| 2010 | if (cam->module_param.force_munmap) | ||
| 2011 | for (i = 0; i < cam->nbuffers; i++) | ||
| 2012 | if (cam->frame[i].vma_use_count) { | ||
| 2013 | DBG(3, "VIDIOC_S_CROP failed. " | ||
| 2014 | "Unmap the buffers first."); | ||
| 2015 | return -EINVAL; | ||
| 2016 | } | ||
| 2017 | |||
| 2018 | /* Preserve R,G or B origin */ | ||
| 2019 | rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; | ||
| 2020 | rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; | ||
| 2021 | |||
| 2022 | if (rect->width < 16) | ||
| 2023 | rect->width = 16; | ||
| 2024 | if (rect->height < 16) | ||
| 2025 | rect->height = 16; | ||
| 2026 | if (rect->width > bounds->width) | ||
| 2027 | rect->width = bounds->width; | ||
| 2028 | if (rect->height > bounds->height) | ||
| 2029 | rect->height = bounds->height; | ||
| 2030 | if (rect->left < bounds->left) | ||
| 2031 | rect->left = bounds->left; | ||
| 2032 | if (rect->top < bounds->top) | ||
| 2033 | rect->top = bounds->top; | ||
| 2034 | if (rect->left + rect->width > bounds->left + bounds->width) | ||
| 2035 | rect->left = bounds->left+bounds->width - rect->width; | ||
| 2036 | if (rect->top + rect->height > bounds->top + bounds->height) | ||
| 2037 | rect->top = bounds->top+bounds->height - rect->height; | ||
| 2038 | |||
| 2039 | rect->width &= ~15L; | ||
| 2040 | rect->height &= ~15L; | ||
| 2041 | |||
| 2042 | if (SN9C102_PRESERVE_IMGSCALE) { | ||
| 2043 | /* Calculate the actual scaling factor */ | ||
| 2044 | u32 a, b; | ||
| 2045 | a = rect->width * rect->height; | ||
| 2046 | b = pix_format->width * pix_format->height; | ||
| 2047 | scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; | ||
| 2048 | } else | ||
| 2049 | scale = 1; | ||
| 2050 | |||
| 2051 | if (cam->stream == STREAM_ON) | ||
| 2052 | if ((err = sn9c102_stream_interrupt(cam))) | ||
| 2053 | return err; | ||
| 2054 | |||
| 2055 | if (copy_to_user(arg, &crop, sizeof(crop))) { | ||
| 2056 | cam->stream = stream; | ||
| 2057 | return -EFAULT; | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
| 2061 | sn9c102_release_buffers(cam); | ||
| 2062 | |||
| 2063 | err = sn9c102_set_crop(cam, rect); | ||
| 2064 | if (s->set_crop) | ||
| 2065 | err += s->set_crop(cam, rect); | ||
| 2066 | err += sn9c102_set_scale(cam, scale); | ||
| 2067 | |||
| 2068 | if (err) { /* atomic, no rollback in ioctl() */ | ||
| 2069 | cam->state |= DEV_MISCONFIGURED; | ||
| 2070 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | ||
| 2071 | "use the camera, close and open /dev/video%d again.", | ||
| 2072 | cam->v4ldev->minor); | ||
| 2073 | return -EIO; | ||
| 2074 | } | ||
| 2075 | |||
| 2076 | s->pix_format.width = rect->width/scale; | ||
| 2077 | s->pix_format.height = rect->height/scale; | ||
| 2078 | memcpy(&(s->_rect), rect, sizeof(*rect)); | ||
| 2079 | |||
| 2080 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
| 2081 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { | ||
| 2082 | cam->state |= DEV_MISCONFIGURED; | ||
| 2083 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | ||
| 2084 | "use the camera, close and open /dev/video%d again.", | ||
| 2085 | cam->v4ldev->minor); | ||
| 2086 | return -ENOMEM; | ||
| 2087 | } | ||
| 2088 | |||
| 2089 | if (cam->io == IO_READ) | ||
| 2090 | sn9c102_empty_framequeues(cam); | ||
| 2091 | else if (cam->module_param.force_munmap) | ||
| 2092 | sn9c102_requeue_outqueue(cam); | ||
| 2093 | |||
| 2094 | cam->stream = stream; | ||
| 2095 | |||
| 2096 | return 0; | ||
| 2097 | } | ||
| 2098 | |||
| 2099 | |||
| 2100 | static int | ||
| 2101 | sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) | ||
| 2102 | { | ||
| 2103 | struct v4l2_fmtdesc fmtd; | ||
| 2104 | |||
| 2105 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) | ||
| 2106 | return -EFAULT; | ||
| 2107 | |||
| 2108 | if (fmtd.index == 0) { | ||
| 2109 | strcpy(fmtd.description, "bayer rgb"); | ||
| 2110 | fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
| 2111 | } else if (fmtd.index == 1) { | ||
| 2112 | strcpy(fmtd.description, "compressed"); | ||
| 2113 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; | ||
| 2114 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; | ||
| 2115 | } else | ||
| 2116 | return -EINVAL; | ||
| 2117 | |||
| 2118 | fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 2119 | memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); | ||
| 2120 | |||
| 2121 | if (copy_to_user(arg, &fmtd, sizeof(fmtd))) | ||
| 2122 | return -EFAULT; | ||
| 2123 | |||
| 2124 | return 0; | ||
| 2125 | } | ||
| 2126 | |||
| 2127 | |||
| 2128 | static int | ||
| 2129 | sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) | ||
| 2130 | { | ||
| 2131 | struct v4l2_format format; | ||
| 2132 | struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); | ||
| 2133 | |||
| 2134 | if (copy_from_user(&format, arg, sizeof(format))) | ||
| 2135 | return -EFAULT; | ||
| 2136 | |||
| 2137 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 2138 | return -EINVAL; | ||
| 2139 | |||
| 2140 | pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X) | ||
| 2141 | ? 0 : (pfmt->width * pfmt->priv) / 8; | ||
| 2142 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | ||
| 2143 | pfmt->field = V4L2_FIELD_NONE; | ||
| 2144 | memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); | ||
| 2145 | |||
| 2146 | if (copy_to_user(arg, &format, sizeof(format))) | ||
| 2147 | return -EFAULT; | ||
| 2148 | |||
| 2149 | return 0; | ||
| 2150 | } | ||
| 2151 | |||
| 2152 | |||
| 2153 | static int | ||
| 2154 | sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | ||
| 2155 | void __user * arg) | ||
| 2156 | { | ||
| 2157 | struct sn9c102_sensor* s = &cam->sensor; | ||
| 2158 | struct v4l2_format format; | ||
| 2159 | struct v4l2_pix_format* pix; | ||
| 2160 | struct v4l2_pix_format* pfmt = &(s->pix_format); | ||
| 2161 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
| 2162 | struct v4l2_rect rect; | ||
| 2163 | u8 scale; | ||
| 2164 | const enum sn9c102_stream_state stream = cam->stream; | ||
| 2165 | const u32 nbuffers = cam->nbuffers; | ||
| 2166 | u32 i; | ||
| 2167 | int err = 0; | ||
| 2168 | |||
| 2169 | if (copy_from_user(&format, arg, sizeof(format))) | ||
| 2170 | return -EFAULT; | ||
| 2171 | |||
| 2172 | pix = &(format.fmt.pix); | ||
| 2173 | |||
| 2174 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 2175 | return -EINVAL; | ||
| 2176 | |||
| 2177 | memcpy(&rect, &(s->_rect), sizeof(rect)); | ||
| 2178 | |||
| 2179 | { /* calculate the actual scaling factor */ | ||
| 2180 | u32 a, b; | ||
| 2181 | a = rect.width * rect.height; | ||
| 2182 | b = pix->width * pix->height; | ||
| 2183 | scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; | ||
| 2184 | } | ||
| 2185 | |||
| 2186 | rect.width = scale * pix->width; | ||
| 2187 | rect.height = scale * pix->height; | ||
| 2188 | |||
| 2189 | if (rect.width < 16) | ||
| 2190 | rect.width = 16; | ||
| 2191 | if (rect.height < 16) | ||
| 2192 | rect.height = 16; | ||
| 2193 | if (rect.width > bounds->left + bounds->width - rect.left) | ||
| 2194 | rect.width = bounds->left + bounds->width - rect.left; | ||
| 2195 | if (rect.height > bounds->top + bounds->height - rect.top) | ||
| 2196 | rect.height = bounds->top + bounds->height - rect.top; | ||
| 2197 | |||
| 2198 | rect.width &= ~15L; | ||
| 2199 | rect.height &= ~15L; | ||
| 2200 | |||
| 2201 | { /* adjust the scaling factor */ | ||
| 2202 | u32 a, b; | ||
| 2203 | a = rect.width * rect.height; | ||
| 2204 | b = pix->width * pix->height; | ||
| 2205 | scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; | ||
| 2206 | } | ||
| 2207 | |||
| 2208 | pix->width = rect.width / scale; | ||
| 2209 | pix->height = rect.height / scale; | ||
| 2210 | |||
| 2211 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && | ||
| 2212 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | ||
| 2213 | pix->pixelformat = pfmt->pixelformat; | ||
| 2214 | pix->priv = pfmt->priv; /* bpp */ | ||
| 2215 | pix->colorspace = pfmt->colorspace; | ||
| 2216 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 2217 | ? 0 : (pix->width * pix->priv) / 8; | ||
| 2218 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); | ||
| 2219 | pix->field = V4L2_FIELD_NONE; | ||
| 2220 | |||
| 2221 | if (cmd == VIDIOC_TRY_FMT) { | ||
| 2222 | if (copy_to_user(arg, &format, sizeof(format))) | ||
| 2223 | return -EFAULT; | ||
| 2224 | return 0; | ||
| 2225 | } | ||
| 2226 | |||
| 2227 | if (cam->module_param.force_munmap) | ||
| 2228 | for (i = 0; i < cam->nbuffers; i++) | ||
| 2229 | if (cam->frame[i].vma_use_count) { | ||
| 2230 | DBG(3, "VIDIOC_S_FMT failed. Unmap the " | ||
| 2231 | "buffers first."); | ||
| 2232 | return -EINVAL; | ||
| 2233 | } | ||
| 2234 | |||
| 2235 | if (cam->stream == STREAM_ON) | ||
| 2236 | if ((err = sn9c102_stream_interrupt(cam))) | ||
| 2237 | return err; | ||
| 2238 | |||
| 2239 | if (copy_to_user(arg, &format, sizeof(format))) { | ||
| 2240 | cam->stream = stream; | ||
| 2241 | return -EFAULT; | ||
| 2242 | } | ||
| 2243 | |||
| 2244 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
| 2245 | sn9c102_release_buffers(cam); | ||
| 2246 | |||
| 2247 | err += sn9c102_set_pix_format(cam, pix); | ||
| 2248 | err += sn9c102_set_crop(cam, &rect); | ||
| 2249 | if (s->set_pix_format) | ||
| 2250 | err += s->set_pix_format(cam, pix); | ||
| 2251 | if (s->set_crop) | ||
| 2252 | err += s->set_crop(cam, &rect); | ||
| 2253 | err += sn9c102_set_scale(cam, scale); | ||
| 2254 | |||
| 2255 | if (err) { /* atomic, no rollback in ioctl() */ | ||
| 2256 | cam->state |= DEV_MISCONFIGURED; | ||
| 2257 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | ||
| 2258 | "use the camera, close and open /dev/video%d again.", | ||
| 2259 | cam->v4ldev->minor); | ||
| 2260 | return -EIO; | ||
| 2261 | } | ||
| 2262 | |||
| 2263 | memcpy(pfmt, pix, sizeof(*pix)); | ||
| 2264 | memcpy(&(s->_rect), &rect, sizeof(rect)); | ||
| 2265 | |||
| 2266 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
| 2267 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { | ||
| 2268 | cam->state |= DEV_MISCONFIGURED; | ||
| 2269 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | ||
| 2270 | "use the camera, close and open /dev/video%d again.", | ||
| 2271 | cam->v4ldev->minor); | ||
| 2272 | return -ENOMEM; | ||
| 2273 | } | ||
| 2274 | |||
| 2275 | if (cam->io == IO_READ) | ||
| 2276 | sn9c102_empty_framequeues(cam); | ||
| 2277 | else if (cam->module_param.force_munmap) | ||
| 2278 | sn9c102_requeue_outqueue(cam); | ||
| 2279 | |||
| 2280 | cam->stream = stream; | ||
| 2281 | |||
| 2282 | return 0; | ||
| 2283 | } | ||
| 2284 | |||
| 2285 | |||
| 2286 | static int | ||
| 2287 | sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg) | ||
| 2288 | { | ||
| 2289 | if (copy_to_user(arg, &cam->compression, | ||
| 2290 | sizeof(cam->compression))) | ||
| 2291 | return -EFAULT; | ||
| 2292 | |||
| 2293 | return 0; | ||
| 2294 | } | ||
| 2295 | |||
| 2296 | |||
| 2297 | static int | ||
| 2298 | sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg) | ||
| 2299 | { | ||
| 2300 | struct v4l2_jpegcompression jc; | ||
| 2301 | const enum sn9c102_stream_state stream = cam->stream; | ||
| 2302 | int err = 0; | ||
| 2303 | |||
| 2304 | if (copy_from_user(&jc, arg, sizeof(jc))) | ||
| 2305 | return -EFAULT; | ||
| 2306 | |||
| 2307 | if (jc.quality != 0 && jc.quality != 1) | ||
| 2308 | return -EINVAL; | ||
| 2309 | |||
| 2310 | if (cam->stream == STREAM_ON) | ||
| 2311 | if ((err = sn9c102_stream_interrupt(cam))) | ||
| 2312 | return err; | ||
| 2313 | |||
| 2314 | err += sn9c102_set_compression(cam, &jc); | ||
| 2315 | if (err) { /* atomic, no rollback in ioctl() */ | ||
| 2316 | cam->state |= DEV_MISCONFIGURED; | ||
| 2317 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | ||
| 2318 | "problems. To use the camera, close and open " | ||
| 2319 | "/dev/video%d again.", cam->v4ldev->minor); | ||
| 2320 | return -EIO; | ||
| 2321 | } | ||
| 2322 | |||
| 2323 | cam->compression.quality = jc.quality; | ||
| 2324 | |||
| 2325 | cam->stream = stream; | ||
| 2326 | |||
| 2327 | return 0; | ||
| 2328 | } | ||
| 2329 | |||
| 2330 | |||
| 2331 | static int | ||
| 2332 | sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) | ||
| 2333 | { | ||
| 2334 | struct v4l2_requestbuffers rb; | ||
| 2335 | u32 i; | ||
| 2336 | int err; | ||
| 2337 | |||
| 2338 | if (copy_from_user(&rb, arg, sizeof(rb))) | ||
| 2339 | return -EFAULT; | ||
| 2340 | |||
| 2341 | if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
| 2342 | rb.memory != V4L2_MEMORY_MMAP) | ||
| 2343 | return -EINVAL; | ||
| 2344 | |||
| 2345 | if (cam->io == IO_READ) { | ||
| 2346 | DBG(3, "Close and open the device again to choose the mmap " | ||
| 2347 | "I/O method"); | ||
| 2348 | return -EINVAL; | ||
| 2349 | } | ||
| 2350 | |||
| 2351 | for (i = 0; i < cam->nbuffers; i++) | ||
| 2352 | if (cam->frame[i].vma_use_count) { | ||
| 2353 | DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " | ||
| 2354 | "still mapped."); | ||
| 2355 | return -EINVAL; | ||
| 2356 | } | ||
| 2357 | |||
| 2358 | if (cam->stream == STREAM_ON) | ||
| 2359 | if ((err = sn9c102_stream_interrupt(cam))) | ||
| 2360 | return err; | ||
| 2361 | |||
| 2362 | sn9c102_empty_framequeues(cam); | ||
| 2363 | |||
| 2364 | sn9c102_release_buffers(cam); | ||
| 2365 | if (rb.count) | ||
| 2366 | rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP); | ||
| 2367 | |||
| 2368 | if (copy_to_user(arg, &rb, sizeof(rb))) { | ||
| 2369 | sn9c102_release_buffers(cam); | ||
| 2370 | cam->io = IO_NONE; | ||
| 2371 | return -EFAULT; | ||
| 2372 | } | ||
| 2373 | |||
| 2374 | cam->io = rb.count ? IO_MMAP : IO_NONE; | ||
| 2375 | |||
| 2376 | return 0; | ||
| 2377 | } | ||
| 2378 | |||
| 2379 | |||
| 2380 | static int | ||
| 2381 | sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg) | ||
| 2382 | { | ||
| 2383 | struct v4l2_buffer b; | ||
| 2384 | |||
| 2385 | if (copy_from_user(&b, arg, sizeof(b))) | ||
| 2386 | return -EFAULT; | ||
| 2387 | |||
| 2388 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
| 2389 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
| 2390 | return -EINVAL; | ||
| 2391 | |||
| 2392 | memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); | ||
| 2393 | |||
| 2394 | if (cam->frame[b.index].vma_use_count) | ||
| 2395 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
| 2396 | |||
| 2397 | if (cam->frame[b.index].state == F_DONE) | ||
| 2398 | b.flags |= V4L2_BUF_FLAG_DONE; | ||
| 2399 | else if (cam->frame[b.index].state != F_UNUSED) | ||
| 2400 | b.flags |= V4L2_BUF_FLAG_QUEUED; | ||
| 2401 | |||
| 2402 | if (copy_to_user(arg, &b, sizeof(b))) | ||
| 2403 | return -EFAULT; | ||
| 2404 | |||
| 2405 | return 0; | ||
| 2406 | } | ||
| 2407 | |||
| 2408 | |||
| 2409 | static int | ||
| 2410 | sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg) | ||
| 2411 | { | ||
| 2412 | struct v4l2_buffer b; | ||
| 2413 | unsigned long lock_flags; | ||
| 2414 | |||
| 2415 | if (copy_from_user(&b, arg, sizeof(b))) | ||
| 2416 | return -EFAULT; | ||
| 2417 | |||
| 2418 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
| 2419 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
| 2420 | return -EINVAL; | ||
| 2421 | |||
| 2422 | if (cam->frame[b.index].state != F_UNUSED) | ||
| 2423 | return -EINVAL; | ||
| 2424 | |||
| 2425 | cam->frame[b.index].state = F_QUEUED; | ||
| 2426 | |||
| 2427 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 2428 | list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); | ||
| 2429 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 2430 | |||
| 2431 | PDBGG("Frame #%lu queued", (unsigned long)b.index); | ||
| 2432 | |||
| 2433 | return 0; | ||
| 2434 | } | ||
| 2435 | |||
| 2436 | |||
| 2437 | static int | ||
| 2438 | sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, | ||
| 2439 | void __user * arg) | ||
| 2440 | { | ||
| 2441 | struct v4l2_buffer b; | ||
| 2442 | struct sn9c102_frame_t *f; | ||
| 2443 | unsigned long lock_flags; | ||
| 2444 | long timeout; | ||
| 2445 | |||
| 2446 | if (copy_from_user(&b, arg, sizeof(b))) | ||
| 2447 | return -EFAULT; | ||
| 2448 | |||
| 2449 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
| 2450 | return -EINVAL; | ||
| 2451 | |||
| 2452 | if (list_empty(&cam->outqueue)) { | ||
| 2453 | if (cam->stream == STREAM_OFF) | ||
| 2454 | return -EINVAL; | ||
| 2455 | if (filp->f_flags & O_NONBLOCK) | ||
| 2456 | return -EAGAIN; | ||
| 2457 | timeout = wait_event_interruptible_timeout | ||
| 2458 | ( cam->wait_frame, | ||
| 2459 | (!list_empty(&cam->outqueue)) || | ||
| 2460 | (cam->state & DEV_DISCONNECTED) || | ||
| 2461 | (cam->state & DEV_MISCONFIGURED), | ||
| 2462 | cam->module_param.frame_timeout * | ||
| 2463 | 1000 * msecs_to_jiffies(1) ); | ||
| 2464 | if (timeout < 0) | ||
| 2465 | return timeout; | ||
| 2466 | if (cam->state & DEV_DISCONNECTED) | ||
| 2467 | return -ENODEV; | ||
| 2468 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) | ||
| 2469 | return -EIO; | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 2473 | f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); | ||
| 2474 | list_del(cam->outqueue.next); | ||
| 2475 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 2476 | |||
| 2477 | f->state = F_UNUSED; | ||
| 2478 | |||
| 2479 | memcpy(&b, &f->buf, sizeof(b)); | ||
| 2480 | if (f->vma_use_count) | ||
| 2481 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
| 2482 | |||
| 2483 | if (copy_to_user(arg, &b, sizeof(b))) | ||
| 2484 | return -EFAULT; | ||
| 2485 | |||
| 2486 | PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); | ||
| 2487 | |||
| 2488 | return 0; | ||
| 2489 | } | ||
| 2490 | |||
| 2491 | |||
| 2492 | static int | ||
| 2493 | sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) | ||
| 2494 | { | ||
| 2495 | int type; | ||
| 2496 | |||
| 2497 | if (copy_from_user(&type, arg, sizeof(type))) | ||
| 2498 | return -EFAULT; | ||
| 2499 | |||
| 2500 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
| 2501 | return -EINVAL; | ||
| 2502 | |||
| 2503 | if (list_empty(&cam->inqueue)) | ||
| 2504 | return -EINVAL; | ||
| 2505 | |||
| 2506 | cam->stream = STREAM_ON; | ||
| 2507 | |||
| 2508 | DBG(3, "Stream on"); | ||
| 2509 | |||
| 2510 | return 0; | ||
| 2511 | } | ||
| 2512 | |||
| 2513 | |||
| 2514 | static int | ||
| 2515 | sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg) | ||
| 2516 | { | ||
| 2517 | int type, err; | ||
| 2518 | |||
| 2519 | if (copy_from_user(&type, arg, sizeof(type))) | ||
| 2520 | return -EFAULT; | ||
| 2521 | |||
| 2522 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
| 2523 | return -EINVAL; | ||
| 2524 | |||
| 2525 | if (cam->stream == STREAM_ON) | ||
| 2526 | if ((err = sn9c102_stream_interrupt(cam))) | ||
| 2527 | return err; | ||
| 2528 | |||
| 2529 | sn9c102_empty_framequeues(cam); | ||
| 2530 | |||
| 2531 | DBG(3, "Stream off"); | ||
| 2532 | |||
| 2533 | return 0; | ||
| 2534 | } | ||
| 2535 | |||
| 2536 | |||
| 2537 | static int | ||
| 2538 | sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg) | ||
| 2539 | { | ||
| 2540 | struct v4l2_streamparm sp; | ||
| 2541 | |||
| 2542 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
| 2543 | return -EFAULT; | ||
| 2544 | |||
| 2545 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 2546 | return -EINVAL; | ||
| 2547 | |||
| 2548 | sp.parm.capture.extendedmode = 0; | ||
| 2549 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
| 2550 | |||
| 2551 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
| 2552 | return -EFAULT; | ||
| 2553 | |||
| 2554 | return 0; | ||
| 2555 | } | ||
| 2556 | |||
| 2557 | |||
| 2558 | static int | ||
| 2559 | sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg) | ||
| 2560 | { | ||
| 2561 | struct v4l2_streamparm sp; | ||
| 2562 | |||
| 2563 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
| 2564 | return -EFAULT; | ||
| 2565 | |||
| 2566 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 2567 | return -EINVAL; | ||
| 2568 | |||
| 2569 | sp.parm.capture.extendedmode = 0; | ||
| 2570 | |||
| 2571 | if (sp.parm.capture.readbuffers == 0) | ||
| 2572 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
| 2573 | |||
| 2574 | if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES) | ||
| 2575 | sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES; | ||
| 2576 | |||
| 2577 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
| 2578 | return -EFAULT; | ||
| 2579 | |||
| 2580 | cam->nreadbuffers = sp.parm.capture.readbuffers; | ||
| 2581 | |||
| 2582 | return 0; | ||
| 2583 | } | ||
| 2584 | |||
| 2585 | |||
| 2586 | static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, | ||
| 2587 | unsigned int cmd, void __user * arg) | ||
| 2588 | { | ||
| 2589 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 2590 | |||
| 2591 | switch (cmd) { | ||
| 2592 | |||
| 2593 | case VIDIOC_QUERYCAP: | ||
| 2594 | return sn9c102_vidioc_querycap(cam, arg); | ||
| 2595 | |||
| 2596 | case VIDIOC_ENUMINPUT: | ||
| 2597 | return sn9c102_vidioc_enuminput(cam, arg); | ||
| 2598 | |||
| 2599 | case VIDIOC_G_INPUT: | ||
| 2600 | return sn9c102_vidioc_g_input(cam, arg); | ||
| 2601 | |||
| 2602 | case VIDIOC_S_INPUT: | ||
| 2603 | return sn9c102_vidioc_s_input(cam, arg); | ||
| 2604 | |||
| 2605 | case VIDIOC_QUERYCTRL: | ||
| 2606 | return sn9c102_vidioc_query_ctrl(cam, arg); | ||
| 2607 | |||
| 2608 | case VIDIOC_G_CTRL: | ||
| 2609 | return sn9c102_vidioc_g_ctrl(cam, arg); | ||
| 2610 | |||
| 2611 | case VIDIOC_S_CTRL_OLD: | ||
| 2612 | case VIDIOC_S_CTRL: | ||
| 2613 | return sn9c102_vidioc_s_ctrl(cam, arg); | ||
| 2614 | |||
| 2615 | case VIDIOC_CROPCAP_OLD: | ||
| 2616 | case VIDIOC_CROPCAP: | ||
| 2617 | return sn9c102_vidioc_cropcap(cam, arg); | ||
| 2618 | |||
| 2619 | case VIDIOC_G_CROP: | ||
| 2620 | return sn9c102_vidioc_g_crop(cam, arg); | ||
| 2621 | |||
| 2622 | case VIDIOC_S_CROP: | ||
| 2623 | return sn9c102_vidioc_s_crop(cam, arg); | ||
| 2624 | |||
| 2625 | case VIDIOC_ENUM_FMT: | ||
| 2626 | return sn9c102_vidioc_enum_fmt(cam, arg); | ||
| 2627 | |||
| 2628 | case VIDIOC_G_FMT: | ||
| 2629 | return sn9c102_vidioc_g_fmt(cam, arg); | ||
| 2630 | |||
| 2631 | case VIDIOC_TRY_FMT: | ||
| 2632 | case VIDIOC_S_FMT: | ||
| 2633 | return sn9c102_vidioc_try_s_fmt(cam, cmd, arg); | ||
| 2634 | |||
| 2635 | case VIDIOC_G_JPEGCOMP: | ||
| 2636 | return sn9c102_vidioc_g_jpegcomp(cam, arg); | ||
| 2637 | |||
| 2638 | case VIDIOC_S_JPEGCOMP: | ||
| 2639 | return sn9c102_vidioc_s_jpegcomp(cam, arg); | ||
| 2640 | |||
| 2641 | case VIDIOC_REQBUFS: | ||
| 2642 | return sn9c102_vidioc_reqbufs(cam, arg); | ||
| 2643 | |||
| 2644 | case VIDIOC_QUERYBUF: | ||
| 2645 | return sn9c102_vidioc_querybuf(cam, arg); | ||
| 2646 | |||
| 2647 | case VIDIOC_QBUF: | ||
| 2648 | return sn9c102_vidioc_qbuf(cam, arg); | ||
| 2649 | |||
| 2650 | case VIDIOC_DQBUF: | ||
| 2651 | return sn9c102_vidioc_dqbuf(cam, filp, arg); | ||
| 2652 | |||
| 2653 | case VIDIOC_STREAMON: | ||
| 2654 | return sn9c102_vidioc_streamon(cam, arg); | ||
| 2655 | |||
| 2656 | case VIDIOC_STREAMOFF: | ||
| 2657 | return sn9c102_vidioc_streamoff(cam, arg); | ||
| 2658 | |||
| 2659 | case VIDIOC_G_PARM: | ||
| 2660 | return sn9c102_vidioc_g_parm(cam, arg); | ||
| 2661 | |||
| 2662 | case VIDIOC_S_PARM_OLD: | ||
| 2663 | case VIDIOC_S_PARM: | ||
| 2664 | return sn9c102_vidioc_s_parm(cam, arg); | ||
| 2665 | |||
| 2666 | case VIDIOC_G_STD: | ||
| 2667 | case VIDIOC_S_STD: | ||
| 2668 | case VIDIOC_QUERYSTD: | ||
| 2669 | case VIDIOC_ENUMSTD: | ||
| 2670 | case VIDIOC_QUERYMENU: | ||
| 2671 | return -EINVAL; | ||
| 2672 | |||
| 2673 | default: | ||
| 2674 | return -EINVAL; | ||
| 2675 | |||
| 2676 | } | ||
| 2677 | } | ||
| 2678 | |||
| 2679 | |||
| 2680 | static int sn9c102_ioctl(struct inode* inode, struct file* filp, | ||
| 2681 | unsigned int cmd, unsigned long arg) | ||
| 2682 | { | ||
| 2683 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 2684 | int err = 0; | ||
| 2685 | |||
| 2686 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 2687 | return -ERESTARTSYS; | ||
| 2688 | |||
| 2689 | if (cam->state & DEV_DISCONNECTED) { | ||
| 2690 | DBG(1, "Device not present"); | ||
| 2691 | mutex_unlock(&cam->fileop_mutex); | ||
| 2692 | return -ENODEV; | ||
| 2693 | } | ||
| 2694 | |||
| 2695 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 2696 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 2697 | "again."); | ||
| 2698 | mutex_unlock(&cam->fileop_mutex); | ||
| 2699 | return -EIO; | ||
| 2700 | } | ||
| 2701 | |||
| 2702 | V4LDBG(3, "sn9c102", cmd); | ||
| 2703 | |||
| 2704 | err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); | ||
| 2705 | |||
| 2706 | mutex_unlock(&cam->fileop_mutex); | ||
| 2707 | |||
| 2708 | return err; | ||
| 2709 | } | ||
| 2710 | |||
| 2711 | /*****************************************************************************/ | ||
| 2712 | |||
| 2713 | static struct file_operations sn9c102_fops = { | ||
| 2714 | .owner = THIS_MODULE, | ||
| 2715 | .open = sn9c102_open, | ||
| 2716 | .release = sn9c102_release, | ||
| 2717 | .ioctl = sn9c102_ioctl, | ||
| 2718 | .read = sn9c102_read, | ||
| 2719 | .poll = sn9c102_poll, | ||
| 2720 | .mmap = sn9c102_mmap, | ||
| 2721 | .llseek = no_llseek, | ||
| 2722 | }; | ||
| 2723 | |||
| 2724 | /*****************************************************************************/ | ||
| 2725 | |||
| 2726 | /* It exists a single interface only. We do not need to validate anything. */ | ||
| 2727 | static int | ||
| 2728 | sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
| 2729 | { | ||
| 2730 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 2731 | struct sn9c102_device* cam; | ||
| 2732 | static unsigned int dev_nr = 0; | ||
| 2733 | unsigned int i; | ||
| 2734 | int err = 0, r; | ||
| 2735 | |||
| 2736 | if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL))) | ||
| 2737 | return -ENOMEM; | ||
| 2738 | |||
| 2739 | cam->usbdev = udev; | ||
| 2740 | |||
| 2741 | if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { | ||
| 2742 | DBG(1, "kmalloc() failed"); | ||
| 2743 | err = -ENOMEM; | ||
| 2744 | goto fail; | ||
| 2745 | } | ||
| 2746 | |||
| 2747 | if (!(cam->v4ldev = video_device_alloc())) { | ||
| 2748 | DBG(1, "video_device_alloc() failed"); | ||
| 2749 | err = -ENOMEM; | ||
| 2750 | goto fail; | ||
| 2751 | } | ||
| 2752 | |||
| 2753 | mutex_init(&cam->dev_mutex); | ||
| 2754 | |||
| 2755 | r = sn9c102_read_reg(cam, 0x00); | ||
| 2756 | if (r < 0 || r != 0x10) { | ||
| 2757 | DBG(1, "Sorry, this is not a SN9C10x based camera " | ||
| 2758 | "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); | ||
| 2759 | err = -ENODEV; | ||
| 2760 | goto fail; | ||
| 2761 | } | ||
| 2762 | |||
| 2763 | cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ? | ||
| 2764 | BRIDGE_SN9C103 : BRIDGE_SN9C102; | ||
| 2765 | switch (cam->bridge) { | ||
| 2766 | case BRIDGE_SN9C101: | ||
| 2767 | case BRIDGE_SN9C102: | ||
| 2768 | DBG(2, "SN9C10[12] PC Camera Controller detected " | ||
| 2769 | "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); | ||
| 2770 | break; | ||
| 2771 | case BRIDGE_SN9C103: | ||
| 2772 | DBG(2, "SN9C103 PC Camera Controller detected " | ||
| 2773 | "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); | ||
| 2774 | break; | ||
| 2775 | } | ||
| 2776 | |||
| 2777 | for (i = 0; sn9c102_sensor_table[i]; i++) { | ||
| 2778 | err = sn9c102_sensor_table[i](cam); | ||
| 2779 | if (!err) | ||
| 2780 | break; | ||
| 2781 | } | ||
| 2782 | |||
| 2783 | if (!err) { | ||
| 2784 | DBG(2, "%s image sensor detected", cam->sensor.name); | ||
| 2785 | DBG(3, "Support for %s maintained by %s", | ||
| 2786 | cam->sensor.name, cam->sensor.maintainer); | ||
| 2787 | } else { | ||
| 2788 | DBG(1, "No supported image sensor detected"); | ||
| 2789 | err = -ENODEV; | ||
| 2790 | goto fail; | ||
| 2791 | } | ||
| 2792 | |||
| 2793 | if (sn9c102_init(cam)) { | ||
| 2794 | DBG(1, "Initialization failed. I will retry on open()."); | ||
| 2795 | cam->state |= DEV_MISCONFIGURED; | ||
| 2796 | } | ||
| 2797 | |||
| 2798 | strcpy(cam->v4ldev->name, "SN9C10x PC Camera"); | ||
| 2799 | cam->v4ldev->owner = THIS_MODULE; | ||
| 2800 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
| 2801 | cam->v4ldev->hardware = 0; | ||
| 2802 | cam->v4ldev->fops = &sn9c102_fops; | ||
| 2803 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
| 2804 | cam->v4ldev->release = video_device_release; | ||
| 2805 | video_set_drvdata(cam->v4ldev, cam); | ||
| 2806 | |||
| 2807 | mutex_lock(&cam->dev_mutex); | ||
| 2808 | |||
| 2809 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
| 2810 | video_nr[dev_nr]); | ||
| 2811 | if (err) { | ||
| 2812 | DBG(1, "V4L2 device registration failed"); | ||
| 2813 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
| 2814 | DBG(1, "Free /dev/videoX node not found"); | ||
| 2815 | video_nr[dev_nr] = -1; | ||
| 2816 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
| 2817 | mutex_unlock(&cam->dev_mutex); | ||
| 2818 | goto fail; | ||
| 2819 | } | ||
| 2820 | |||
| 2821 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); | ||
| 2822 | |||
| 2823 | cam->module_param.force_munmap = force_munmap[dev_nr]; | ||
| 2824 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; | ||
| 2825 | |||
| 2826 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
| 2827 | |||
| 2828 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
| 2829 | sn9c102_create_sysfs(cam); | ||
| 2830 | DBG(2, "Optional device control through 'sysfs' interface ready"); | ||
| 2831 | #endif | ||
| 2832 | |||
| 2833 | usb_set_intfdata(intf, cam); | ||
| 2834 | |||
| 2835 | mutex_unlock(&cam->dev_mutex); | ||
| 2836 | |||
| 2837 | return 0; | ||
| 2838 | |||
| 2839 | fail: | ||
| 2840 | if (cam) { | ||
| 2841 | kfree(cam->control_buffer); | ||
| 2842 | if (cam->v4ldev) | ||
| 2843 | video_device_release(cam->v4ldev); | ||
| 2844 | kfree(cam); | ||
| 2845 | } | ||
| 2846 | return err; | ||
| 2847 | } | ||
| 2848 | |||
| 2849 | |||
| 2850 | static void sn9c102_usb_disconnect(struct usb_interface* intf) | ||
| 2851 | { | ||
| 2852 | struct sn9c102_device* cam = usb_get_intfdata(intf); | ||
| 2853 | |||
| 2854 | if (!cam) | ||
| 2855 | return; | ||
| 2856 | |||
| 2857 | down_write(&sn9c102_disconnect); | ||
| 2858 | |||
| 2859 | mutex_lock(&cam->dev_mutex); | ||
| 2860 | |||
| 2861 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | ||
| 2862 | |||
| 2863 | wake_up_interruptible_all(&cam->open); | ||
| 2864 | |||
| 2865 | if (cam->users) { | ||
| 2866 | DBG(2, "Device /dev/video%d is open! Deregistration and " | ||
| 2867 | "memory deallocation are deferred on close.", | ||
| 2868 | cam->v4ldev->minor); | ||
| 2869 | cam->state |= DEV_MISCONFIGURED; | ||
| 2870 | sn9c102_stop_transfer(cam); | ||
| 2871 | cam->state |= DEV_DISCONNECTED; | ||
| 2872 | wake_up_interruptible(&cam->wait_frame); | ||
| 2873 | wake_up(&cam->wait_stream); | ||
| 2874 | usb_get_dev(cam->usbdev); | ||
| 2875 | } else { | ||
| 2876 | cam->state |= DEV_DISCONNECTED; | ||
| 2877 | sn9c102_release_resources(cam); | ||
| 2878 | } | ||
| 2879 | |||
| 2880 | mutex_unlock(&cam->dev_mutex); | ||
| 2881 | |||
| 2882 | if (!cam->users) | ||
| 2883 | kfree(cam); | ||
| 2884 | |||
| 2885 | up_write(&sn9c102_disconnect); | ||
| 2886 | } | ||
| 2887 | |||
| 2888 | |||
| 2889 | static struct usb_driver sn9c102_usb_driver = { | ||
| 2890 | .name = "sn9c102", | ||
| 2891 | .id_table = sn9c102_id_table, | ||
| 2892 | .probe = sn9c102_usb_probe, | ||
| 2893 | .disconnect = sn9c102_usb_disconnect, | ||
| 2894 | }; | ||
| 2895 | |||
| 2896 | /*****************************************************************************/ | ||
| 2897 | |||
| 2898 | static int __init sn9c102_module_init(void) | ||
| 2899 | { | ||
| 2900 | int err = 0; | ||
| 2901 | |||
| 2902 | KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION); | ||
| 2903 | KDBG(3, SN9C102_MODULE_AUTHOR); | ||
| 2904 | |||
| 2905 | if ((err = usb_register(&sn9c102_usb_driver))) | ||
| 2906 | KDBG(1, "usb_register() failed"); | ||
| 2907 | |||
| 2908 | return err; | ||
| 2909 | } | ||
| 2910 | |||
| 2911 | |||
| 2912 | static void __exit sn9c102_module_exit(void) | ||
| 2913 | { | ||
| 2914 | usb_deregister(&sn9c102_usb_driver); | ||
| 2915 | } | ||
| 2916 | |||
| 2917 | |||
| 2918 | module_init(sn9c102_module_init); | ||
| 2919 | module_exit(sn9c102_module_exit); | ||
diff --git a/drivers/usb/media/sn9c102_hv7131d.c b/drivers/usb/media/sn9c102_hv7131d.c deleted file mode 100644 index 46c12ec3ca62..000000000000 --- a/drivers/usb/media/sn9c102_hv7131d.c +++ /dev/null | |||
| @@ -1,271 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera * | ||
| 3 | * Controllers * | ||
| 4 | * * | ||
| 5 | * Copyright (C) 2004-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 "sn9c102_sensor.h" | ||
| 23 | |||
| 24 | |||
| 25 | static struct sn9c102_sensor hv7131d; | ||
| 26 | |||
| 27 | |||
| 28 | static int hv7131d_init(struct sn9c102_device* cam) | ||
| 29 | { | ||
| 30 | int err = 0; | ||
| 31 | |||
| 32 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
| 33 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
| 34 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
| 35 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
| 36 | err += sn9c102_write_reg(cam, 0x0e, 0x18); | ||
| 37 | err += sn9c102_write_reg(cam, 0xf2, 0x19); | ||
| 38 | |||
| 39 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
| 40 | err += sn9c102_i2c_write(cam, 0x02, 0x00); | ||
| 41 | err += sn9c102_i2c_write(cam, 0x28, 0x00); | ||
| 42 | |||
| 43 | return err; | ||
| 44 | } | ||
| 45 | |||
| 46 | |||
| 47 | static int hv7131d_get_ctrl(struct sn9c102_device* cam, | ||
| 48 | struct v4l2_control* ctrl) | ||
| 49 | { | ||
| 50 | switch (ctrl->id) { | ||
| 51 | case V4L2_CID_EXPOSURE: | ||
| 52 | { | ||
| 53 | int r1 = sn9c102_i2c_read(cam, 0x26), | ||
| 54 | r2 = sn9c102_i2c_read(cam, 0x27); | ||
| 55 | if (r1 < 0 || r2 < 0) | ||
| 56 | return -EIO; | ||
| 57 | ctrl->value = (r1 << 8) | (r2 & 0xff); | ||
| 58 | } | ||
| 59 | return 0; | ||
| 60 | case V4L2_CID_RED_BALANCE: | ||
| 61 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) | ||
| 62 | return -EIO; | ||
| 63 | ctrl->value = 0x3f - (ctrl->value & 0x3f); | ||
| 64 | return 0; | ||
| 65 | case V4L2_CID_BLUE_BALANCE: | ||
| 66 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) | ||
| 67 | return -EIO; | ||
| 68 | ctrl->value = 0x3f - (ctrl->value & 0x3f); | ||
| 69 | return 0; | ||
| 70 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 71 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) | ||
| 72 | return -EIO; | ||
| 73 | ctrl->value = 0x3f - (ctrl->value & 0x3f); | ||
| 74 | return 0; | ||
| 75 | case SN9C102_V4L2_CID_RESET_LEVEL: | ||
| 76 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) | ||
| 77 | return -EIO; | ||
| 78 | ctrl->value &= 0x3f; | ||
| 79 | return 0; | ||
| 80 | case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: | ||
| 81 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0) | ||
| 82 | return -EIO; | ||
| 83 | ctrl->value &= 0x07; | ||
| 84 | return 0; | ||
| 85 | default: | ||
| 86 | return -EINVAL; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | |||
| 91 | static int hv7131d_set_ctrl(struct sn9c102_device* cam, | ||
| 92 | const struct v4l2_control* ctrl) | ||
| 93 | { | ||
| 94 | int err = 0; | ||
| 95 | |||
| 96 | switch (ctrl->id) { | ||
| 97 | case V4L2_CID_EXPOSURE: | ||
| 98 | err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8); | ||
| 99 | err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff); | ||
| 100 | break; | ||
| 101 | case V4L2_CID_RED_BALANCE: | ||
| 102 | err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value); | ||
| 103 | break; | ||
| 104 | case V4L2_CID_BLUE_BALANCE: | ||
| 105 | err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value); | ||
| 106 | break; | ||
| 107 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 108 | err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value); | ||
| 109 | break; | ||
| 110 | case SN9C102_V4L2_CID_RESET_LEVEL: | ||
| 111 | err += sn9c102_i2c_write(cam, 0x30, ctrl->value); | ||
| 112 | break; | ||
| 113 | case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: | ||
| 114 | err += sn9c102_i2c_write(cam, 0x34, ctrl->value); | ||
| 115 | break; | ||
| 116 | default: | ||
| 117 | return -EINVAL; | ||
| 118 | } | ||
| 119 | |||
| 120 | return err ? -EIO : 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | |||
| 124 | static int hv7131d_set_crop(struct sn9c102_device* cam, | ||
| 125 | const struct v4l2_rect* rect) | ||
| 126 | { | ||
| 127 | struct sn9c102_sensor* s = &hv7131d; | ||
| 128 | int err = 0; | ||
| 129 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2, | ||
| 130 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; | ||
| 131 | |||
| 132 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
| 133 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
| 134 | |||
| 135 | return err; | ||
| 136 | } | ||
| 137 | |||
| 138 | |||
| 139 | static int hv7131d_set_pix_format(struct sn9c102_device* cam, | ||
| 140 | const struct v4l2_pix_format* pix) | ||
| 141 | { | ||
| 142 | int err = 0; | ||
| 143 | |||
| 144 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 145 | err += sn9c102_write_reg(cam, 0x42, 0x19); | ||
| 146 | else | ||
| 147 | err += sn9c102_write_reg(cam, 0xf2, 0x19); | ||
| 148 | |||
| 149 | return err; | ||
| 150 | } | ||
| 151 | |||
| 152 | |||
| 153 | static struct sn9c102_sensor hv7131d = { | ||
| 154 | .name = "HV7131D", | ||
| 155 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
| 156 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
| 157 | .frequency = SN9C102_I2C_100KHZ, | ||
| 158 | .interface = SN9C102_I2C_2WIRES, | ||
| 159 | .i2c_slave_id = 0x11, | ||
| 160 | .init = &hv7131d_init, | ||
| 161 | .qctrl = { | ||
| 162 | { | ||
| 163 | .id = V4L2_CID_EXPOSURE, | ||
| 164 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 165 | .name = "exposure", | ||
| 166 | .minimum = 0x0250, | ||
| 167 | .maximum = 0xffff, | ||
| 168 | .step = 0x0001, | ||
| 169 | .default_value = 0x0250, | ||
| 170 | .flags = 0, | ||
| 171 | }, | ||
| 172 | { | ||
| 173 | .id = V4L2_CID_RED_BALANCE, | ||
| 174 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 175 | .name = "red balance", | ||
| 176 | .minimum = 0x00, | ||
| 177 | .maximum = 0x3f, | ||
| 178 | .step = 0x01, | ||
| 179 | .default_value = 0x00, | ||
| 180 | .flags = 0, | ||
| 181 | }, | ||
| 182 | { | ||
| 183 | .id = V4L2_CID_BLUE_BALANCE, | ||
| 184 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 185 | .name = "blue balance", | ||
| 186 | .minimum = 0x00, | ||
| 187 | .maximum = 0x3f, | ||
| 188 | .step = 0x01, | ||
| 189 | .default_value = 0x20, | ||
| 190 | .flags = 0, | ||
| 191 | }, | ||
| 192 | { | ||
| 193 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
| 194 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 195 | .name = "green balance", | ||
| 196 | .minimum = 0x00, | ||
| 197 | .maximum = 0x3f, | ||
| 198 | .step = 0x01, | ||
| 199 | .default_value = 0x1e, | ||
| 200 | .flags = 0, | ||
| 201 | }, | ||
| 202 | { | ||
| 203 | .id = SN9C102_V4L2_CID_RESET_LEVEL, | ||
| 204 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 205 | .name = "reset level", | ||
| 206 | .minimum = 0x19, | ||
| 207 | .maximum = 0x3f, | ||
| 208 | .step = 0x01, | ||
| 209 | .default_value = 0x30, | ||
| 210 | .flags = 0, | ||
| 211 | }, | ||
| 212 | { | ||
| 213 | .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE, | ||
| 214 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 215 | .name = "pixel bias voltage", | ||
| 216 | .minimum = 0x00, | ||
| 217 | .maximum = 0x07, | ||
| 218 | .step = 0x01, | ||
| 219 | .default_value = 0x02, | ||
| 220 | .flags = 0, | ||
| 221 | }, | ||
| 222 | }, | ||
| 223 | .get_ctrl = &hv7131d_get_ctrl, | ||
| 224 | .set_ctrl = &hv7131d_set_ctrl, | ||
| 225 | .cropcap = { | ||
| 226 | .bounds = { | ||
| 227 | .left = 0, | ||
| 228 | .top = 0, | ||
| 229 | .width = 640, | ||
| 230 | .height = 480, | ||
| 231 | }, | ||
| 232 | .defrect = { | ||
| 233 | .left = 0, | ||
| 234 | .top = 0, | ||
| 235 | .width = 640, | ||
| 236 | .height = 480, | ||
| 237 | }, | ||
| 238 | }, | ||
| 239 | .set_crop = &hv7131d_set_crop, | ||
| 240 | .pix_format = { | ||
| 241 | .width = 640, | ||
| 242 | .height = 480, | ||
| 243 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
| 244 | .priv = 8, | ||
| 245 | }, | ||
| 246 | .set_pix_format = &hv7131d_set_pix_format | ||
| 247 | }; | ||
| 248 | |||
| 249 | |||
| 250 | int sn9c102_probe_hv7131d(struct sn9c102_device* cam) | ||
| 251 | { | ||
| 252 | int r0 = 0, r1 = 0, err = 0; | ||
| 253 | |||
| 254 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
| 255 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
| 256 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
| 257 | if (err) | ||
| 258 | return -EIO; | ||
| 259 | |||
| 260 | r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00); | ||
| 261 | r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01); | ||
| 262 | if (r0 < 0 || r1 < 0) | ||
| 263 | return -EIO; | ||
| 264 | |||
| 265 | if (r0 != 0x00 && r1 != 0x04) | ||
| 266 | return -ENODEV; | ||
| 267 | |||
| 268 | sn9c102_attach_sensor(cam, &hv7131d); | ||
| 269 | |||
| 270 | return 0; | ||
| 271 | } | ||
diff --git a/drivers/usb/media/sn9c102_mi0343.c b/drivers/usb/media/sn9c102_mi0343.c deleted file mode 100644 index d9aa7a61095d..000000000000 --- a/drivers/usb/media/sn9c102_mi0343.c +++ /dev/null | |||
| @@ -1,363 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera * | ||
| 3 | * Controllers * | ||
| 4 | * * | ||
| 5 | * Copyright (C) 2004-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 "sn9c102_sensor.h" | ||
| 23 | |||
| 24 | |||
| 25 | static struct sn9c102_sensor mi0343; | ||
| 26 | static u8 mi0343_i2c_data[5+1]; | ||
| 27 | |||
| 28 | |||
| 29 | static int mi0343_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, 0x0a, 0x14); | ||
| 36 | err += sn9c102_write_reg(cam, 0x40, 0x01); | ||
| 37 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
| 38 | err += sn9c102_write_reg(cam, 0x07, 0x18); | ||
| 39 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | ||
| 40 | |||
| 41 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
| 42 | 0x0d, 0x00, 0x01, 0, 0); | ||
| 43 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
| 44 | 0x0d, 0x00, 0x00, 0, 0); | ||
| 45 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
| 46 | 0x03, 0x01, 0xe1, 0, 0); | ||
| 47 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
| 48 | 0x04, 0x02, 0x81, 0, 0); | ||
| 49 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
| 50 | 0x05, 0x00, 0x17, 0, 0); | ||
| 51 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
| 52 | 0x06, 0x00, 0x11, 0, 0); | ||
| 53 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
| 54 | 0x62, 0x04, 0x9a, 0, 0); | ||
| 55 | |||
| 56 | return err; | ||
| 57 | } | ||
| 58 | |||
| 59 | |||
| 60 | static int mi0343_get_ctrl(struct sn9c102_device* cam, | ||
| 61 | struct v4l2_control* ctrl) | ||
| 62 | { | ||
| 63 | switch (ctrl->id) { | ||
| 64 | case V4L2_CID_EXPOSURE: | ||
| 65 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
| 66 | 0x09, 2+1, mi0343_i2c_data) < 0) | ||
| 67 | return -EIO; | ||
| 68 | ctrl->value = mi0343_i2c_data[2]; | ||
| 69 | return 0; | ||
| 70 | case V4L2_CID_GAIN: | ||
| 71 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
| 72 | 0x35, 2+1, mi0343_i2c_data) < 0) | ||
| 73 | return -EIO; | ||
| 74 | break; | ||
| 75 | case V4L2_CID_HFLIP: | ||
| 76 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
| 77 | 0x20, 2+1, mi0343_i2c_data) < 0) | ||
| 78 | return -EIO; | ||
| 79 | ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0; | ||
| 80 | return 0; | ||
| 81 | case V4L2_CID_VFLIP: | ||
| 82 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
| 83 | 0x20, 2+1, mi0343_i2c_data) < 0) | ||
| 84 | return -EIO; | ||
| 85 | ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0; | ||
| 86 | return 0; | ||
| 87 | case V4L2_CID_RED_BALANCE: | ||
| 88 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
| 89 | 0x2d, 2+1, mi0343_i2c_data) < 0) | ||
| 90 | return -EIO; | ||
| 91 | break; | ||
| 92 | case V4L2_CID_BLUE_BALANCE: | ||
| 93 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
| 94 | 0x2c, 2+1, mi0343_i2c_data) < 0) | ||
| 95 | return -EIO; | ||
| 96 | break; | ||
| 97 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 98 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
| 99 | 0x2e, 2+1, mi0343_i2c_data) < 0) | ||
| 100 | return -EIO; | ||
| 101 | break; | ||
| 102 | default: | ||
| 103 | return -EINVAL; | ||
| 104 | } | ||
| 105 | |||
| 106 | switch (ctrl->id) { | ||
| 107 | case V4L2_CID_GAIN: | ||
| 108 | case V4L2_CID_RED_BALANCE: | ||
| 109 | case V4L2_CID_BLUE_BALANCE: | ||
| 110 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 111 | ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8); | ||
| 112 | if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) | ||
| 113 | ctrl->value -= 0x10; | ||
| 114 | else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) | ||
| 115 | ctrl->value -= 0x60; | ||
| 116 | else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff) | ||
| 117 | ctrl->value -= 0xe0; | ||
| 118 | } | ||
| 119 | |||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | |||
| 124 | static int mi0343_set_ctrl(struct sn9c102_device* cam, | ||
| 125 | const struct v4l2_control* ctrl) | ||
| 126 | { | ||
| 127 | u16 reg = 0; | ||
| 128 | int err = 0; | ||
| 129 | |||
| 130 | switch (ctrl->id) { | ||
| 131 | case V4L2_CID_GAIN: | ||
| 132 | case V4L2_CID_RED_BALANCE: | ||
| 133 | case V4L2_CID_BLUE_BALANCE: | ||
| 134 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 135 | if (ctrl->value <= (0x3f-0x10)) | ||
| 136 | reg = 0x10 + ctrl->value; | ||
| 137 | else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60))) | ||
| 138 | reg = 0x60 + (ctrl->value - (0x3f-0x10)); | ||
| 139 | else | ||
| 140 | reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60)); | ||
| 141 | break; | ||
| 142 | } | ||
| 143 | |||
| 144 | switch (ctrl->id) { | ||
| 145 | case V4L2_CID_EXPOSURE: | ||
| 146 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 147 | mi0343.i2c_slave_id, | ||
| 148 | 0x09, ctrl->value, 0x00, | ||
| 149 | 0, 0); | ||
| 150 | break; | ||
| 151 | case V4L2_CID_GAIN: | ||
| 152 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 153 | mi0343.i2c_slave_id, | ||
| 154 | 0x35, reg >> 8, reg & 0xff, | ||
| 155 | 0, 0); | ||
| 156 | break; | ||
| 157 | case V4L2_CID_HFLIP: | ||
| 158 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 159 | mi0343.i2c_slave_id, | ||
| 160 | 0x20, ctrl->value ? 0x40:0x00, | ||
| 161 | ctrl->value ? 0x20:0x00, | ||
| 162 | 0, 0); | ||
| 163 | break; | ||
| 164 | case V4L2_CID_VFLIP: | ||
| 165 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 166 | mi0343.i2c_slave_id, | ||
| 167 | 0x20, ctrl->value ? 0x80:0x00, | ||
| 168 | ctrl->value ? 0x80:0x00, | ||
| 169 | 0, 0); | ||
| 170 | break; | ||
| 171 | case V4L2_CID_RED_BALANCE: | ||
| 172 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 173 | mi0343.i2c_slave_id, | ||
| 174 | 0x2d, reg >> 8, reg & 0xff, | ||
| 175 | 0, 0); | ||
| 176 | break; | ||
| 177 | case V4L2_CID_BLUE_BALANCE: | ||
| 178 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 179 | mi0343.i2c_slave_id, | ||
| 180 | 0x2c, reg >> 8, reg & 0xff, | ||
| 181 | 0, 0); | ||
| 182 | break; | ||
| 183 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 184 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 185 | mi0343.i2c_slave_id, | ||
| 186 | 0x2b, reg >> 8, reg & 0xff, | ||
| 187 | 0, 0); | ||
| 188 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 189 | mi0343.i2c_slave_id, | ||
| 190 | 0x2e, reg >> 8, reg & 0xff, | ||
| 191 | 0, 0); | ||
| 192 | break; | ||
| 193 | default: | ||
| 194 | return -EINVAL; | ||
| 195 | } | ||
| 196 | |||
| 197 | return err ? -EIO : 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | |||
| 201 | static int mi0343_set_crop(struct sn9c102_device* cam, | ||
| 202 | const struct v4l2_rect* rect) | ||
| 203 | { | ||
| 204 | struct sn9c102_sensor* s = &mi0343; | ||
| 205 | int err = 0; | ||
| 206 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, | ||
| 207 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; | ||
| 208 | |||
| 209 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
| 210 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
| 211 | |||
| 212 | return err; | ||
| 213 | } | ||
| 214 | |||
| 215 | |||
| 216 | static int mi0343_set_pix_format(struct sn9c102_device* cam, | ||
| 217 | const struct v4l2_pix_format* pix) | ||
| 218 | { | ||
| 219 | int err = 0; | ||
| 220 | |||
| 221 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { | ||
| 222 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 223 | mi0343.i2c_slave_id, | ||
| 224 | 0x0a, 0x00, 0x03, 0, 0); | ||
| 225 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
| 226 | } else { | ||
| 227 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
| 228 | mi0343.i2c_slave_id, | ||
| 229 | 0x0a, 0x00, 0x05, 0, 0); | ||
| 230 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | ||
| 231 | } | ||
| 232 | |||
| 233 | return err; | ||
| 234 | } | ||
| 235 | |||
| 236 | |||
| 237 | static struct sn9c102_sensor mi0343 = { | ||
| 238 | .name = "MI-0343", | ||
| 239 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
| 240 | .frequency = SN9C102_I2C_100KHZ, | ||
| 241 | .interface = SN9C102_I2C_2WIRES, | ||
| 242 | .i2c_slave_id = 0x5d, | ||
| 243 | .init = &mi0343_init, | ||
| 244 | .qctrl = { | ||
| 245 | { | ||
| 246 | .id = V4L2_CID_EXPOSURE, | ||
| 247 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 248 | .name = "exposure", | ||
| 249 | .minimum = 0x00, | ||
| 250 | .maximum = 0x0f, | ||
| 251 | .step = 0x01, | ||
| 252 | .default_value = 0x06, | ||
| 253 | .flags = 0, | ||
| 254 | }, | ||
| 255 | { | ||
| 256 | .id = V4L2_CID_GAIN, | ||
| 257 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 258 | .name = "global gain", | ||
| 259 | .minimum = 0x00, | ||
| 260 | .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/ | ||
| 261 | .step = 0x01, | ||
| 262 | .default_value = 0x00, | ||
| 263 | .flags = 0, | ||
| 264 | }, | ||
| 265 | { | ||
| 266 | .id = V4L2_CID_HFLIP, | ||
| 267 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 268 | .name = "horizontal mirror", | ||
| 269 | .minimum = 0, | ||
| 270 | .maximum = 1, | ||
| 271 | .step = 1, | ||
| 272 | .default_value = 0, | ||
| 273 | .flags = 0, | ||
| 274 | }, | ||
| 275 | { | ||
| 276 | .id = V4L2_CID_VFLIP, | ||
| 277 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 278 | .name = "vertical mirror", | ||
| 279 | .minimum = 0, | ||
| 280 | .maximum = 1, | ||
| 281 | .step = 1, | ||
| 282 | .default_value = 0, | ||
| 283 | .flags = 0, | ||
| 284 | }, | ||
| 285 | { | ||
| 286 | .id = V4L2_CID_RED_BALANCE, | ||
| 287 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 288 | .name = "red balance", | ||
| 289 | .minimum = 0x00, | ||
| 290 | .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), | ||
| 291 | .step = 0x01, | ||
| 292 | .default_value = 0x00, | ||
| 293 | .flags = 0, | ||
| 294 | }, | ||
| 295 | { | ||
| 296 | .id = V4L2_CID_BLUE_BALANCE, | ||
| 297 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 298 | .name = "blue balance", | ||
| 299 | .minimum = 0x00, | ||
| 300 | .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), | ||
| 301 | .step = 0x01, | ||
| 302 | .default_value = 0x00, | ||
| 303 | .flags = 0, | ||
| 304 | }, | ||
| 305 | { | ||
| 306 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
| 307 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 308 | .name = "green balance", | ||
| 309 | .minimum = 0x00, | ||
| 310 | .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)), | ||
| 311 | .step = 0x01, | ||
| 312 | .default_value = 0x00, | ||
| 313 | .flags = 0, | ||
| 314 | }, | ||
| 315 | }, | ||
| 316 | .get_ctrl = &mi0343_get_ctrl, | ||
| 317 | .set_ctrl = &mi0343_set_ctrl, | ||
| 318 | .cropcap = { | ||
| 319 | .bounds = { | ||
| 320 | .left = 0, | ||
| 321 | .top = 0, | ||
| 322 | .width = 640, | ||
| 323 | .height = 480, | ||
| 324 | }, | ||
| 325 | .defrect = { | ||
| 326 | .left = 0, | ||
| 327 | .top = 0, | ||
| 328 | .width = 640, | ||
| 329 | .height = 480, | ||
| 330 | }, | ||
| 331 | }, | ||
| 332 | .set_crop = &mi0343_set_crop, | ||
| 333 | .pix_format = { | ||
| 334 | .width = 640, | ||
| 335 | .height = 480, | ||
| 336 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
| 337 | .priv = 8, | ||
| 338 | }, | ||
| 339 | .set_pix_format = &mi0343_set_pix_format | ||
| 340 | }; | ||
| 341 | |||
| 342 | |||
| 343 | int sn9c102_probe_mi0343(struct sn9c102_device* cam) | ||
| 344 | { | ||
| 345 | int err = 0; | ||
| 346 | |||
| 347 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
| 348 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
| 349 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
| 350 | if (err) | ||
| 351 | return -EIO; | ||
| 352 | |||
| 353 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, | ||
| 354 | 2, mi0343_i2c_data) < 0) | ||
| 355 | return -EIO; | ||
| 356 | |||
| 357 | if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3) | ||
| 358 | return -ENODEV; | ||
| 359 | |||
| 360 | sn9c102_attach_sensor(cam, &mi0343); | ||
| 361 | |||
| 362 | return 0; | ||
| 363 | } | ||
diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c deleted file mode 100644 index 42852b7cb042..000000000000 --- a/drivers/usb/media/sn9c102_ov7630.c +++ /dev/null | |||
| @@ -1,401 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera * | ||
| 3 | * Controllers * | ||
| 4 | * * | ||
| 5 | * Copyright (C) 2005-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 "sn9c102_sensor.h" | ||
| 23 | |||
| 24 | |||
| 25 | static struct sn9c102_sensor ov7630; | ||
| 26 | |||
| 27 | |||
| 28 | static int ov7630_init(struct sn9c102_device* cam) | ||
| 29 | { | ||
| 30 | int err = 0; | ||
| 31 | |||
| 32 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
| 33 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
| 34 | err += sn9c102_write_reg(cam, 0x0f, 0x18); | ||
| 35 | err += sn9c102_write_reg(cam, 0x50, 0x19); | ||
| 36 | |||
| 37 | err += sn9c102_i2c_write(cam, 0x12, 0x80); | ||
| 38 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
| 39 | err += sn9c102_i2c_write(cam, 0x15, 0x34); | ||
| 40 | err += sn9c102_i2c_write(cam, 0x16, 0x03); | ||
| 41 | err += sn9c102_i2c_write(cam, 0x17, 0x1c); | ||
| 42 | err += sn9c102_i2c_write(cam, 0x18, 0xbd); | ||
| 43 | err += sn9c102_i2c_write(cam, 0x19, 0x06); | ||
| 44 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); | ||
| 45 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | ||
| 46 | err += sn9c102_i2c_write(cam, 0x20, 0xf6); | ||
| 47 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | ||
| 48 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | ||
| 49 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); | ||
| 50 | err += sn9c102_i2c_write(cam, 0x28, 0xa0); | ||
| 51 | 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); | ||
| 55 | err += sn9c102_i2c_write(cam, 0x30, 0x24); | ||
| 56 | err += sn9c102_i2c_write(cam, 0x32, 0x86); | ||
| 57 | err += sn9c102_i2c_write(cam, 0x60, 0xa9); | ||
| 58 | err += sn9c102_i2c_write(cam, 0x61, 0x42); | ||
| 59 | err += sn9c102_i2c_write(cam, 0x65, 0x00); | ||
| 60 | err += sn9c102_i2c_write(cam, 0x69, 0x38); | ||
| 61 | err += sn9c102_i2c_write(cam, 0x6f, 0x88); | ||
| 62 | err += sn9c102_i2c_write(cam, 0x70, 0x0b); | ||
| 63 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | ||
| 64 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | ||
| 65 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | ||
| 66 | |||
| 67 | return err; | ||
| 68 | } | ||
| 69 | |||
| 70 | |||
| 71 | static int ov7630_set_ctrl(struct sn9c102_device* cam, | ||
| 72 | const struct v4l2_control* ctrl) | ||
| 73 | { | ||
| 74 | int err = 0; | ||
| 75 | |||
| 76 | switch (ctrl->id) { | ||
| 77 | case V4L2_CID_EXPOSURE: | ||
| 78 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2); | ||
| 79 | err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03); | ||
| 80 | break; | ||
| 81 | case V4L2_CID_RED_BALANCE: | ||
| 82 | err += sn9c102_i2c_write(cam, 0x02, ctrl->value); | ||
| 83 | break; | ||
| 84 | case V4L2_CID_BLUE_BALANCE: | ||
| 85 | err += sn9c102_i2c_write(cam, 0x01, ctrl->value); | ||
| 86 | break; | ||
| 87 | case V4L2_CID_GAIN: | ||
| 88 | err += sn9c102_i2c_write(cam, 0x00, ctrl->value); | ||
| 89 | break; | ||
| 90 | case V4L2_CID_CONTRAST: | ||
| 91 | err += ctrl->value ? sn9c102_i2c_write(cam, 0x05, | ||
| 92 | (ctrl->value-1) | 0x20) | ||
| 93 | : sn9c102_i2c_write(cam, 0x05, 0x00); | ||
| 94 | break; | ||
| 95 | case V4L2_CID_BRIGHTNESS: | ||
| 96 | err += sn9c102_i2c_write(cam, 0x06, ctrl->value); | ||
| 97 | break; | ||
| 98 | case V4L2_CID_SATURATION: | ||
| 99 | err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4); | ||
| 100 | break; | ||
| 101 | case V4L2_CID_HUE: | ||
| 102 | err += ctrl->value ? sn9c102_i2c_write(cam, 0x04, | ||
| 103 | (ctrl->value-1) | 0x20) | ||
| 104 | : sn9c102_i2c_write(cam, 0x04, 0x00); | ||
| 105 | break; | ||
| 106 | case V4L2_CID_DO_WHITE_BALANCE: | ||
| 107 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
| 108 | break; | ||
| 109 | case V4L2_CID_WHITENESS: | ||
| 110 | err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); | ||
| 111 | 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: | ||
| 116 | err += sn9c102_i2c_write(cam, 0x13, ctrl->value); | ||
| 117 | break; | ||
| 118 | case V4L2_CID_VFLIP: | ||
| 119 | err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); | ||
| 120 | 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: | ||
| 128 | err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80); | ||
| 129 | break; | ||
| 130 | case SN9C102_V4L2_CID_BAND_FILTER: | ||
| 131 | err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); | ||
| 132 | break; | ||
| 133 | default: | ||
| 134 | return -EINVAL; | ||
| 135 | } | ||
| 136 | |||
| 137 | return err ? -EIO : 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | |||
| 141 | static int ov7630_set_crop(struct sn9c102_device* cam, | ||
| 142 | const struct v4l2_rect* rect) | ||
| 143 | { | ||
| 144 | struct sn9c102_sensor* s = &ov7630; | ||
| 145 | int err = 0; | ||
| 146 | u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
| 147 | |||
| 148 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
| 149 | |||
| 150 | return err; | ||
| 151 | } | ||
| 152 | |||
| 153 | |||
| 154 | static int ov7630_set_pix_format(struct sn9c102_device* cam, | ||
| 155 | const struct v4l2_pix_format* pix) | ||
| 156 | { | ||
| 157 | int err = 0; | ||
| 158 | |||
| 159 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 160 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
| 161 | else | ||
| 162 | err += sn9c102_write_reg(cam, 0x50, 0x19); | ||
| 163 | |||
| 164 | return err; | ||
| 165 | } | ||
| 166 | |||
| 167 | |||
| 168 | static struct sn9c102_sensor ov7630 = { | ||
| 169 | .name = "OV7630", | ||
| 170 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
| 171 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
| 172 | .frequency = SN9C102_I2C_100KHZ, | ||
| 173 | .interface = SN9C102_I2C_2WIRES, | ||
| 174 | .i2c_slave_id = 0x21, | ||
| 175 | .init = &ov7630_init, | ||
| 176 | .qctrl = { | ||
| 177 | { | ||
| 178 | .id = V4L2_CID_GAIN, | ||
| 179 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 180 | .name = "global gain", | ||
| 181 | .minimum = 0x00, | ||
| 182 | .maximum = 0x3f, | ||
| 183 | .step = 0x01, | ||
| 184 | .default_value = 0x14, | ||
| 185 | .flags = 0, | ||
| 186 | }, | ||
| 187 | { | ||
| 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, | ||
| 219 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 220 | .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, | ||
| 242 | .maximum = 0xff, | ||
| 243 | .step = 0x01, | ||
| 244 | .default_value = 0x77, | ||
| 245 | .flags = 0, | ||
| 246 | }, | ||
| 247 | { | ||
| 248 | .id = V4L2_CID_BRIGHTNESS, | ||
| 249 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 250 | .name = "brightness", | ||
| 251 | .minimum = 0x00, | ||
| 252 | .maximum = 0xff, | ||
| 253 | .step = 0x01, | ||
| 254 | .default_value = 0xa0, | ||
| 255 | .flags = 0, | ||
| 256 | }, | ||
| 257 | { | ||
| 258 | .id = V4L2_CID_DO_WHITE_BALANCE, | ||
| 259 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 260 | .name = "white balance background: blue", | ||
| 261 | .minimum = 0x00, | ||
| 262 | .maximum = 0x3f, | ||
| 263 | .step = 0x01, | ||
| 264 | .default_value = 0x20, | ||
| 265 | .flags = 0, | ||
| 266 | }, | ||
| 267 | { | ||
| 268 | .id = V4L2_CID_WHITENESS, | ||
| 269 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 270 | .name = "white balance background: red", | ||
| 271 | .minimum = 0x00, | ||
| 272 | .maximum = 0x3f, | ||
| 273 | .step = 0x01, | ||
| 274 | .default_value = 0x20, | ||
| 275 | .flags = 0, | ||
| 276 | }, | ||
| 277 | { | ||
| 278 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
| 279 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 280 | .name = "auto white balance", | ||
| 281 | .minimum = 0x00, | ||
| 282 | .maximum = 0x01, | ||
| 283 | .step = 0x01, | ||
| 284 | .default_value = 0x01, | ||
| 285 | .flags = 0, | ||
| 286 | }, | ||
| 287 | { | ||
| 288 | .id = V4L2_CID_AUTOGAIN, | ||
| 289 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 290 | .name = "gain & exposure mode", | ||
| 291 | .minimum = 0x00, | ||
| 292 | .maximum = 0x03, | ||
| 293 | .step = 0x01, | ||
| 294 | .default_value = 0x00, | ||
| 295 | .flags = 0, | ||
| 296 | }, | ||
| 297 | { | ||
| 298 | .id = V4L2_CID_VFLIP, | ||
| 299 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 300 | .name = "vertical flip", | ||
| 301 | .minimum = 0x00, | ||
| 302 | .maximum = 0x01, | ||
| 303 | .step = 0x01, | ||
| 304 | .default_value = 0x01, | ||
| 305 | .flags = 0, | ||
| 306 | }, | ||
| 307 | { | ||
| 308 | .id = V4L2_CID_BLACK_LEVEL, | ||
| 309 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 310 | .name = "black pixel ratio", | ||
| 311 | .minimum = 0x01, | ||
| 312 | .maximum = 0x9a, | ||
| 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, | ||
| 324 | .default_value = 0x10, | ||
| 325 | .flags = 0, | ||
| 326 | }, | ||
| 327 | { | ||
| 328 | .id = SN9C102_V4L2_CID_BAND_FILTER, | ||
| 329 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 330 | .name = "band filter", | ||
| 331 | .minimum = 0x00, | ||
| 332 | .maximum = 0x01, | ||
| 333 | .step = 0x01, | ||
| 334 | .default_value = 0x00, | ||
| 335 | .flags = 0, | ||
| 336 | }, | ||
| 337 | { | ||
| 338 | .id = SN9C102_V4L2_CID_GAMMA, | ||
| 339 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 340 | .name = "rgb gamma", | ||
| 341 | .minimum = 0x00, | ||
| 342 | .maximum = 0x01, | ||
| 343 | .step = 0x01, | ||
| 344 | .default_value = 0x00, | ||
| 345 | .flags = 0, | ||
| 346 | }, | ||
| 347 | }, | ||
| 348 | .set_ctrl = &ov7630_set_ctrl, | ||
| 349 | .cropcap = { | ||
| 350 | .bounds = { | ||
| 351 | .left = 0, | ||
| 352 | .top = 0, | ||
| 353 | .width = 640, | ||
| 354 | .height = 480, | ||
| 355 | }, | ||
| 356 | .defrect = { | ||
| 357 | .left = 0, | ||
| 358 | .top = 0, | ||
| 359 | .width = 640, | ||
| 360 | .height = 480, | ||
| 361 | }, | ||
| 362 | }, | ||
| 363 | .set_crop = &ov7630_set_crop, | ||
| 364 | .pix_format = { | ||
| 365 | .width = 640, | ||
| 366 | .height = 480, | ||
| 367 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
| 368 | .priv = 8, | ||
| 369 | }, | ||
| 370 | .set_pix_format = &ov7630_set_pix_format | ||
| 371 | }; | ||
| 372 | |||
| 373 | |||
| 374 | int sn9c102_probe_ov7630(struct sn9c102_device* cam) | ||
| 375 | { | ||
| 376 | const struct usb_device_id ov7630_id_table[] = { | ||
| 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 | |||
| 388 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
| 389 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
| 390 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
| 391 | if (err) | ||
| 392 | return -EIO; | ||
| 393 | |||
| 394 | err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0); | ||
| 395 | if (err) | ||
| 396 | return -ENODEV; | ||
| 397 | |||
| 398 | sn9c102_attach_sensor(cam, &ov7630); | ||
| 399 | |||
| 400 | return 0; | ||
| 401 | } | ||
diff --git a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c deleted file mode 100644 index b1dee78abe04..000000000000 --- a/drivers/usb/media/sn9c102_pas106b.c +++ /dev/null | |||
| @@ -1,307 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera * | ||
| 3 | * Controllers * | ||
| 4 | * * | ||
| 5 | * Copyright (C) 2004-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 pas106b; | ||
| 27 | |||
| 28 | |||
| 29 | static int pas106b_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, 0x20, 0x19); | ||
| 38 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
| 39 | |||
| 40 | err += sn9c102_i2c_write(cam, 0x02, 0x0c); | ||
| 41 | err += sn9c102_i2c_write(cam, 0x05, 0x5a); | ||
| 42 | err += sn9c102_i2c_write(cam, 0x06, 0x88); | ||
| 43 | err += sn9c102_i2c_write(cam, 0x07, 0x80); | ||
| 44 | err += sn9c102_i2c_write(cam, 0x10, 0x06); | ||
| 45 | err += sn9c102_i2c_write(cam, 0x11, 0x06); | ||
| 46 | err += sn9c102_i2c_write(cam, 0x12, 0x00); | ||
| 47 | err += sn9c102_i2c_write(cam, 0x14, 0x02); | ||
| 48 | err += sn9c102_i2c_write(cam, 0x13, 0x01); | ||
| 49 | |||
| 50 | msleep(400); | ||
| 51 | |||
| 52 | return err; | ||
| 53 | } | ||
| 54 | |||
| 55 | |||
| 56 | static int pas106b_get_ctrl(struct sn9c102_device* cam, | ||
| 57 | struct v4l2_control* ctrl) | ||
| 58 | { | ||
| 59 | switch (ctrl->id) { | ||
| 60 | case V4L2_CID_EXPOSURE: | ||
| 61 | { | ||
| 62 | int r1 = sn9c102_i2c_read(cam, 0x03), | ||
| 63 | r2 = sn9c102_i2c_read(cam, 0x04); | ||
| 64 | if (r1 < 0 || r2 < 0) | ||
| 65 | return -EIO; | ||
| 66 | ctrl->value = (r1 << 4) | (r2 & 0x0f); | ||
| 67 | } | ||
| 68 | return 0; | ||
| 69 | case V4L2_CID_RED_BALANCE: | ||
| 70 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) | ||
| 71 | return -EIO; | ||
| 72 | ctrl->value &= 0x1f; | ||
| 73 | return 0; | ||
| 74 | case V4L2_CID_BLUE_BALANCE: | ||
| 75 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) | ||
| 76 | return -EIO; | ||
| 77 | ctrl->value &= 0x1f; | ||
| 78 | return 0; | ||
| 79 | case V4L2_CID_GAIN: | ||
| 80 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0) | ||
| 81 | return -EIO; | ||
| 82 | ctrl->value &= 0x1f; | ||
| 83 | return 0; | ||
| 84 | case V4L2_CID_CONTRAST: | ||
| 85 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) | ||
| 86 | return -EIO; | ||
| 87 | ctrl->value &= 0x07; | ||
| 88 | return 0; | ||
| 89 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 90 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0) | ||
| 91 | return -EIO; | ||
| 92 | ctrl->value = (ctrl->value & 0x1f) << 1; | ||
| 93 | return 0; | ||
| 94 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
| 95 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) | ||
| 96 | return -EIO; | ||
| 97 | ctrl->value &= 0xf8; | ||
| 98 | return 0; | ||
| 99 | default: | ||
| 100 | return -EINVAL; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | |||
| 105 | static int pas106b_set_ctrl(struct sn9c102_device* cam, | ||
| 106 | const struct v4l2_control* ctrl) | ||
| 107 | { | ||
| 108 | int err = 0; | ||
| 109 | |||
| 110 | switch (ctrl->id) { | ||
| 111 | case V4L2_CID_EXPOSURE: | ||
| 112 | err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4); | ||
| 113 | err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f); | ||
| 114 | break; | ||
| 115 | case V4L2_CID_RED_BALANCE: | ||
| 116 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
| 117 | break; | ||
| 118 | case V4L2_CID_BLUE_BALANCE: | ||
| 119 | err += sn9c102_i2c_write(cam, 0x09, ctrl->value); | ||
| 120 | break; | ||
| 121 | case V4L2_CID_GAIN: | ||
| 122 | err += sn9c102_i2c_write(cam, 0x0e, ctrl->value); | ||
| 123 | break; | ||
| 124 | case V4L2_CID_CONTRAST: | ||
| 125 | err += sn9c102_i2c_write(cam, 0x0f, ctrl->value); | ||
| 126 | break; | ||
| 127 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 128 | err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1); | ||
| 129 | err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1); | ||
| 130 | break; | ||
| 131 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
| 132 | err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3); | ||
| 133 | break; | ||
| 134 | default: | ||
| 135 | return -EINVAL; | ||
| 136 | } | ||
| 137 | err += sn9c102_i2c_write(cam, 0x13, 0x01); | ||
| 138 | |||
| 139 | return err ? -EIO : 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | |||
| 143 | static int pas106b_set_crop(struct sn9c102_device* cam, | ||
| 144 | const struct v4l2_rect* rect) | ||
| 145 | { | ||
| 146 | struct sn9c102_sensor* s = &pas106b; | ||
| 147 | int err = 0; | ||
| 148 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, | ||
| 149 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | ||
| 150 | |||
| 151 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
| 152 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
| 153 | |||
| 154 | return err; | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | static int pas106b_set_pix_format(struct sn9c102_device* cam, | ||
| 159 | const struct v4l2_pix_format* pix) | ||
| 160 | { | ||
| 161 | int err = 0; | ||
| 162 | |||
| 163 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 164 | err += sn9c102_write_reg(cam, 0x2c, 0x17); | ||
| 165 | else | ||
| 166 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
| 167 | |||
| 168 | return err; | ||
| 169 | } | ||
| 170 | |||
| 171 | |||
| 172 | static struct sn9c102_sensor pas106b = { | ||
| 173 | .name = "PAS106B", | ||
| 174 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
| 175 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
| 176 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | ||
| 177 | .interface = SN9C102_I2C_2WIRES, | ||
| 178 | .i2c_slave_id = 0x40, | ||
| 179 | .init = &pas106b_init, | ||
| 180 | .qctrl = { | ||
| 181 | { | ||
| 182 | .id = V4L2_CID_EXPOSURE, | ||
| 183 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 184 | .name = "exposure", | ||
| 185 | .minimum = 0x125, | ||
| 186 | .maximum = 0xfff, | ||
| 187 | .step = 0x001, | ||
| 188 | .default_value = 0x140, | ||
| 189 | .flags = 0, | ||
| 190 | }, | ||
| 191 | { | ||
| 192 | .id = V4L2_CID_GAIN, | ||
| 193 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 194 | .name = "global gain", | ||
| 195 | .minimum = 0x00, | ||
| 196 | .maximum = 0x1f, | ||
| 197 | .step = 0x01, | ||
| 198 | .default_value = 0x0d, | ||
| 199 | .flags = 0, | ||
| 200 | }, | ||
| 201 | { | ||
| 202 | .id = V4L2_CID_CONTRAST, | ||
| 203 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 204 | .name = "contrast", | ||
| 205 | .minimum = 0x00, | ||
| 206 | .maximum = 0x07, | ||
| 207 | .step = 0x01, | ||
| 208 | .default_value = 0x00, /* 0x00~0x03 have same effect */ | ||
| 209 | .flags = 0, | ||
| 210 | }, | ||
| 211 | { | ||
| 212 | .id = V4L2_CID_RED_BALANCE, | ||
| 213 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 214 | .name = "red balance", | ||
| 215 | .minimum = 0x00, | ||
| 216 | .maximum = 0x1f, | ||
| 217 | .step = 0x01, | ||
| 218 | .default_value = 0x04, | ||
| 219 | .flags = 0, | ||
| 220 | }, | ||
| 221 | { | ||
| 222 | .id = V4L2_CID_BLUE_BALANCE, | ||
| 223 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 224 | .name = "blue balance", | ||
| 225 | .minimum = 0x00, | ||
| 226 | .maximum = 0x1f, | ||
| 227 | .step = 0x01, | ||
| 228 | .default_value = 0x06, | ||
| 229 | .flags = 0, | ||
| 230 | }, | ||
| 231 | { | ||
| 232 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
| 233 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 234 | .name = "green balance", | ||
| 235 | .minimum = 0x00, | ||
| 236 | .maximum = 0x3e, | ||
| 237 | .step = 0x02, | ||
| 238 | .default_value = 0x02, | ||
| 239 | .flags = 0, | ||
| 240 | }, | ||
| 241 | { | ||
| 242 | .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, | ||
| 243 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 244 | .name = "DAC magnitude", | ||
| 245 | .minimum = 0x00, | ||
| 246 | .maximum = 0x1f, | ||
| 247 | .step = 0x01, | ||
| 248 | .default_value = 0x01, | ||
| 249 | .flags = 0, | ||
| 250 | }, | ||
| 251 | }, | ||
| 252 | .get_ctrl = &pas106b_get_ctrl, | ||
| 253 | .set_ctrl = &pas106b_set_ctrl, | ||
| 254 | .cropcap = { | ||
| 255 | .bounds = { | ||
| 256 | .left = 0, | ||
| 257 | .top = 0, | ||
| 258 | .width = 352, | ||
| 259 | .height = 288, | ||
| 260 | }, | ||
| 261 | .defrect = { | ||
| 262 | .left = 0, | ||
| 263 | .top = 0, | ||
| 264 | .width = 352, | ||
| 265 | .height = 288, | ||
| 266 | }, | ||
| 267 | }, | ||
| 268 | .set_crop = &pas106b_set_crop, | ||
| 269 | .pix_format = { | ||
| 270 | .width = 352, | ||
| 271 | .height = 288, | ||
| 272 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
| 273 | .priv = 8, /* we use this field as 'bits per pixel' */ | ||
| 274 | }, | ||
| 275 | .set_pix_format = &pas106b_set_pix_format | ||
| 276 | }; | ||
| 277 | |||
| 278 | |||
| 279 | int sn9c102_probe_pas106b(struct sn9c102_device* cam) | ||
| 280 | { | ||
| 281 | int r0 = 0, r1 = 0, err = 0; | ||
| 282 | unsigned int pid = 0; | ||
| 283 | |||
| 284 | /* | ||
| 285 | Minimal initialization to enable the I2C communication | ||
| 286 | NOTE: do NOT change the values! | ||
| 287 | */ | ||
| 288 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ | ||
| 289 | err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ | ||
| 290 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ | ||
| 291 | if (err) | ||
| 292 | return -EIO; | ||
| 293 | |||
| 294 | r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00); | ||
| 295 | r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01); | ||
| 296 | |||
| 297 | if (r0 < 0 || r1 < 0) | ||
| 298 | return -EIO; | ||
| 299 | |||
| 300 | pid = (r0 << 11) | ((r1 & 0xf0) >> 4); | ||
| 301 | if (pid != 0x007) | ||
| 302 | return -ENODEV; | ||
| 303 | |||
| 304 | sn9c102_attach_sensor(cam, &pas106b); | ||
| 305 | |||
| 306 | return 0; | ||
| 307 | } | ||
diff --git a/drivers/usb/media/sn9c102_pas202bca.c b/drivers/usb/media/sn9c102_pas202bca.c deleted file mode 100644 index 3453237055bb..000000000000 --- a/drivers/usb/media/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/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c deleted file mode 100644 index d068616ab337..000000000000 --- a/drivers/usb/media/sn9c102_pas202bcb.c +++ /dev/null | |||
| @@ -1,293 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera * | ||
| 3 | * Controllers * | ||
| 4 | * * | ||
| 5 | * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * | ||
| 6 | * <medaglia@undl.org.br> * | ||
| 7 | * http://cadu.homelinux.com:8080/ * | ||
| 8 | * * | ||
| 9 | * DAC Magnitude, exposure and green gain controls added by * | ||
| 10 | * Luca Risolia <luca.risolia@studio.unibo.it> * | ||
| 11 | * * | ||
| 12 | * This program is free software; you can redistribute it and/or modify * | ||
| 13 | * it under the terms of the GNU General Public License as published by * | ||
| 14 | * the Free Software Foundation; either version 2 of the License, or * | ||
| 15 | * (at your option) any later version. * | ||
| 16 | * * | ||
| 17 | * This program is distributed in the hope that it will be useful, * | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 20 | * GNU General Public License for more details. * | ||
| 21 | * * | ||
| 22 | * You should have received a copy of the GNU General Public License * | ||
| 23 | * along with this program; if not, write to the Free Software * | ||
| 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
| 25 | ***************************************************************************/ | ||
| 26 | |||
| 27 | #include <linux/delay.h> | ||
| 28 | #include "sn9c102_sensor.h" | ||
| 29 | |||
| 30 | |||
| 31 | static struct sn9c102_sensor pas202bcb; | ||
| 32 | |||
| 33 | |||
| 34 | static int pas202bcb_init(struct sn9c102_device* cam) | ||
| 35 | { | ||
| 36 | int err = 0; | ||
| 37 | |||
| 38 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
| 39 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
| 40 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
| 41 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
| 42 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
| 43 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
| 44 | |||
| 45 | err += sn9c102_i2c_write(cam, 0x02, 0x14); | ||
| 46 | err += sn9c102_i2c_write(cam, 0x03, 0x40); | ||
| 47 | err += sn9c102_i2c_write(cam, 0x0d, 0x2c); | ||
| 48 | err += sn9c102_i2c_write(cam, 0x0e, 0x01); | ||
| 49 | err += sn9c102_i2c_write(cam, 0x0f, 0xa9); | ||
| 50 | err += sn9c102_i2c_write(cam, 0x10, 0x08); | ||
| 51 | err += sn9c102_i2c_write(cam, 0x13, 0x63); | ||
| 52 | err += sn9c102_i2c_write(cam, 0x15, 0x70); | ||
| 53 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
| 54 | |||
| 55 | msleep(400); | ||
| 56 | |||
| 57 | return err; | ||
| 58 | } | ||
| 59 | |||
| 60 | |||
| 61 | static int pas202bcb_get_ctrl(struct sn9c102_device* cam, | ||
| 62 | struct v4l2_control* ctrl) | ||
| 63 | { | ||
| 64 | switch (ctrl->id) { | ||
| 65 | case V4L2_CID_EXPOSURE: | ||
| 66 | { | ||
| 67 | int r1 = sn9c102_i2c_read(cam, 0x04), | ||
| 68 | r2 = sn9c102_i2c_read(cam, 0x05); | ||
| 69 | if (r1 < 0 || r2 < 0) | ||
| 70 | return -EIO; | ||
| 71 | ctrl->value = (r1 << 6) | (r2 & 0x3f); | ||
| 72 | } | ||
| 73 | return 0; | ||
| 74 | case V4L2_CID_RED_BALANCE: | ||
| 75 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) | ||
| 76 | return -EIO; | ||
| 77 | ctrl->value &= 0x0f; | ||
| 78 | return 0; | ||
| 79 | case V4L2_CID_BLUE_BALANCE: | ||
| 80 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) | ||
| 81 | return -EIO; | ||
| 82 | ctrl->value &= 0x0f; | ||
| 83 | return 0; | ||
| 84 | case V4L2_CID_GAIN: | ||
| 85 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) | ||
| 86 | return -EIO; | ||
| 87 | ctrl->value &= 0x1f; | ||
| 88 | return 0; | ||
| 89 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 90 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) | ||
| 91 | return -EIO; | ||
| 92 | ctrl->value &= 0x0f; | ||
| 93 | return 0; | ||
| 94 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
| 95 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) | ||
| 96 | return -EIO; | ||
| 97 | return 0; | ||
| 98 | default: | ||
| 99 | return -EINVAL; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | |||
| 104 | static int pas202bcb_set_pix_format(struct sn9c102_device* cam, | ||
| 105 | const struct v4l2_pix_format* pix) | ||
| 106 | { | ||
| 107 | int err = 0; | ||
| 108 | |||
| 109 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 110 | err += sn9c102_write_reg(cam, 0x24, 0x17); | ||
| 111 | else | ||
| 112 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
| 113 | |||
| 114 | return err; | ||
| 115 | } | ||
| 116 | |||
| 117 | |||
| 118 | static int pas202bcb_set_ctrl(struct sn9c102_device* cam, | ||
| 119 | const struct v4l2_control* ctrl) | ||
| 120 | { | ||
| 121 | int err = 0; | ||
| 122 | |||
| 123 | switch (ctrl->id) { | ||
| 124 | case V4L2_CID_EXPOSURE: | ||
| 125 | err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); | ||
| 126 | err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); | ||
| 127 | break; | ||
| 128 | case V4L2_CID_RED_BALANCE: | ||
| 129 | err += sn9c102_i2c_write(cam, 0x09, ctrl->value); | ||
| 130 | break; | ||
| 131 | case V4L2_CID_BLUE_BALANCE: | ||
| 132 | err += sn9c102_i2c_write(cam, 0x07, ctrl->value); | ||
| 133 | break; | ||
| 134 | case V4L2_CID_GAIN: | ||
| 135 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value); | ||
| 136 | break; | ||
| 137 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
| 138 | err += sn9c102_i2c_write(cam, 0x08, ctrl->value); | ||
| 139 | break; | ||
| 140 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
| 141 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
| 142 | break; | ||
| 143 | default: | ||
| 144 | return -EINVAL; | ||
| 145 | } | ||
| 146 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
| 147 | |||
| 148 | return err ? -EIO : 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | |||
| 152 | static int pas202bcb_set_crop(struct sn9c102_device* cam, | ||
| 153 | const struct v4l2_rect* rect) | ||
| 154 | { | ||
| 155 | struct sn9c102_sensor* s = &pas202bcb; | ||
| 156 | int err = 0; | ||
| 157 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, | ||
| 158 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | ||
| 159 | |||
| 160 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
| 161 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
| 162 | |||
| 163 | return err; | ||
| 164 | } | ||
| 165 | |||
| 166 | |||
| 167 | static struct sn9c102_sensor pas202bcb = { | ||
| 168 | .name = "PAS202BCB", | ||
| 169 | .maintainer = "Carlos Eduardo Medaglia Dyonisio " | ||
| 170 | "<medaglia@undl.org.br>", | ||
| 171 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
| 172 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | ||
| 173 | .interface = SN9C102_I2C_2WIRES, | ||
| 174 | .i2c_slave_id = 0x40, | ||
| 175 | .init = &pas202bcb_init, | ||
| 176 | .qctrl = { | ||
| 177 | { | ||
| 178 | .id = V4L2_CID_EXPOSURE, | ||
| 179 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 180 | .name = "exposure", | ||
| 181 | .minimum = 0x01e5, | ||
| 182 | .maximum = 0x3fff, | ||
| 183 | .step = 0x0001, | ||
| 184 | .default_value = 0x01e5, | ||
| 185 | .flags = 0, | ||
| 186 | }, | ||
| 187 | { | ||
| 188 | .id = V4L2_CID_GAIN, | ||
| 189 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 190 | .name = "global gain", | ||
| 191 | .minimum = 0x00, | ||
| 192 | .maximum = 0x1f, | ||
| 193 | .step = 0x01, | ||
| 194 | .default_value = 0x0c, | ||
| 195 | .flags = 0, | ||
| 196 | }, | ||
| 197 | { | ||
| 198 | .id = V4L2_CID_RED_BALANCE, | ||
| 199 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 200 | .name = "red balance", | ||
| 201 | .minimum = 0x00, | ||
| 202 | .maximum = 0x0f, | ||
| 203 | .step = 0x01, | ||
| 204 | .default_value = 0x01, | ||
| 205 | .flags = 0, | ||
| 206 | }, | ||
| 207 | { | ||
| 208 | .id = V4L2_CID_BLUE_BALANCE, | ||
| 209 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 210 | .name = "blue balance", | ||
| 211 | .minimum = 0x00, | ||
| 212 | .maximum = 0x0f, | ||
| 213 | .step = 0x01, | ||
| 214 | .default_value = 0x05, | ||
| 215 | .flags = 0, | ||
| 216 | }, | ||
| 217 | { | ||
| 218 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
| 219 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 220 | .name = "green balance", | ||
| 221 | .minimum = 0x00, | ||
| 222 | .maximum = 0x0f, | ||
| 223 | .step = 0x01, | ||
| 224 | .default_value = 0x00, | ||
| 225 | .flags = 0, | ||
| 226 | }, | ||
| 227 | { | ||
| 228 | .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, | ||
| 229 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 230 | .name = "DAC magnitude", | ||
| 231 | .minimum = 0x00, | ||
| 232 | .maximum = 0xff, | ||
| 233 | .step = 0x01, | ||
| 234 | .default_value = 0x04, | ||
| 235 | .flags = 0, | ||
| 236 | }, | ||
| 237 | }, | ||
| 238 | .get_ctrl = &pas202bcb_get_ctrl, | ||
| 239 | .set_ctrl = &pas202bcb_set_ctrl, | ||
| 240 | .cropcap = { | ||
| 241 | .bounds = { | ||
| 242 | .left = 0, | ||
| 243 | .top = 0, | ||
| 244 | .width = 640, | ||
| 245 | .height = 480, | ||
| 246 | }, | ||
| 247 | .defrect = { | ||
| 248 | .left = 0, | ||
| 249 | .top = 0, | ||
| 250 | .width = 640, | ||
| 251 | .height = 480, | ||
| 252 | }, | ||
| 253 | }, | ||
| 254 | .set_crop = &pas202bcb_set_crop, | ||
| 255 | .pix_format = { | ||
| 256 | .width = 640, | ||
| 257 | .height = 480, | ||
| 258 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
| 259 | .priv = 8, | ||
| 260 | }, | ||
| 261 | .set_pix_format = &pas202bcb_set_pix_format | ||
| 262 | }; | ||
| 263 | |||
| 264 | |||
| 265 | int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) | ||
| 266 | { | ||
| 267 | int r0 = 0, r1 = 0, err = 0; | ||
| 268 | unsigned int pid = 0; | ||
| 269 | |||
| 270 | /* | ||
| 271 | * Minimal initialization to enable the I2C communication | ||
| 272 | * NOTE: do NOT change the values! | ||
| 273 | */ | ||
| 274 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ | ||
| 275 | err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */ | ||
| 276 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ | ||
| 277 | if (err) | ||
| 278 | return -EIO; | ||
| 279 | |||
| 280 | r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); | ||
| 281 | r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); | ||
| 282 | |||
| 283 | if (r0 < 0 || r1 < 0) | ||
| 284 | return -EIO; | ||
| 285 | |||
| 286 | pid = (r0 << 4) | ((r1 & 0xf0) >> 4); | ||
| 287 | if (pid != 0x017) | ||
| 288 | return -ENODEV; | ||
| 289 | |||
| 290 | sn9c102_attach_sensor(cam, &pas202bcb); | ||
| 291 | |||
| 292 | return 0; | ||
| 293 | } | ||
diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h deleted file mode 100644 index 2afd9e9d09bb..000000000000 --- a/drivers/usb/media/sn9c102_sensor.h +++ /dev/null | |||
| @@ -1,389 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * API for image sensors connected to the SN9C10x PC Camera Controllers * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2004-2006 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_SENSOR_H_ | ||
| 22 | #define _SN9C102_SENSOR_H_ | ||
| 23 | |||
| 24 | #include <linux/usb.h> | ||
| 25 | #include <linux/videodev.h> | ||
| 26 | #include <linux/device.h> | ||
| 27 | #include <linux/stddef.h> | ||
| 28 | #include <linux/errno.h> | ||
| 29 | #include <asm/types.h> | ||
| 30 | |||
| 31 | struct sn9c102_device; | ||
| 32 | struct sn9c102_sensor; | ||
| 33 | |||
| 34 | /*****************************************************************************/ | ||
| 35 | |||
| 36 | /* | ||
| 37 | OVERVIEW. | ||
| 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 | ||
| 40 | below. In the most general case, to support a sensor there are three steps | ||
| 41 | you have to follow: | ||
| 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 | ||
| 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 | ||
| 46 | below); | ||
| 47 | 3) implement the methods that you want/need (and fill the rest of the main | ||
| 48 | structure accordingly). | ||
| 49 | "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do | ||
| 50 | NOT need to touch the source code of the core module for the things to work | ||
| 51 | properly, unless you find bugs or flaws in it. Finally, do not forget to | ||
| 52 | read the V4L2 API for completeness. | ||
| 53 | */ | ||
| 54 | |||
| 55 | /*****************************************************************************/ | ||
| 56 | |||
| 57 | /* | ||
| 58 | Probing functions: on success, you must attach the sensor to the camera | ||
| 59 | by calling sn9c102_attach_sensor() provided below. | ||
| 60 | To enable the I2C communication, you might need to perform a really basic | ||
| 61 | initialization of the SN9C10X chip by using the write function declared | ||
| 62 | ahead. | ||
| 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 | }; | ||
| 91 | |||
| 92 | /* Device identification */ | ||
| 93 | extern struct sn9c102_device* | ||
| 94 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id); | ||
| 95 | |||
| 96 | /* Attach a probed sensor to the camera. */ | ||
| 97 | extern void | ||
| 98 | sn9c102_attach_sensor(struct sn9c102_device* cam, | ||
| 99 | struct sn9c102_sensor* sensor); | ||
| 100 | |||
| 101 | /* | ||
| 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 | ||
| 163 | otherwise. NOTE that a real read operation is not supported by the SN9C10X | ||
| 164 | 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 | ||
| 166 | on the register (0 if it has never been written), the usual -1 on error. | ||
| 167 | */ | ||
| 168 | |||
| 169 | /* The "try" I2C I/O versions are used when probing the sensor */ | ||
| 170 | extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, | ||
| 171 | u8 address, u8 value); | ||
| 172 | extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, | ||
| 173 | u8 address); | ||
| 174 | |||
| 175 | /* | ||
| 176 | 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 | ||
| 178 | 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 | ||
| 180 | 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 | ||
| 182 | buffer pointed by 'buffer'. Both the functions return -1 on error; the write | ||
| 183 | version returns 0 on success, while the read version returns the first read | ||
| 184 | byte. | ||
| 185 | */ | ||
| 186 | extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, | ||
| 187 | struct sn9c102_sensor* sensor, u8 n, | ||
| 188 | u8 data0, u8 data1, u8 data2, u8 data3, | ||
| 189 | u8 data4, u8 data5); | ||
| 190 | extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, | ||
| 191 | struct sn9c102_sensor* sensor, u8 data0, | ||
| 192 | u8 data1, u8 n, u8 buffer[]); | ||
| 193 | |||
| 194 | /* To be used after the sensor struct has been attached to the camera struct */ | ||
| 195 | extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); | ||
| 196 | extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); | ||
| 197 | |||
| 198 | /* I/O on registers in the bridge. Could be used by the sensor methods too */ | ||
| 199 | 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); | ||
| 201 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); | ||
| 202 | |||
| 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 | /*****************************************************************************/ | ||
| 214 | |||
| 215 | enum sn9c102_i2c_sysfs_ops { | ||
| 216 | SN9C102_I2C_READ = 0x01, | ||
| 217 | SN9C102_I2C_WRITE = 0x02, | ||
| 218 | }; | ||
| 219 | |||
| 220 | enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */ | ||
| 221 | SN9C102_I2C_100KHZ = 0x01, | ||
| 222 | SN9C102_I2C_400KHZ = 0x02, | ||
| 223 | }; | ||
| 224 | |||
| 225 | enum sn9c102_i2c_interface { | ||
| 226 | SN9C102_I2C_2WIRES, | ||
| 227 | SN9C102_I2C_3WIRES, | ||
| 228 | }; | ||
| 229 | |||
| 230 | #define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 | ||
| 231 | |||
| 232 | struct sn9c102_sensor { | ||
| 233 | char name[32], /* sensor name */ | ||
| 234 | maintainer[64]; /* name of the mantainer <email> */ | ||
| 235 | |||
| 236 | /* Supported operations through the 'sysfs' interface */ | ||
| 237 | enum sn9c102_i2c_sysfs_ops sysfs_ops; | ||
| 238 | |||
| 239 | /* | ||
| 240 | These sensor capabilities must be provided if the SN9C10X controller | ||
| 241 | needs to communicate through the sensor serial interface by using | ||
| 242 | at least one of the i2c functions available. | ||
| 243 | */ | ||
| 244 | enum sn9c102_i2c_frequency frequency; | ||
| 245 | enum sn9c102_i2c_interface interface; | ||
| 246 | |||
| 247 | /* | ||
| 248 | This identifier must be provided if the image sensor implements | ||
| 249 | the standard I2C protocol. | ||
| 250 | */ | ||
| 251 | u8 i2c_slave_id; /* reg. 0x09 */ | ||
| 252 | |||
| 253 | /* | ||
| 254 | NOTE: Where not noted,most of the functions below are not mandatory. | ||
| 255 | Set to null if you do not implement them. If implemented, | ||
| 256 | they must return 0 on success, the proper error otherwise. | ||
| 257 | */ | ||
| 258 | |||
| 259 | int (*init)(struct sn9c102_device* cam); | ||
| 260 | /* | ||
| 261 | This function will be called after the sensor has been attached. | ||
| 262 | 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 | ||
| 264 | setup picture settings like brightness, contrast, etc.. here, if | ||
| 265 | the corrisponding controls are implemented (see below), since | ||
| 266 | they are adjusted in the core driver by calling the set_ctrl() | ||
| 267 | method after init(), where the arguments are the default values | ||
| 268 | specified in the v4l2_queryctrl list of supported controls; | ||
| 269 | Same suggestions apply for other settings, _if_ the corresponding | ||
| 270 | methods are present; if not, the initialization must configure the | ||
| 271 | sensor according to the default configuration structures below. | ||
| 272 | */ | ||
| 273 | |||
| 274 | struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS]; | ||
| 275 | /* | ||
| 276 | Optional list of default controls, defined as indicated in the | ||
| 277 | V4L2 API. Menu type controls are not handled by this interface. | ||
| 278 | */ | ||
| 279 | |||
| 280 | int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); | ||
| 281 | int (*set_ctrl)(struct sn9c102_device* cam, | ||
| 282 | const struct v4l2_control* ctrl); | ||
| 283 | /* | ||
| 284 | You must implement at least the set_ctrl method if you have defined | ||
| 285 | the list above. The returned value must follow the V4L2 | ||
| 286 | specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER | ||
| 287 | are not supported by this driver, so do not implement them. Also, | ||
| 288 | you don't have to check whether the passed values are out of bounds, | ||
| 289 | given that this is done by the core module. | ||
| 290 | */ | ||
| 291 | |||
| 292 | struct v4l2_cropcap cropcap; | ||
| 293 | /* | ||
| 294 | Think the image sensor as a grid of R,G,B monochromatic pixels | ||
| 295 | disposed according to a particular Bayer pattern, which describes | ||
| 296 | the complete array of pixels, from (0,0) to (xmax, ymax). We will | ||
| 297 | use this coordinate system from now on. It is assumed the sensor | ||
| 298 | chip can be programmed to capture/transmit a subsection of that | ||
| 299 | array of pixels: we will call this subsection "active window". | ||
| 300 | It is not always true that the largest achievable active window can | ||
| 301 | cover the whole array of pixels. The V4L2 API defines another | ||
| 302 | area called "source rectangle", which, in turn, is a subrectangle of | ||
| 303 | the active window. The SN9C10X chip is always programmed to read the | ||
| 304 | source rectangle. | ||
| 305 | The bounds of both the active window and the source rectangle are | ||
| 306 | specified in the cropcap substructures 'bounds' and 'defrect'. | ||
| 307 | By default, the source rectangle should cover the largest possible | ||
| 308 | area. Again, it is not always true that the largest source rectangle | ||
| 309 | can cover the entire active window, although it is a rare case for | ||
| 310 | the hardware we have. The bounds of the source rectangle _must_ be | ||
| 311 | multiple of 16 and must use the same coordinate system as indicated | ||
| 312 | before; their centers shall align initially. | ||
| 313 | If necessary, the sensor chip must be initialized during init() to | ||
| 314 | set the bounds of the active sensor window; however, by default, it | ||
| 315 | usually covers the largest achievable area (maxwidth x maxheight) | ||
| 316 | of pixels, so no particular initialization is needed, if you have | ||
| 317 | defined the correct default bounds in the structures. | ||
| 318 | See the V4L2 API for further details. | ||
| 319 | NOTE: once you have defined the bounds of the active window | ||
| 320 | (struct cropcap.bounds) you must not change them.anymore. | ||
| 321 | Only 'bounds' and 'defrect' fields are mandatory, other fields | ||
| 322 | will be ignored. | ||
| 323 | */ | ||
| 324 | |||
| 325 | int (*set_crop)(struct sn9c102_device* cam, | ||
| 326 | const struct v4l2_rect* rect); | ||
| 327 | /* | ||
| 328 | To be called on VIDIOC_C_SETCROP. The core module always calls a | ||
| 329 | default routine which configures the appropriate SN9C10X regs (also | ||
| 330 | scaling), but you may need to override/adjust specific stuff. | ||
| 331 | 'rect' contains width and height values that are multiple of 16: in | ||
| 332 | case you override the default function, you always have to program | ||
| 333 | the chip to match those values; on error return the corresponding | ||
| 334 | error code without rolling back. | ||
| 335 | NOTE: in case, you must program the SN9C10X chip to get rid of | ||
| 336 | 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 | ||
| 338 | real RGB data (see regs 0x12, 0x13) (having set H_SIZE and, | ||
| 339 | V_SIZE you don't have to care about blank pixels or blank | ||
| 340 | lines at the end of each line or frame). | ||
| 341 | */ | ||
| 342 | |||
| 343 | struct v4l2_pix_format pix_format; | ||
| 344 | /* | ||
| 345 | What you have to define here are: 1) initial 'width' and 'height' of | ||
| 346 | the target rectangle 2) the initial 'pixelformat', which can be | ||
| 347 | either V4L2_PIX_FMT_SN9C10X (for compressed video) or | ||
| 348 | V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the | ||
| 349 | number of bits per pixel for uncompressed video, 8 or 9 (despite the | ||
| 350 | current value of 'pixelformat'). | ||
| 351 | 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 | ||
| 353 | suggest 1/1. | ||
| 354 | NOTE 2: The initial compression quality is defined by the first bit | ||
| 355 | 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 | ||
| 357 | rid of any blank pixels, so that the output of the sensor | ||
| 358 | matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). | ||
| 359 | */ | ||
| 360 | |||
| 361 | int (*set_pix_format)(struct sn9c102_device* cam, | ||
| 362 | const struct v4l2_pix_format* pix); | ||
| 363 | /* | ||
| 364 | To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to | ||
| 365 | SN9C10X pixel format or viceversa. On error return the corresponding | ||
| 366 | error code without rolling back. | ||
| 367 | */ | ||
| 368 | |||
| 369 | /* | ||
| 370 | Do NOT write to the data below, it's READ ONLY. It is used by the | ||
| 371 | core module to store successfully updated values of the above | ||
| 372 | settings, for rollbacks..etc..in case of errors during atomic I/O | ||
| 373 | */ | ||
| 374 | struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS]; | ||
| 375 | struct v4l2_rect _rect; | ||
| 376 | }; | ||
| 377 | |||
| 378 | /*****************************************************************************/ | ||
| 379 | |||
| 380 | /* Private ioctl's for control settings supported by some image sensors */ | ||
| 381 | #define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE | ||
| 382 | #define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 | ||
| 383 | #define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2 | ||
| 384 | #define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3 | ||
| 385 | #define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4 | ||
| 386 | #define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5 | ||
| 387 | #define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6 | ||
| 388 | |||
| 389 | #endif /* _SN9C102_SENSOR_H_ */ | ||
diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c deleted file mode 100644 index 2e08c552f40a..000000000000 --- a/drivers/usb/media/sn9c102_tas5110c1b.c +++ /dev/null | |||
| @@ -1,159 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera * | ||
| 3 | * Controllers * | ||
| 4 | * * | ||
| 5 | * Copyright (C) 2004-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 "sn9c102_sensor.h" | ||
| 23 | |||
| 24 | |||
| 25 | static struct sn9c102_sensor tas5110c1b; | ||
| 26 | |||
| 27 | |||
| 28 | static int tas5110c1b_init(struct sn9c102_device* cam) | ||
| 29 | { | ||
| 30 | int err = 0; | ||
| 31 | |||
| 32 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
| 33 | err += sn9c102_write_reg(cam, 0x44, 0x01); | ||
| 34 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
| 35 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
| 36 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | ||
| 37 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
| 38 | err += sn9c102_write_reg(cam, 0x06, 0x18); | ||
| 39 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
| 40 | |||
| 41 | err += sn9c102_i2c_write(cam, 0xc0, 0x80); | ||
| 42 | |||
| 43 | return err; | ||
| 44 | } | ||
| 45 | |||
| 46 | |||
| 47 | static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, | ||
| 48 | const struct v4l2_control* ctrl) | ||
| 49 | { | ||
| 50 | int err = 0; | ||
| 51 | |||
| 52 | switch (ctrl->id) { | ||
| 53 | case V4L2_CID_GAIN: | ||
| 54 | err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); | ||
| 55 | break; | ||
| 56 | default: | ||
| 57 | return -EINVAL; | ||
| 58 | } | ||
| 59 | |||
| 60 | return err ? -EIO : 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | |||
| 64 | static int tas5110c1b_set_crop(struct sn9c102_device* cam, | ||
| 65 | const struct v4l2_rect* rect) | ||
| 66 | { | ||
| 67 | struct sn9c102_sensor* s = &tas5110c1b; | ||
| 68 | int err = 0; | ||
| 69 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, | ||
| 70 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; | ||
| 71 | |||
| 72 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
| 73 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
| 74 | |||
| 75 | /* Don't change ! */ | ||
| 76 | err += sn9c102_write_reg(cam, 0x14, 0x1a); | ||
| 77 | err += sn9c102_write_reg(cam, 0x0a, 0x1b); | ||
| 78 | err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); | ||
| 79 | |||
| 80 | return err; | ||
| 81 | } | ||
| 82 | |||
| 83 | |||
| 84 | static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, | ||
| 85 | const struct v4l2_pix_format* pix) | ||
| 86 | { | ||
| 87 | int err = 0; | ||
| 88 | |||
| 89 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 90 | err += sn9c102_write_reg(cam, 0x2b, 0x19); | ||
| 91 | else | ||
| 92 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
| 93 | |||
| 94 | return err; | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 98 | static struct sn9c102_sensor tas5110c1b = { | ||
| 99 | .name = "TAS5110C1B", | ||
| 100 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
| 101 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
| 102 | .frequency = SN9C102_I2C_100KHZ, | ||
| 103 | .interface = SN9C102_I2C_3WIRES, | ||
| 104 | .init = &tas5110c1b_init, | ||
| 105 | .qctrl = { | ||
| 106 | { | ||
| 107 | .id = V4L2_CID_GAIN, | ||
| 108 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 109 | .name = "global gain", | ||
| 110 | .minimum = 0x00, | ||
| 111 | .maximum = 0xf6, | ||
| 112 | .step = 0x01, | ||
| 113 | .default_value = 0x40, | ||
| 114 | .flags = 0, | ||
| 115 | }, | ||
| 116 | }, | ||
| 117 | .set_ctrl = &tas5110c1b_set_ctrl, | ||
| 118 | .cropcap = { | ||
| 119 | .bounds = { | ||
| 120 | .left = 0, | ||
| 121 | .top = 0, | ||
| 122 | .width = 352, | ||
| 123 | .height = 288, | ||
| 124 | }, | ||
| 125 | .defrect = { | ||
| 126 | .left = 0, | ||
| 127 | .top = 0, | ||
| 128 | .width = 352, | ||
| 129 | .height = 288, | ||
| 130 | }, | ||
| 131 | }, | ||
| 132 | .set_crop = &tas5110c1b_set_crop, | ||
| 133 | .pix_format = { | ||
| 134 | .width = 352, | ||
| 135 | .height = 288, | ||
| 136 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
| 137 | .priv = 8, | ||
| 138 | }, | ||
| 139 | .set_pix_format = &tas5110c1b_set_pix_format | ||
| 140 | }; | ||
| 141 | |||
| 142 | |||
| 143 | int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) | ||
| 144 | { | ||
| 145 | const struct usb_device_id tas5110c1b_id_table[] = { | ||
| 146 | { USB_DEVICE(0x0c45, 0x6001), }, | ||
| 147 | { USB_DEVICE(0x0c45, 0x6005), }, | ||
| 148 | { USB_DEVICE(0x0c45, 0x60ab), }, | ||
| 149 | { } | ||
| 150 | }; | ||
| 151 | |||
| 152 | /* Sensor detection is based on USB pid/vid */ | ||
| 153 | if (!sn9c102_match_id(cam, tas5110c1b_id_table)) | ||
| 154 | return -ENODEV; | ||
| 155 | |||
| 156 | sn9c102_attach_sensor(cam, &tas5110c1b); | ||
| 157 | |||
| 158 | return 0; | ||
| 159 | } | ||
diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c deleted file mode 100644 index c7b339740bbf..000000000000 --- a/drivers/usb/media/sn9c102_tas5130d1b.c +++ /dev/null | |||
| @@ -1,169 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera * | ||
| 3 | * Controllers * | ||
| 4 | * * | ||
| 5 | * Copyright (C) 2004-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 "sn9c102_sensor.h" | ||
| 23 | |||
| 24 | |||
| 25 | static struct sn9c102_sensor tas5130d1b; | ||
| 26 | |||
| 27 | |||
| 28 | static int tas5130d1b_init(struct sn9c102_device* cam) | ||
| 29 | { | ||
| 30 | int err = 0; | ||
| 31 | |||
| 32 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
| 33 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
| 34 | err += sn9c102_write_reg(cam, 0x04, 0x01); | ||
| 35 | err += sn9c102_write_reg(cam, 0x01, 0x10); | ||
| 36 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
| 37 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
| 38 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
| 39 | err += sn9c102_write_reg(cam, 0x07, 0x18); | ||
| 40 | |||
| 41 | return err; | ||
| 42 | } | ||
| 43 | |||
| 44 | |||
| 45 | static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, | ||
| 46 | const struct v4l2_control* ctrl) | ||
| 47 | { | ||
| 48 | int err = 0; | ||
| 49 | |||
| 50 | switch (ctrl->id) { | ||
| 51 | case V4L2_CID_GAIN: | ||
| 52 | err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); | ||
| 53 | break; | ||
| 54 | case V4L2_CID_EXPOSURE: | ||
| 55 | err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value); | ||
| 56 | break; | ||
| 57 | default: | ||
| 58 | return -EINVAL; | ||
| 59 | } | ||
| 60 | |||
| 61 | return err ? -EIO : 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | |||
| 65 | static int tas5130d1b_set_crop(struct sn9c102_device* cam, | ||
| 66 | const struct v4l2_rect* rect) | ||
| 67 | { | ||
| 68 | struct sn9c102_sensor* s = &tas5130d1b; | ||
| 69 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, | ||
| 70 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; | ||
| 71 | int err = 0; | ||
| 72 | |||
| 73 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
| 74 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
| 75 | |||
| 76 | /* Do NOT change! */ | ||
| 77 | err += sn9c102_write_reg(cam, 0x1f, 0x1a); | ||
| 78 | err += sn9c102_write_reg(cam, 0x1a, 0x1b); | ||
| 79 | err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); | ||
| 80 | |||
| 81 | return err; | ||
| 82 | } | ||
| 83 | |||
| 84 | |||
| 85 | static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, | ||
| 86 | const struct v4l2_pix_format* pix) | ||
| 87 | { | ||
| 88 | int err = 0; | ||
| 89 | |||
| 90 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
| 91 | err += sn9c102_write_reg(cam, 0x63, 0x19); | ||
| 92 | else | ||
| 93 | err += sn9c102_write_reg(cam, 0xf3, 0x19); | ||
| 94 | |||
| 95 | return err; | ||
| 96 | } | ||
| 97 | |||
| 98 | |||
| 99 | static struct sn9c102_sensor tas5130d1b = { | ||
| 100 | .name = "TAS5130D1B", | ||
| 101 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
| 102 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
| 103 | .frequency = SN9C102_I2C_100KHZ, | ||
| 104 | .interface = SN9C102_I2C_3WIRES, | ||
| 105 | .init = &tas5130d1b_init, | ||
| 106 | .qctrl = { | ||
| 107 | { | ||
| 108 | .id = V4L2_CID_GAIN, | ||
| 109 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 110 | .name = "global gain", | ||
| 111 | .minimum = 0x00, | ||
| 112 | .maximum = 0xf6, | ||
| 113 | .step = 0x02, | ||
| 114 | .default_value = 0x00, | ||
| 115 | .flags = 0, | ||
| 116 | }, | ||
| 117 | { | ||
| 118 | .id = V4L2_CID_EXPOSURE, | ||
| 119 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 120 | .name = "exposure", | ||
| 121 | .minimum = 0x00, | ||
| 122 | .maximum = 0x47, | ||
| 123 | .step = 0x01, | ||
| 124 | .default_value = 0x00, | ||
| 125 | .flags = 0, | ||
| 126 | }, | ||
| 127 | }, | ||
| 128 | .set_ctrl = &tas5130d1b_set_ctrl, | ||
| 129 | .cropcap = { | ||
| 130 | .bounds = { | ||
| 131 | .left = 0, | ||
| 132 | .top = 0, | ||
| 133 | .width = 640, | ||
| 134 | .height = 480, | ||
| 135 | }, | ||
| 136 | .defrect = { | ||
| 137 | .left = 0, | ||
| 138 | .top = 0, | ||
| 139 | .width = 640, | ||
| 140 | .height = 480, | ||
| 141 | }, | ||
| 142 | }, | ||
| 143 | .set_crop = &tas5130d1b_set_crop, | ||
| 144 | .pix_format = { | ||
| 145 | .width = 640, | ||
| 146 | .height = 480, | ||
| 147 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
| 148 | .priv = 8, | ||
| 149 | }, | ||
| 150 | .set_pix_format = &tas5130d1b_set_pix_format | ||
| 151 | }; | ||
| 152 | |||
| 153 | |||
| 154 | int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) | ||
| 155 | { | ||
| 156 | const struct usb_device_id tas5130d1b_id_table[] = { | ||
| 157 | { USB_DEVICE(0x0c45, 0x6025), }, | ||
| 158 | { USB_DEVICE(0x0c45, 0x60aa), }, | ||
| 159 | { } | ||
| 160 | }; | ||
| 161 | |||
| 162 | /* Sensor detection is based on USB pid/vid */ | ||
| 163 | if (!sn9c102_match_id(cam, tas5130d1b_id_table)) | ||
| 164 | return -ENODEV; | ||
| 165 | |||
| 166 | sn9c102_attach_sensor(cam, &tas5130d1b); | ||
| 167 | |||
| 168 | return 0; | ||
| 169 | } | ||
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c deleted file mode 100644 index 9636da20748d..000000000000 --- a/drivers/usb/media/stv680.c +++ /dev/null | |||
| @@ -1,1508 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net) | ||
| 3 | * | ||
| 4 | * Thanks to STMicroelectronics for information on the usb commands, and | ||
| 5 | * to Steve Miller at STM for his help and encouragement while I was | ||
| 6 | * writing this driver. | ||
| 7 | * | ||
| 8 | * This driver is based heavily on the | ||
| 9 | * Endpoints (formerly known as AOX) se401 USB Camera Driver | ||
| 10 | * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) | ||
| 11 | * | ||
| 12 | * Still somewhat based on the Linux ov511 driver. | ||
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or modify it | ||
| 15 | * under the terms of the GNU General Public License as published by the | ||
| 16 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 17 | * option) any later version. | ||
| 18 | * | ||
| 19 | * This program is distributed in the hope that it will be useful, but | ||
| 20 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 21 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 22 | * for more details. | ||
| 23 | * | ||
| 24 | * You should have received a copy of the GNU General Public License | ||
| 25 | * along with this program; if not, write to the Free Software Foundation, | ||
| 26 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 27 | * | ||
| 28 | * History: | ||
| 29 | * ver 0.1 October, 2001. Initial attempt. | ||
| 30 | * | ||
| 31 | * ver 0.2 November, 2001. Fixed asbility to resize, added brightness | ||
| 32 | * function, made more stable (?) | ||
| 33 | * | ||
| 34 | * ver 0.21 Nov, 2001. Added gamma correction and white balance, | ||
| 35 | * due to Alexander Schwartz. Still trying to | ||
| 36 | * improve stablility. Moved stuff into stv680.h | ||
| 37 | * | ||
| 38 | * ver 0.22 Nov, 2001. Added sharpen function (by Michael Sweet, | ||
| 39 | * mike@easysw.com) from GIMP, also used in pencam. | ||
| 40 | * Simple, fast, good integer math routine. | ||
| 41 | * | ||
| 42 | * ver 0.23 Dec, 2001 (gkh) | ||
| 43 | * Took out sharpen function, ran code through | ||
| 44 | * Lindent, and did other minor tweaks to get | ||
| 45 | * things to work properly with 2.5.1 | ||
| 46 | * | ||
| 47 | * ver 0.24 Jan, 2002 (kjs) | ||
| 48 | * Fixed the problem with webcam crashing after | ||
| 49 | * two pictures. Changed the way pic is halved to | ||
| 50 | * improve quality. Got rid of green line around | ||
| 51 | * frame. Fix brightness reset when changing size | ||
| 52 | * bug. Adjusted gamma filters slightly. | ||
| 53 | * | ||
| 54 | * ver 0.25 Jan, 2002 (kjs) | ||
| 55 | * Fixed a bug in which the driver sometimes attempted | ||
| 56 | * to set to a non-supported size. This allowed | ||
| 57 | * gnomemeeting to work. | ||
| 58 | * Fixed proc entry removal bug. | ||
| 59 | */ | ||
| 60 | |||
| 61 | #include <linux/config.h> | ||
| 62 | #include <linux/module.h> | ||
| 63 | #include <linux/init.h> | ||
| 64 | #include <linux/vmalloc.h> | ||
| 65 | #include <linux/slab.h> | ||
| 66 | #include <linux/pagemap.h> | ||
| 67 | #include <linux/errno.h> | ||
| 68 | #include <linux/videodev.h> | ||
| 69 | #include <linux/usb.h> | ||
| 70 | #include <linux/mutex.h> | ||
| 71 | |||
| 72 | #include "stv680.h" | ||
| 73 | |||
| 74 | static int video_nr = -1; | ||
| 75 | static int swapRGB = 0; /* default for auto sleect */ | ||
| 76 | static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */ | ||
| 77 | |||
| 78 | static unsigned int debug = 0; | ||
| 79 | |||
| 80 | #define PDEBUG(level, fmt, args...) \ | ||
| 81 | do { \ | ||
| 82 | if (debug >= level) \ | ||
| 83 | info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \ | ||
| 84 | } while (0) | ||
| 85 | |||
| 86 | |||
| 87 | /* | ||
| 88 | * Version Information | ||
| 89 | */ | ||
| 90 | #define DRIVER_VERSION "v0.25" | ||
| 91 | #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>" | ||
| 92 | #define DRIVER_DESC "STV0680 USB Camera Driver" | ||
| 93 | |||
| 94 | MODULE_AUTHOR (DRIVER_AUTHOR); | ||
| 95 | MODULE_DESCRIPTION (DRIVER_DESC); | ||
| 96 | MODULE_LICENSE ("GPL"); | ||
| 97 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
| 98 | MODULE_PARM_DESC (debug, "Debug enabled or not"); | ||
| 99 | module_param(swapRGB_on, int, 0); | ||
| 100 | MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never"); | ||
| 101 | module_param(video_nr, int, 0); | ||
| 102 | |||
| 103 | /******************************************************************** | ||
| 104 | * | ||
| 105 | * Memory management | ||
| 106 | * | ||
| 107 | * This is a shameless copy from the USB-cpia driver (linux kernel | ||
| 108 | * version 2.3.29 or so, I have no idea what this code actually does ;). | ||
| 109 | * Actually it seems to be a copy of a shameless copy of the bttv-driver. | ||
| 110 | * Or that is a copy of a shameless copy of ... (To the powers: is there | ||
| 111 | * no generic kernel-function to do this sort of stuff?) | ||
| 112 | * | ||
| 113 | * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says | ||
| 114 | * there will be one, but apparentely not yet -jerdfelt | ||
| 115 | * | ||
| 116 | * So I copied it again for the ov511 driver -claudio | ||
| 117 | * | ||
| 118 | * Same for the se401 driver -Jeroen | ||
| 119 | * | ||
| 120 | * And the STV0680 driver - Kevin | ||
| 121 | ********************************************************************/ | ||
| 122 | static void *rvmalloc (unsigned long size) | ||
| 123 | { | ||
| 124 | void *mem; | ||
| 125 | unsigned long adr; | ||
| 126 | |||
| 127 | size = PAGE_ALIGN(size); | ||
| 128 | mem = vmalloc_32 (size); | ||
| 129 | if (!mem) | ||
| 130 | return NULL; | ||
| 131 | |||
| 132 | memset (mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
| 133 | adr = (unsigned long) mem; | ||
| 134 | while (size > 0) { | ||
| 135 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
| 136 | adr += PAGE_SIZE; | ||
| 137 | size -= PAGE_SIZE; | ||
| 138 | } | ||
| 139 | return mem; | ||
| 140 | } | ||
| 141 | |||
| 142 | static void rvfree (void *mem, unsigned long size) | ||
| 143 | { | ||
| 144 | unsigned long adr; | ||
| 145 | |||
| 146 | if (!mem) | ||
| 147 | return; | ||
| 148 | |||
| 149 | adr = (unsigned long) mem; | ||
| 150 | while ((long) size > 0) { | ||
| 151 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
| 152 | adr += PAGE_SIZE; | ||
| 153 | size -= PAGE_SIZE; | ||
| 154 | } | ||
| 155 | vfree (mem); | ||
| 156 | } | ||
| 157 | |||
| 158 | |||
| 159 | /********************************************************************* | ||
| 160 | * pencam read/write functions | ||
| 161 | ********************************************************************/ | ||
| 162 | |||
| 163 | static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size) | ||
| 164 | { | ||
| 165 | int ret = -1; | ||
| 166 | |||
| 167 | switch (set) { | ||
| 168 | case 0: /* 0xc1 */ | ||
| 169 | ret = usb_control_msg (stv680->udev, | ||
| 170 | usb_rcvctrlpipe (stv680->udev, 0), | ||
| 171 | req, | ||
| 172 | (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), | ||
| 173 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
| 174 | break; | ||
| 175 | |||
| 176 | case 1: /* 0x41 */ | ||
| 177 | ret = usb_control_msg (stv680->udev, | ||
| 178 | usb_sndctrlpipe (stv680->udev, 0), | ||
| 179 | req, | ||
| 180 | (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), | ||
| 181 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
| 182 | break; | ||
| 183 | |||
| 184 | case 2: /* 0x80 */ | ||
| 185 | ret = usb_control_msg (stv680->udev, | ||
| 186 | usb_rcvctrlpipe (stv680->udev, 0), | ||
| 187 | req, | ||
| 188 | (USB_DIR_IN | USB_RECIP_DEVICE), | ||
| 189 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
| 190 | break; | ||
| 191 | |||
| 192 | case 3: /* 0x40 */ | ||
| 193 | ret = usb_control_msg (stv680->udev, | ||
| 194 | usb_sndctrlpipe (stv680->udev, 0), | ||
| 195 | req, | ||
| 196 | (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), | ||
| 197 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
| 198 | break; | ||
| 199 | |||
| 200 | } | ||
| 201 | if ((ret < 0) && (req != 0x0a)) { | ||
| 202 | PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret); | ||
| 203 | } | ||
| 204 | return ret; | ||
| 205 | } | ||
| 206 | |||
| 207 | static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate) | ||
| 208 | { | ||
| 209 | |||
| 210 | if (configuration != dev->udev->actconfig->desc.bConfigurationValue | ||
| 211 | || usb_reset_configuration (dev->udev) < 0) { | ||
| 212 | PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration); | ||
| 213 | return -1; | ||
| 214 | } | ||
| 215 | if (usb_set_interface (dev->udev, interface, alternate) < 0) { | ||
| 216 | PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate); | ||
| 217 | return -1; | ||
| 218 | } | ||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | static int stv_stop_video (struct usb_stv *dev) | ||
| 223 | { | ||
| 224 | int i; | ||
| 225 | unsigned char *buf; | ||
| 226 | |||
| 227 | buf = kmalloc (40, GFP_KERNEL); | ||
| 228 | if (buf == NULL) { | ||
| 229 | PDEBUG (0, "STV(e): Out of (small buf) memory"); | ||
| 230 | return -1; | ||
| 231 | } | ||
| 232 | |||
| 233 | /* this is a high priority command; it stops all lower order commands */ | ||
| 234 | if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) { | ||
| 235 | i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02); /* Get Last Error; 2 = busy */ | ||
| 236 | PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buf[0], buf[1]); | ||
| 237 | } else { | ||
| 238 | PDEBUG (1, "STV(i): Camera reset to idle mode."); | ||
| 239 | } | ||
| 240 | |||
| 241 | if ((i = stv_set_config (dev, 1, 0, 0)) < 0) | ||
| 242 | PDEBUG (1, "STV(e): Reset config during exit failed"); | ||
| 243 | |||
| 244 | /* get current mode */ | ||
| 245 | buf[0] = 0xf0; | ||
| 246 | if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08) /* get mode */ | ||
| 247 | PDEBUG (0, "STV(e): Stop_video: problem setting original mode"); | ||
| 248 | if (dev->origMode != buf[0]) { | ||
| 249 | memset (buf, 0, 8); | ||
| 250 | buf[0] = (unsigned char) dev->origMode; | ||
| 251 | if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) { | ||
| 252 | PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed"); | ||
| 253 | i = -1; | ||
| 254 | } | ||
| 255 | buf[0] = 0xf0; | ||
| 256 | i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08); | ||
| 257 | if ((i != 0x08) || (buf[0] != dev->origMode)) { | ||
| 258 | PDEBUG (0, "STV(e): camera NOT set to original resolution."); | ||
| 259 | i = -1; | ||
| 260 | } else | ||
| 261 | PDEBUG (0, "STV(i): Camera set to original resolution"); | ||
| 262 | } | ||
| 263 | /* origMode */ | ||
| 264 | kfree(buf); | ||
| 265 | return i; | ||
| 266 | } | ||
| 267 | |||
| 268 | static int stv_set_video_mode (struct usb_stv *dev) | ||
| 269 | { | ||
| 270 | int i, stop_video = 1; | ||
| 271 | unsigned char *buf; | ||
| 272 | |||
| 273 | buf = kmalloc (40, GFP_KERNEL); | ||
| 274 | if (buf == NULL) { | ||
| 275 | PDEBUG (0, "STV(e): Out of (small buf) memory"); | ||
| 276 | return -1; | ||
| 277 | } | ||
| 278 | |||
| 279 | if ((i = stv_set_config (dev, 1, 0, 0)) < 0) { | ||
| 280 | kfree(buf); | ||
| 281 | return i; | ||
| 282 | } | ||
| 283 | |||
| 284 | i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12); | ||
| 285 | if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) { | ||
| 286 | PDEBUG (1, "STV(e): Could not get descriptor 0100."); | ||
| 287 | goto error; | ||
| 288 | } | ||
| 289 | |||
| 290 | /* set alternate interface 1 */ | ||
| 291 | if ((i = stv_set_config (dev, 1, 0, 1)) < 0) | ||
| 292 | goto error; | ||
| 293 | |||
| 294 | if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10) | ||
| 295 | goto error; | ||
| 296 | PDEBUG (1, "STV(i): Setting video mode."); | ||
| 297 | /* Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240) */ | ||
| 298 | if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) { | ||
| 299 | stop_video = 0; | ||
| 300 | goto error; | ||
| 301 | } | ||
| 302 | goto exit; | ||
| 303 | |||
| 304 | error: | ||
| 305 | kfree(buf); | ||
| 306 | if (stop_video == 1) | ||
| 307 | stv_stop_video (dev); | ||
| 308 | return -1; | ||
| 309 | |||
| 310 | exit: | ||
| 311 | kfree(buf); | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | static int stv_init (struct usb_stv *stv680) | ||
| 316 | { | ||
| 317 | int i = 0; | ||
| 318 | unsigned char *buffer; | ||
| 319 | unsigned long int bufsize; | ||
| 320 | |||
| 321 | buffer = kzalloc (40, GFP_KERNEL); | ||
| 322 | if (buffer == NULL) { | ||
| 323 | PDEBUG (0, "STV(e): Out of (small buf) memory"); | ||
| 324 | return -1; | ||
| 325 | } | ||
| 326 | udelay (100); | ||
| 327 | |||
| 328 | /* set config 1, interface 0, alternate 0 */ | ||
| 329 | if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) { | ||
| 330 | kfree(buffer); | ||
| 331 | PDEBUG (0, "STV(e): set config 1,0,0 failed"); | ||
| 332 | return -1; | ||
| 333 | } | ||
| 334 | /* ping camera to be sure STV0680 is present */ | ||
| 335 | if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02) | ||
| 336 | goto error; | ||
| 337 | if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) { | ||
| 338 | PDEBUG (1, "STV(e): camera ping failed!!"); | ||
| 339 | goto error; | ||
| 340 | } | ||
| 341 | |||
| 342 | /* get camera descriptor */ | ||
| 343 | if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09) | ||
| 344 | goto error; | ||
| 345 | i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22); | ||
| 346 | if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) { | ||
| 347 | PDEBUG (1, "STV(e): Could not get descriptor 0200."); | ||
| 348 | goto error; | ||
| 349 | } | ||
| 350 | if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02) | ||
| 351 | goto error; | ||
| 352 | if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24) | ||
| 353 | goto error; | ||
| 354 | if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) | ||
| 355 | goto error; | ||
| 356 | |||
| 357 | stv680->SupportedModes = buffer[7]; | ||
| 358 | i = stv680->SupportedModes; | ||
| 359 | stv680->CIF = 0; | ||
| 360 | stv680->VGA = 0; | ||
| 361 | stv680->QVGA = 0; | ||
| 362 | if (i & 1) | ||
| 363 | stv680->CIF = 1; | ||
| 364 | if (i & 2) | ||
| 365 | stv680->VGA = 1; | ||
| 366 | if (i & 8) | ||
| 367 | stv680->QVGA = 1; | ||
| 368 | if (stv680->SupportedModes == 0) { | ||
| 369 | PDEBUG (0, "STV(e): There are NO supported STV680 modes!!"); | ||
| 370 | i = -1; | ||
| 371 | goto error; | ||
| 372 | } else { | ||
| 373 | if (stv680->CIF) | ||
| 374 | PDEBUG (0, "STV(i): CIF is supported"); | ||
| 375 | if (stv680->QVGA) | ||
| 376 | PDEBUG (0, "STV(i): QVGA is supported"); | ||
| 377 | } | ||
| 378 | /* FW rev, ASIC rev, sensor ID */ | ||
| 379 | PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]); | ||
| 380 | PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]); | ||
| 381 | PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4)); | ||
| 382 | |||
| 383 | /* set alternate interface 1 */ | ||
| 384 | if ((i = stv_set_config (stv680, 1, 0, 1)) < 0) | ||
| 385 | goto error; | ||
| 386 | |||
| 387 | if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) | ||
| 388 | goto error; | ||
| 389 | if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08) | ||
| 390 | goto error; | ||
| 391 | i = buffer[3]; | ||
| 392 | PDEBUG (0, "STV(i): Camera has %i pictures.", i); | ||
| 393 | |||
| 394 | /* get current mode */ | ||
| 395 | if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08) | ||
| 396 | goto error; | ||
| 397 | stv680->origMode = buffer[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */ | ||
| 398 | |||
| 399 | /* This will attemp CIF mode, if supported. If not, set to QVGA */ | ||
| 400 | memset (buffer, 0, 8); | ||
| 401 | if (stv680->CIF) | ||
| 402 | buffer[0] = 0x00; | ||
| 403 | else if (stv680->QVGA) | ||
| 404 | buffer[0] = 0x03; | ||
| 405 | if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) { | ||
| 406 | PDEBUG (0, "STV(i): Set_Camera_Mode failed"); | ||
| 407 | i = -1; | ||
| 408 | goto error; | ||
| 409 | } | ||
| 410 | buffer[0] = 0xf0; | ||
| 411 | stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08); | ||
| 412 | if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) { | ||
| 413 | PDEBUG (0, "STV(e): Error setting camera video mode!"); | ||
| 414 | i = -1; | ||
| 415 | goto error; | ||
| 416 | } else { | ||
| 417 | if (buffer[0] == 0) { | ||
| 418 | stv680->VideoMode = 0x0000; | ||
| 419 | PDEBUG (0, "STV(i): Video Mode set to CIF"); | ||
| 420 | } | ||
| 421 | if (buffer[0] == 0x03) { | ||
| 422 | stv680->VideoMode = 0x0300; | ||
| 423 | PDEBUG (0, "STV(i): Video Mode set to QVGA"); | ||
| 424 | } | ||
| 425 | } | ||
| 426 | if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10) | ||
| 427 | goto error; | ||
| 428 | bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); | ||
| 429 | stv680->cwidth = (buffer[4] << 8) | (buffer[5]); /* ->camera = 322, 356, 644 */ | ||
| 430 | stv680->cheight = (buffer[6] << 8) | (buffer[7]); /* ->camera = 242, 292, 484 */ | ||
| 431 | stv680->origGain = buffer[12]; | ||
| 432 | |||
| 433 | goto exit; | ||
| 434 | |||
| 435 | error: | ||
| 436 | i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02); /* Get Last Error */ | ||
| 437 | PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buffer[0], buffer[1]); | ||
| 438 | kfree(buffer); | ||
| 439 | return -1; | ||
| 440 | |||
| 441 | exit: | ||
| 442 | kfree(buffer); | ||
| 443 | |||
| 444 | /* video = 320x240, 352x288 */ | ||
| 445 | if (stv680->CIF == 1) { | ||
| 446 | stv680->maxwidth = 352; | ||
| 447 | stv680->maxheight = 288; | ||
| 448 | stv680->vwidth = 352; | ||
| 449 | stv680->vheight = 288; | ||
| 450 | } | ||
| 451 | if (stv680->QVGA == 1) { | ||
| 452 | stv680->maxwidth = 320; | ||
| 453 | stv680->maxheight = 240; | ||
| 454 | stv680->vwidth = 320; | ||
| 455 | stv680->vheight = 240; | ||
| 456 | } | ||
| 457 | |||
| 458 | stv680->rawbufsize = bufsize; /* must be ./. by 8 */ | ||
| 459 | stv680->maxframesize = bufsize * 3; /* RGB size */ | ||
| 460 | PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight); | ||
| 461 | PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize); | ||
| 462 | |||
| 463 | /* some default values */ | ||
| 464 | stv680->bulk_in_endpointAddr = 0x82; | ||
| 465 | stv680->dropped = 0; | ||
| 466 | stv680->error = 0; | ||
| 467 | stv680->framecount = 0; | ||
| 468 | stv680->readcount = 0; | ||
| 469 | stv680->streaming = 0; | ||
| 470 | /* bright, white, colour, hue, contrast are set by software, not in stv0680 */ | ||
| 471 | stv680->brightness = 32767; | ||
| 472 | stv680->chgbright = 0; | ||
| 473 | stv680->whiteness = 0; /* only for greyscale */ | ||
| 474 | stv680->colour = 32767; | ||
| 475 | stv680->contrast = 32767; | ||
| 476 | stv680->hue = 32767; | ||
| 477 | stv680->palette = STV_VIDEO_PALETTE; | ||
| 478 | stv680->depth = 24; /* rgb24 bits */ | ||
| 479 | if ((swapRGB_on == 0) && (swapRGB == 0)) | ||
| 480 | PDEBUG (1, "STV(i): swapRGB is (auto) OFF"); | ||
| 481 | else if ((swapRGB_on == 0) && (swapRGB == 1)) | ||
| 482 | PDEBUG (1, "STV(i): swapRGB is (auto) ON"); | ||
| 483 | else if (swapRGB_on == 1) | ||
| 484 | PDEBUG (1, "STV(i): swapRGB is (forced) ON"); | ||
| 485 | else if (swapRGB_on == -1) | ||
| 486 | PDEBUG (1, "STV(i): swapRGB is (forced) OFF"); | ||
| 487 | |||
| 488 | if (stv_set_video_mode (stv680) < 0) { | ||
| 489 | PDEBUG (0, "STV(e): Could not set video mode in stv_init"); | ||
| 490 | return -1; | ||
| 491 | } | ||
| 492 | |||
| 493 | return 0; | ||
| 494 | } | ||
| 495 | |||
| 496 | /***************** last of pencam routines *******************/ | ||
| 497 | |||
| 498 | /**************************************************************************** | ||
| 499 | * sysfs | ||
| 500 | ***************************************************************************/ | ||
| 501 | #define stv680_file(name, variable, field) \ | ||
| 502 | static ssize_t show_##name(struct class_device *class_dev, char *buf) \ | ||
| 503 | { \ | ||
| 504 | struct video_device *vdev = to_video_device(class_dev); \ | ||
| 505 | struct usb_stv *stv = video_get_drvdata(vdev); \ | ||
| 506 | return sprintf(buf, field, stv->variable); \ | ||
| 507 | } \ | ||
| 508 | static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); | ||
| 509 | |||
| 510 | stv680_file(model, camera_name, "%s\n"); | ||
| 511 | stv680_file(in_use, user, "%d\n"); | ||
| 512 | stv680_file(streaming, streaming, "%d\n"); | ||
| 513 | stv680_file(palette, palette, "%i\n"); | ||
| 514 | stv680_file(frames_total, readcount, "%d\n"); | ||
| 515 | stv680_file(frames_read, framecount, "%d\n"); | ||
| 516 | stv680_file(packets_dropped, dropped, "%d\n"); | ||
| 517 | stv680_file(decoding_errors, error, "%d\n"); | ||
| 518 | |||
| 519 | static void stv680_create_sysfs_files(struct video_device *vdev) | ||
| 520 | { | ||
| 521 | video_device_create_file(vdev, &class_device_attr_model); | ||
| 522 | video_device_create_file(vdev, &class_device_attr_in_use); | ||
| 523 | video_device_create_file(vdev, &class_device_attr_streaming); | ||
| 524 | video_device_create_file(vdev, &class_device_attr_palette); | ||
| 525 | video_device_create_file(vdev, &class_device_attr_frames_total); | ||
| 526 | video_device_create_file(vdev, &class_device_attr_frames_read); | ||
| 527 | video_device_create_file(vdev, &class_device_attr_packets_dropped); | ||
| 528 | video_device_create_file(vdev, &class_device_attr_decoding_errors); | ||
| 529 | } | ||
| 530 | |||
| 531 | static void stv680_remove_sysfs_files(struct video_device *vdev) | ||
| 532 | { | ||
| 533 | video_device_remove_file(vdev, &class_device_attr_model); | ||
| 534 | video_device_remove_file(vdev, &class_device_attr_in_use); | ||
| 535 | video_device_remove_file(vdev, &class_device_attr_streaming); | ||
| 536 | video_device_remove_file(vdev, &class_device_attr_palette); | ||
| 537 | video_device_remove_file(vdev, &class_device_attr_frames_total); | ||
| 538 | video_device_remove_file(vdev, &class_device_attr_frames_read); | ||
| 539 | video_device_remove_file(vdev, &class_device_attr_packets_dropped); | ||
| 540 | video_device_remove_file(vdev, &class_device_attr_decoding_errors); | ||
| 541 | } | ||
| 542 | |||
| 543 | /******************************************************************** | ||
| 544 | * Camera control | ||
| 545 | *******************************************************************/ | ||
| 546 | |||
| 547 | static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p) | ||
| 548 | { | ||
| 549 | /* This sets values for v4l interface. max/min = 65535/0 */ | ||
| 550 | |||
| 551 | p->brightness = stv680->brightness; | ||
| 552 | p->whiteness = stv680->whiteness; /* greyscale */ | ||
| 553 | p->colour = stv680->colour; | ||
| 554 | p->contrast = stv680->contrast; | ||
| 555 | p->hue = stv680->hue; | ||
| 556 | p->palette = stv680->palette; | ||
| 557 | p->depth = stv680->depth; | ||
| 558 | return 0; | ||
| 559 | } | ||
| 560 | |||
| 561 | static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p) | ||
| 562 | { | ||
| 563 | /* See above stv680_get_pict */ | ||
| 564 | |||
| 565 | if (p->palette != STV_VIDEO_PALETTE) { | ||
| 566 | PDEBUG (2, "STV(e): Palette set error in _set_pic"); | ||
| 567 | return 1; | ||
| 568 | } | ||
| 569 | |||
| 570 | if (stv680->brightness != p->brightness) { | ||
| 571 | stv680->chgbright = 1; | ||
| 572 | stv680->brightness = p->brightness; | ||
| 573 | } | ||
| 574 | |||
| 575 | stv680->whiteness = p->whiteness; /* greyscale */ | ||
| 576 | stv680->colour = p->colour; | ||
| 577 | stv680->contrast = p->contrast; | ||
| 578 | stv680->hue = p->hue; | ||
| 579 | stv680->palette = p->palette; | ||
| 580 | stv680->depth = p->depth; | ||
| 581 | |||
| 582 | return 0; | ||
| 583 | } | ||
| 584 | |||
| 585 | static void stv680_video_irq (struct urb *urb, struct pt_regs *regs) | ||
| 586 | { | ||
| 587 | struct usb_stv *stv680 = urb->context; | ||
| 588 | int length = urb->actual_length; | ||
| 589 | |||
| 590 | if (length < stv680->rawbufsize) | ||
| 591 | PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length); | ||
| 592 | |||
| 593 | /* ohoh... */ | ||
| 594 | if (!stv680->streaming) | ||
| 595 | return; | ||
| 596 | |||
| 597 | if (!stv680->udev) { | ||
| 598 | PDEBUG (0, "STV(e): device vapourished in video_irq"); | ||
| 599 | return; | ||
| 600 | } | ||
| 601 | |||
| 602 | /* 0 sized packets happen if we are to fast, but sometimes the camera | ||
| 603 | keeps sending them forever... | ||
| 604 | */ | ||
| 605 | if (length && !urb->status) { | ||
| 606 | stv680->nullpackets = 0; | ||
| 607 | switch (stv680->scratch[stv680->scratch_next].state) { | ||
| 608 | case BUFFER_READY: | ||
| 609 | case BUFFER_BUSY: | ||
| 610 | stv680->dropped++; | ||
| 611 | break; | ||
| 612 | |||
| 613 | case BUFFER_UNUSED: | ||
| 614 | memcpy (stv680->scratch[stv680->scratch_next].data, | ||
| 615 | (unsigned char *) urb->transfer_buffer, length); | ||
| 616 | stv680->scratch[stv680->scratch_next].state = BUFFER_READY; | ||
| 617 | stv680->scratch[stv680->scratch_next].length = length; | ||
| 618 | if (waitqueue_active (&stv680->wq)) { | ||
| 619 | wake_up_interruptible (&stv680->wq); | ||
| 620 | } | ||
| 621 | stv680->scratch_overflow = 0; | ||
| 622 | stv680->scratch_next++; | ||
| 623 | if (stv680->scratch_next >= STV680_NUMSCRATCH) | ||
| 624 | stv680->scratch_next = 0; | ||
| 625 | break; | ||
| 626 | } /* switch */ | ||
| 627 | } else { | ||
| 628 | stv680->nullpackets++; | ||
| 629 | if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { | ||
| 630 | if (waitqueue_active (&stv680->wq)) { | ||
| 631 | wake_up_interruptible (&stv680->wq); | ||
| 632 | } | ||
| 633 | } | ||
| 634 | } /* if - else */ | ||
| 635 | |||
| 636 | /* Resubmit urb for new data */ | ||
| 637 | urb->status = 0; | ||
| 638 | urb->dev = stv680->udev; | ||
| 639 | if (usb_submit_urb (urb, GFP_ATOMIC)) | ||
| 640 | PDEBUG (0, "STV(e): urb burned down in video irq"); | ||
| 641 | return; | ||
| 642 | } /* _video_irq */ | ||
| 643 | |||
| 644 | static int stv680_start_stream (struct usb_stv *stv680) | ||
| 645 | { | ||
| 646 | struct urb *urb; | ||
| 647 | int err = 0, i; | ||
| 648 | |||
| 649 | stv680->streaming = 1; | ||
| 650 | |||
| 651 | /* Do some memory allocation */ | ||
| 652 | for (i = 0; i < STV680_NUMFRAMES; i++) { | ||
| 653 | stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize; | ||
| 654 | stv680->frame[i].curpix = 0; | ||
| 655 | } | ||
| 656 | /* packet size = 4096 */ | ||
| 657 | for (i = 0; i < STV680_NUMSBUF; i++) { | ||
| 658 | stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); | ||
| 659 | if (stv680->sbuf[i].data == NULL) { | ||
| 660 | PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i); | ||
| 661 | return -1; | ||
| 662 | } | ||
| 663 | } | ||
| 664 | |||
| 665 | stv680->scratch_next = 0; | ||
| 666 | stv680->scratch_use = 0; | ||
| 667 | stv680->scratch_overflow = 0; | ||
| 668 | for (i = 0; i < STV680_NUMSCRATCH; i++) { | ||
| 669 | stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); | ||
| 670 | if (stv680->scratch[i].data == NULL) { | ||
| 671 | PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i); | ||
| 672 | return -1; | ||
| 673 | } | ||
| 674 | stv680->scratch[i].state = BUFFER_UNUSED; | ||
| 675 | } | ||
| 676 | |||
| 677 | for (i = 0; i < STV680_NUMSBUF; i++) { | ||
| 678 | urb = usb_alloc_urb (0, GFP_KERNEL); | ||
| 679 | if (!urb) | ||
| 680 | return -ENOMEM; | ||
| 681 | |||
| 682 | /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */ | ||
| 683 | usb_fill_bulk_urb (urb, stv680->udev, | ||
| 684 | usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr), | ||
| 685 | stv680->sbuf[i].data, stv680->rawbufsize, | ||
| 686 | stv680_video_irq, stv680); | ||
| 687 | stv680->urb[i] = urb; | ||
| 688 | err = usb_submit_urb (stv680->urb[i], GFP_KERNEL); | ||
| 689 | if (err) | ||
| 690 | PDEBUG (0, "STV(e): urb burned down in start stream"); | ||
| 691 | } /* i STV680_NUMSBUF */ | ||
| 692 | |||
| 693 | stv680->framecount = 0; | ||
| 694 | return 0; | ||
| 695 | } | ||
| 696 | |||
| 697 | static int stv680_stop_stream (struct usb_stv *stv680) | ||
| 698 | { | ||
| 699 | int i; | ||
| 700 | |||
| 701 | if (!stv680->streaming || !stv680->udev) | ||
| 702 | return 1; | ||
| 703 | |||
| 704 | stv680->streaming = 0; | ||
| 705 | |||
| 706 | for (i = 0; i < STV680_NUMSBUF; i++) | ||
| 707 | if (stv680->urb[i]) { | ||
| 708 | usb_kill_urb (stv680->urb[i]); | ||
| 709 | usb_free_urb (stv680->urb[i]); | ||
| 710 | stv680->urb[i] = NULL; | ||
| 711 | kfree(stv680->sbuf[i].data); | ||
| 712 | } | ||
| 713 | for (i = 0; i < STV680_NUMSCRATCH; i++) { | ||
| 714 | kfree(stv680->scratch[i].data); | ||
| 715 | stv680->scratch[i].data = NULL; | ||
| 716 | } | ||
| 717 | |||
| 718 | return 0; | ||
| 719 | } | ||
| 720 | |||
| 721 | static int stv680_set_size (struct usb_stv *stv680, int width, int height) | ||
| 722 | { | ||
| 723 | int wasstreaming = stv680->streaming; | ||
| 724 | |||
| 725 | /* Check to see if we need to change */ | ||
| 726 | if ((stv680->vwidth == width) && (stv680->vheight == height)) | ||
| 727 | return 0; | ||
| 728 | |||
| 729 | PDEBUG (1, "STV(i): size request for %i x %i", width, height); | ||
| 730 | /* Check for a valid mode */ | ||
| 731 | if ((!width || !height) || ((width & 1) || (height & 1))) { | ||
| 732 | PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); | ||
| 733 | return 1; | ||
| 734 | } | ||
| 735 | |||
| 736 | if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) { | ||
| 737 | width = stv680->maxwidth / 2; | ||
| 738 | height = stv680->maxheight / 2; | ||
| 739 | } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) { | ||
| 740 | width = 160; | ||
| 741 | height = 120; | ||
| 742 | } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) { | ||
| 743 | width = 176; | ||
| 744 | height = 144; | ||
| 745 | } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) { | ||
| 746 | width = 320; | ||
| 747 | height = 240; | ||
| 748 | } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) { | ||
| 749 | width = 352; | ||
| 750 | height = 288; | ||
| 751 | } else { | ||
| 752 | PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); | ||
| 753 | return 1; | ||
| 754 | } | ||
| 755 | |||
| 756 | /* Stop a current stream and start it again at the new size */ | ||
| 757 | if (wasstreaming) | ||
| 758 | stv680_stop_stream (stv680); | ||
| 759 | stv680->vwidth = width; | ||
| 760 | stv680->vheight = height; | ||
| 761 | PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight); | ||
| 762 | if (wasstreaming) | ||
| 763 | stv680_start_stream (stv680); | ||
| 764 | |||
| 765 | return 0; | ||
| 766 | } | ||
| 767 | |||
| 768 | /********************************************************************** | ||
| 769 | * Video Decoding | ||
| 770 | **********************************************************************/ | ||
| 771 | |||
| 772 | /******* routines from the pencam program; hey, they work! ********/ | ||
| 773 | |||
| 774 | /* | ||
| 775 | * STV0680 Vision Camera Chipset Driver | ||
| 776 | * Copyright (C) 2000 Adam Harrison <adam@antispin.org> | ||
| 777 | */ | ||
| 778 | |||
| 779 | #define RED 0 | ||
| 780 | #define GREEN 1 | ||
| 781 | #define BLUE 2 | ||
| 782 | #define AD(x, y, w) (((y)*(w)+(x))*3) | ||
| 783 | |||
| 784 | static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer) | ||
| 785 | { | ||
| 786 | int x, y, i; | ||
| 787 | int w = stv680->cwidth; | ||
| 788 | int vw = stv680->cwidth, vh = stv680->cheight; | ||
| 789 | unsigned int p = 0; | ||
| 790 | int colour = 0, bayer = 0; | ||
| 791 | unsigned char *raw = buffer->data; | ||
| 792 | struct stv680_frame *frame = &stv680->frame[stv680->curframe]; | ||
| 793 | unsigned char *output = frame->data; | ||
| 794 | unsigned char *temp = frame->data; | ||
| 795 | int offset = buffer->offset; | ||
| 796 | |||
| 797 | if (frame->curpix == 0) { | ||
| 798 | if (frame->grabstate == FRAME_READY) { | ||
| 799 | frame->grabstate = FRAME_GRABBING; | ||
| 800 | } | ||
| 801 | } | ||
| 802 | if (offset != frame->curpix) { /* Regard frame as lost :( */ | ||
| 803 | frame->curpix = 0; | ||
| 804 | stv680->error++; | ||
| 805 | return; | ||
| 806 | } | ||
| 807 | |||
| 808 | if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) { | ||
| 809 | vw = 320; | ||
| 810 | vh = 240; | ||
| 811 | } | ||
| 812 | if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) { | ||
| 813 | vw = 352; | ||
| 814 | vh = 288; | ||
| 815 | } | ||
| 816 | |||
| 817 | memset (output, 0, 3 * vw * vh); /* clear output matrix. */ | ||
| 818 | |||
| 819 | for (y = 0; y < vh; y++) { | ||
| 820 | for (x = 0; x < vw; x++) { | ||
| 821 | if (x & 1) | ||
| 822 | p = *(raw + y * w + (x >> 1)); | ||
| 823 | else | ||
| 824 | p = *(raw + y * w + (x >> 1) + (w >> 1)); | ||
| 825 | |||
| 826 | if (y & 1) | ||
| 827 | bayer = 2; | ||
| 828 | else | ||
| 829 | bayer = 0; | ||
| 830 | if (x & 1) | ||
| 831 | bayer++; | ||
| 832 | |||
| 833 | switch (bayer) { | ||
| 834 | case 0: | ||
| 835 | case 3: | ||
| 836 | colour = 1; | ||
| 837 | break; | ||
| 838 | case 1: | ||
| 839 | colour = 0; | ||
| 840 | break; | ||
| 841 | case 2: | ||
| 842 | colour = 2; | ||
| 843 | break; | ||
| 844 | } | ||
| 845 | i = (y * vw + x) * 3; | ||
| 846 | *(output + i + colour) = (unsigned char) p; | ||
| 847 | } /* for x */ | ||
| 848 | |||
| 849 | } /* for y */ | ||
| 850 | |||
| 851 | /****** gamma correction plus hardcoded white balance */ | ||
| 852 | /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code. | ||
| 853 | Correction values red[], green[], blue[], are generated by | ||
| 854 | (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. | ||
| 855 | White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and | ||
| 856 | converted to unsigned char. Values are in stv680.h */ | ||
| 857 | |||
| 858 | for (y = 0; y < vh; y++) { | ||
| 859 | for (x = 0; x < vw; x++) { | ||
| 860 | i = (y * vw + x) * 3; | ||
| 861 | *(output + i) = red[*(output + i)]; | ||
| 862 | *(output + i + 1) = green[*(output + i + 1)]; | ||
| 863 | *(output + i + 2) = blue[*(output + i + 2)]; | ||
| 864 | } | ||
| 865 | } | ||
| 866 | |||
| 867 | /****** bayer demosaic ******/ | ||
| 868 | for (y = 1; y < (vh - 1); y++) { | ||
| 869 | for (x = 1; x < (vw - 1); x++) { /* work out pixel type */ | ||
| 870 | if (y & 1) | ||
| 871 | bayer = 0; | ||
| 872 | else | ||
| 873 | bayer = 2; | ||
| 874 | if (!(x & 1)) | ||
| 875 | bayer++; | ||
| 876 | |||
| 877 | switch (bayer) { | ||
| 878 | case 0: /* green. blue lr, red tb */ | ||
| 879 | *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1; | ||
| 880 | *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1; | ||
| 881 | break; | ||
| 882 | |||
| 883 | case 1: /* blue. green lrtb, red diagonals */ | ||
| 884 | *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; | ||
| 885 | *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2; | ||
| 886 | break; | ||
| 887 | |||
| 888 | case 2: /* red. green lrtb, blue diagonals */ | ||
| 889 | *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; | ||
| 890 | *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2; | ||
| 891 | break; | ||
| 892 | |||
| 893 | case 3: /* green. red lr, blue tb */ | ||
| 894 | *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1; | ||
| 895 | *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1; | ||
| 896 | break; | ||
| 897 | } /* switch */ | ||
| 898 | } /* for x */ | ||
| 899 | } /* for y - end demosaic */ | ||
| 900 | |||
| 901 | /* fix top and bottom row, left and right side */ | ||
| 902 | i = vw * 3; | ||
| 903 | memcpy (output, (output + i), i); | ||
| 904 | memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i); | ||
| 905 | for (y = 0; y < vh; y++) { | ||
| 906 | i = y * vw * 3; | ||
| 907 | memcpy ((output + i), (output + i + 3), 3); | ||
| 908 | memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3); | ||
| 909 | } | ||
| 910 | |||
| 911 | /* process all raw data, then trim to size if necessary */ | ||
| 912 | if ((stv680->vwidth == 160) || (stv680->vwidth == 176)) { | ||
| 913 | i = 0; | ||
| 914 | for (y = 0; y < vh; y++) { | ||
| 915 | if (!(y & 1)) { | ||
| 916 | for (x = 0; x < vw; x++) { | ||
| 917 | p = (y * vw + x) * 3; | ||
| 918 | if (!(x & 1)) { | ||
| 919 | *(output + i) = *(output + p); | ||
| 920 | *(output + i + 1) = *(output + p + 1); | ||
| 921 | *(output + i + 2) = *(output + p + 2); | ||
| 922 | i += 3; | ||
| 923 | } | ||
| 924 | } /* for x */ | ||
| 925 | } | ||
| 926 | } /* for y */ | ||
| 927 | } | ||
| 928 | /* reset to proper width */ | ||
| 929 | if ((stv680->vwidth == 160)) { | ||
| 930 | vw = 160; | ||
| 931 | vh = 120; | ||
| 932 | } | ||
| 933 | if ((stv680->vwidth == 176)) { | ||
| 934 | vw = 176; | ||
| 935 | vh = 144; | ||
| 936 | } | ||
| 937 | |||
| 938 | /* output is RGB; some programs want BGR */ | ||
| 939 | /* swapRGB_on=0 -> program decides; swapRGB_on=1, always swap */ | ||
| 940 | /* swapRGB_on=-1, never swap */ | ||
| 941 | if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) { | ||
| 942 | for (y = 0; y < vh; y++) { | ||
| 943 | for (x = 0; x < vw; x++) { | ||
| 944 | i = (y * vw + x) * 3; | ||
| 945 | *(temp) = *(output + i); | ||
| 946 | *(output + i) = *(output + i + 2); | ||
| 947 | *(output + i + 2) = *(temp); | ||
| 948 | } | ||
| 949 | } | ||
| 950 | } | ||
| 951 | /* brightness */ | ||
| 952 | if (stv680->chgbright == 1) { | ||
| 953 | if (stv680->brightness >= 32767) { | ||
| 954 | p = (stv680->brightness - 32767) / 256; | ||
| 955 | for (x = 0; x < (vw * vh * 3); x++) { | ||
| 956 | if ((*(output + x) + (unsigned char) p) > 255) | ||
| 957 | *(output + x) = 255; | ||
| 958 | else | ||
| 959 | *(output + x) += (unsigned char) p; | ||
| 960 | } /* for */ | ||
| 961 | } else { | ||
| 962 | p = (32767 - stv680->brightness) / 256; | ||
| 963 | for (x = 0; x < (vw * vh * 3); x++) { | ||
| 964 | if ((unsigned char) p > *(output + x)) | ||
| 965 | *(output + x) = 0; | ||
| 966 | else | ||
| 967 | *(output + x) -= (unsigned char) p; | ||
| 968 | } /* for */ | ||
| 969 | } /* else */ | ||
| 970 | } | ||
| 971 | /* if */ | ||
| 972 | frame->curpix = 0; | ||
| 973 | frame->curlinepix = 0; | ||
| 974 | frame->grabstate = FRAME_DONE; | ||
| 975 | stv680->framecount++; | ||
| 976 | stv680->readcount++; | ||
| 977 | if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) { | ||
| 978 | stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1); | ||
| 979 | } | ||
| 980 | |||
| 981 | } /* bayer_unshuffle */ | ||
| 982 | |||
| 983 | /******* end routines from the pencam program *********/ | ||
| 984 | |||
| 985 | static int stv680_newframe (struct usb_stv *stv680, int framenr) | ||
| 986 | { | ||
| 987 | int errors = 0; | ||
| 988 | |||
| 989 | while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) { | ||
| 990 | if (!stv680->frame[framenr].curpix) { | ||
| 991 | errors++; | ||
| 992 | } | ||
| 993 | wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY)); | ||
| 994 | |||
| 995 | if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { | ||
| 996 | stv680->nullpackets = 0; | ||
| 997 | PDEBUG (2, "STV(i): too many null length packets, restarting capture"); | ||
| 998 | stv680_stop_stream (stv680); | ||
| 999 | stv680_start_stream (stv680); | ||
| 1000 | } else { | ||
| 1001 | if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) { | ||
| 1002 | stv680->frame[framenr].grabstate = FRAME_ERROR; | ||
| 1003 | PDEBUG (2, "STV(e): FRAME_ERROR in _newframe"); | ||
| 1004 | return -EIO; | ||
| 1005 | } | ||
| 1006 | stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY; | ||
| 1007 | |||
| 1008 | bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]); | ||
| 1009 | |||
| 1010 | stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED; | ||
| 1011 | stv680->scratch_use++; | ||
| 1012 | if (stv680->scratch_use >= STV680_NUMSCRATCH) | ||
| 1013 | stv680->scratch_use = 0; | ||
| 1014 | if (errors > STV680_MAX_ERRORS) { | ||
| 1015 | errors = 0; | ||
| 1016 | PDEBUG (2, "STV(i): too many errors, restarting capture"); | ||
| 1017 | stv680_stop_stream (stv680); | ||
| 1018 | stv680_start_stream (stv680); | ||
| 1019 | } | ||
| 1020 | } /* else */ | ||
| 1021 | } /* while */ | ||
| 1022 | return 0; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | /********************************************************************* | ||
| 1026 | * Video4Linux | ||
| 1027 | *********************************************************************/ | ||
| 1028 | |||
| 1029 | static int stv_open (struct inode *inode, struct file *file) | ||
| 1030 | { | ||
| 1031 | struct video_device *dev = video_devdata(file); | ||
| 1032 | struct usb_stv *stv680 = video_get_drvdata(dev); | ||
| 1033 | int err = 0; | ||
| 1034 | |||
| 1035 | /* we are called with the BKL held */ | ||
| 1036 | stv680->user = 1; | ||
| 1037 | err = stv_init (stv680); /* main initialization routine for camera */ | ||
| 1038 | |||
| 1039 | if (err >= 0) { | ||
| 1040 | stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES); | ||
| 1041 | if (!stv680->fbuf) { | ||
| 1042 | PDEBUG (0, "STV(e): Could not rvmalloc frame bufer"); | ||
| 1043 | err = -ENOMEM; | ||
| 1044 | } | ||
| 1045 | file->private_data = dev; | ||
| 1046 | } | ||
| 1047 | if (err) | ||
| 1048 | stv680->user = 0; | ||
| 1049 | |||
| 1050 | return err; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | static int stv_close (struct inode *inode, struct file *file) | ||
| 1054 | { | ||
| 1055 | struct video_device *dev = file->private_data; | ||
| 1056 | struct usb_stv *stv680 = video_get_drvdata(dev); | ||
| 1057 | int i; | ||
| 1058 | |||
| 1059 | for (i = 0; i < STV680_NUMFRAMES; i++) | ||
| 1060 | stv680->frame[i].grabstate = FRAME_UNUSED; | ||
| 1061 | if (stv680->streaming) | ||
| 1062 | stv680_stop_stream (stv680); | ||
| 1063 | |||
| 1064 | if ((i = stv_stop_video (stv680)) < 0) | ||
| 1065 | PDEBUG (1, "STV(e): stop_video failed in stv_close"); | ||
| 1066 | |||
| 1067 | rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES); | ||
| 1068 | stv680->user = 0; | ||
| 1069 | |||
| 1070 | if (stv680->removed) { | ||
| 1071 | kfree(stv680); | ||
| 1072 | stv680 = NULL; | ||
| 1073 | PDEBUG (0, "STV(i): device unregistered"); | ||
| 1074 | } | ||
| 1075 | file->private_data = NULL; | ||
| 1076 | return 0; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | static int stv680_do_ioctl (struct inode *inode, struct file *file, | ||
| 1080 | unsigned int cmd, void *arg) | ||
| 1081 | { | ||
| 1082 | struct video_device *vdev = file->private_data; | ||
| 1083 | struct usb_stv *stv680 = video_get_drvdata(vdev); | ||
| 1084 | |||
| 1085 | if (!stv680->udev) | ||
| 1086 | return -EIO; | ||
| 1087 | |||
| 1088 | switch (cmd) { | ||
| 1089 | case VIDIOCGCAP:{ | ||
| 1090 | struct video_capability *b = arg; | ||
| 1091 | |||
| 1092 | strcpy (b->name, stv680->camera_name); | ||
| 1093 | b->type = VID_TYPE_CAPTURE; | ||
| 1094 | b->channels = 1; | ||
| 1095 | b->audios = 0; | ||
| 1096 | b->maxwidth = stv680->maxwidth; | ||
| 1097 | b->maxheight = stv680->maxheight; | ||
| 1098 | b->minwidth = stv680->maxwidth / 2; | ||
| 1099 | b->minheight = stv680->maxheight / 2; | ||
| 1100 | return 0; | ||
| 1101 | } | ||
| 1102 | case VIDIOCGCHAN:{ | ||
| 1103 | struct video_channel *v = arg; | ||
| 1104 | |||
| 1105 | if (v->channel != 0) | ||
| 1106 | return -EINVAL; | ||
| 1107 | v->flags = 0; | ||
| 1108 | v->tuners = 0; | ||
| 1109 | v->type = VIDEO_TYPE_CAMERA; | ||
| 1110 | strcpy (v->name, "STV Camera"); | ||
| 1111 | return 0; | ||
| 1112 | } | ||
| 1113 | case VIDIOCSCHAN:{ | ||
| 1114 | struct video_channel *v = arg; | ||
| 1115 | if (v->channel != 0) | ||
| 1116 | return -EINVAL; | ||
| 1117 | return 0; | ||
| 1118 | } | ||
| 1119 | case VIDIOCGPICT:{ | ||
| 1120 | struct video_picture *p = arg; | ||
| 1121 | |||
| 1122 | stv680_get_pict (stv680, p); | ||
| 1123 | return 0; | ||
| 1124 | } | ||
| 1125 | case VIDIOCSPICT:{ | ||
| 1126 | struct video_picture *p = arg; | ||
| 1127 | |||
| 1128 | if (stv680_set_pict (stv680, p)) | ||
| 1129 | return -EINVAL; | ||
| 1130 | return 0; | ||
| 1131 | } | ||
| 1132 | case VIDIOCSWIN:{ | ||
| 1133 | struct video_window *vw = arg; | ||
| 1134 | |||
| 1135 | if (vw->flags) | ||
| 1136 | return -EINVAL; | ||
| 1137 | if (vw->clipcount) | ||
| 1138 | return -EINVAL; | ||
| 1139 | if (vw->width != stv680->vwidth) { | ||
| 1140 | if (stv680_set_size (stv680, vw->width, vw->height)) { | ||
| 1141 | PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN"); | ||
| 1142 | return -EINVAL; | ||
| 1143 | } | ||
| 1144 | } | ||
| 1145 | return 0; | ||
| 1146 | } | ||
| 1147 | case VIDIOCGWIN:{ | ||
| 1148 | struct video_window *vw = arg; | ||
| 1149 | |||
| 1150 | vw->x = 0; /* FIXME */ | ||
| 1151 | vw->y = 0; | ||
| 1152 | vw->chromakey = 0; | ||
| 1153 | vw->flags = 0; | ||
| 1154 | vw->clipcount = 0; | ||
| 1155 | vw->width = stv680->vwidth; | ||
| 1156 | vw->height = stv680->vheight; | ||
| 1157 | return 0; | ||
| 1158 | } | ||
| 1159 | case VIDIOCGMBUF:{ | ||
| 1160 | struct video_mbuf *vm = arg; | ||
| 1161 | int i; | ||
| 1162 | |||
| 1163 | memset (vm, 0, sizeof (*vm)); | ||
| 1164 | vm->size = STV680_NUMFRAMES * stv680->maxframesize; | ||
| 1165 | vm->frames = STV680_NUMFRAMES; | ||
| 1166 | for (i = 0; i < STV680_NUMFRAMES; i++) | ||
| 1167 | vm->offsets[i] = stv680->maxframesize * i; | ||
| 1168 | return 0; | ||
| 1169 | } | ||
| 1170 | case VIDIOCMCAPTURE:{ | ||
| 1171 | struct video_mmap *vm = arg; | ||
| 1172 | |||
| 1173 | if (vm->format != STV_VIDEO_PALETTE) { | ||
| 1174 | PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)", | ||
| 1175 | vm->format, STV_VIDEO_PALETTE); | ||
| 1176 | if ((vm->format == 3) && (swapRGB_on == 0)) { | ||
| 1177 | PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON"); | ||
| 1178 | /* this may fix those apps (e.g., xawtv) that want BGR */ | ||
| 1179 | swapRGB = 1; | ||
| 1180 | } | ||
| 1181 | return -EINVAL; | ||
| 1182 | } | ||
| 1183 | if (vm->frame >= STV680_NUMFRAMES) { | ||
| 1184 | PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES"); | ||
| 1185 | return -EINVAL; | ||
| 1186 | } | ||
| 1187 | if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR) | ||
| 1188 | || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) { | ||
| 1189 | PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error", | ||
| 1190 | stv680->frame[vm->frame].grabstate); | ||
| 1191 | return -EBUSY; | ||
| 1192 | } | ||
| 1193 | /* Is this according to the v4l spec??? */ | ||
| 1194 | if (stv680->vwidth != vm->width) { | ||
| 1195 | if (stv680_set_size (stv680, vm->width, vm->height)) { | ||
| 1196 | PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed"); | ||
| 1197 | return -EINVAL; | ||
| 1198 | } | ||
| 1199 | } | ||
| 1200 | stv680->frame[vm->frame].grabstate = FRAME_READY; | ||
| 1201 | |||
| 1202 | if (!stv680->streaming) | ||
| 1203 | stv680_start_stream (stv680); | ||
| 1204 | |||
| 1205 | return 0; | ||
| 1206 | } | ||
| 1207 | case VIDIOCSYNC:{ | ||
| 1208 | int *frame = arg; | ||
| 1209 | int ret = 0; | ||
| 1210 | |||
| 1211 | if (*frame < 0 || *frame >= STV680_NUMFRAMES) { | ||
| 1212 | PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC"); | ||
| 1213 | return -EINVAL; | ||
| 1214 | } | ||
| 1215 | ret = stv680_newframe (stv680, *frame); | ||
| 1216 | stv680->frame[*frame].grabstate = FRAME_UNUSED; | ||
| 1217 | return ret; | ||
| 1218 | } | ||
| 1219 | case VIDIOCGFBUF:{ | ||
| 1220 | struct video_buffer *vb = arg; | ||
| 1221 | |||
| 1222 | memset (vb, 0, sizeof (*vb)); | ||
| 1223 | return 0; | ||
| 1224 | } | ||
| 1225 | case VIDIOCKEY: | ||
| 1226 | return 0; | ||
| 1227 | case VIDIOCCAPTURE: | ||
| 1228 | { | ||
| 1229 | PDEBUG (2, "STV(e): VIDIOCCAPTURE failed"); | ||
| 1230 | return -EINVAL; | ||
| 1231 | } | ||
| 1232 | case VIDIOCSFBUF: | ||
| 1233 | case VIDIOCGTUNER: | ||
| 1234 | case VIDIOCSTUNER: | ||
| 1235 | case VIDIOCGFREQ: | ||
| 1236 | case VIDIOCSFREQ: | ||
| 1237 | case VIDIOCGAUDIO: | ||
| 1238 | case VIDIOCSAUDIO: | ||
| 1239 | return -EINVAL; | ||
| 1240 | default: | ||
| 1241 | return -ENOIOCTLCMD; | ||
| 1242 | } /* end switch */ | ||
| 1243 | |||
| 1244 | return 0; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | static int stv680_ioctl(struct inode *inode, struct file *file, | ||
| 1248 | unsigned int cmd, unsigned long arg) | ||
| 1249 | { | ||
| 1250 | return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl); | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | static int stv680_mmap (struct file *file, struct vm_area_struct *vma) | ||
| 1254 | { | ||
| 1255 | struct video_device *dev = file->private_data; | ||
| 1256 | struct usb_stv *stv680 = video_get_drvdata(dev); | ||
| 1257 | unsigned long start = vma->vm_start; | ||
| 1258 | unsigned long size = vma->vm_end-vma->vm_start; | ||
| 1259 | unsigned long page, pos; | ||
| 1260 | |||
| 1261 | mutex_lock(&stv680->lock); | ||
| 1262 | |||
| 1263 | if (stv680->udev == NULL) { | ||
| 1264 | mutex_unlock(&stv680->lock); | ||
| 1265 | return -EIO; | ||
| 1266 | } | ||
| 1267 | if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1) | ||
| 1268 | & ~(PAGE_SIZE - 1))) { | ||
| 1269 | mutex_unlock(&stv680->lock); | ||
| 1270 | return -EINVAL; | ||
| 1271 | } | ||
| 1272 | pos = (unsigned long) stv680->fbuf; | ||
| 1273 | while (size > 0) { | ||
| 1274 | page = vmalloc_to_pfn((void *)pos); | ||
| 1275 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | ||
| 1276 | mutex_unlock(&stv680->lock); | ||
| 1277 | return -EAGAIN; | ||
| 1278 | } | ||
| 1279 | start += PAGE_SIZE; | ||
| 1280 | pos += PAGE_SIZE; | ||
| 1281 | if (size > PAGE_SIZE) | ||
| 1282 | size -= PAGE_SIZE; | ||
| 1283 | else | ||
| 1284 | size = 0; | ||
| 1285 | } | ||
| 1286 | mutex_unlock(&stv680->lock); | ||
| 1287 | |||
| 1288 | return 0; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | static ssize_t stv680_read (struct file *file, char __user *buf, | ||
| 1292 | size_t count, loff_t *ppos) | ||
| 1293 | { | ||
| 1294 | struct video_device *dev = file->private_data; | ||
| 1295 | unsigned long int realcount = count; | ||
| 1296 | int ret = 0; | ||
| 1297 | struct usb_stv *stv680 = video_get_drvdata(dev); | ||
| 1298 | unsigned long int i; | ||
| 1299 | |||
| 1300 | if (STV680_NUMFRAMES != 2) { | ||
| 1301 | PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!"); | ||
| 1302 | return -1; | ||
| 1303 | } | ||
| 1304 | if (stv680->udev == NULL) | ||
| 1305 | return -EIO; | ||
| 1306 | if (realcount > (stv680->vwidth * stv680->vheight * 3)) | ||
| 1307 | realcount = stv680->vwidth * stv680->vheight * 3; | ||
| 1308 | |||
| 1309 | /* Shouldn't happen: */ | ||
| 1310 | if (stv680->frame[0].grabstate == FRAME_GRABBING) { | ||
| 1311 | PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read"); | ||
| 1312 | return -EBUSY; | ||
| 1313 | } | ||
| 1314 | stv680->frame[0].grabstate = FRAME_READY; | ||
| 1315 | stv680->frame[1].grabstate = FRAME_UNUSED; | ||
| 1316 | stv680->curframe = 0; | ||
| 1317 | |||
| 1318 | if (!stv680->streaming) | ||
| 1319 | stv680_start_stream (stv680); | ||
| 1320 | |||
| 1321 | if (!stv680->streaming) { | ||
| 1322 | ret = stv680_newframe (stv680, 0); /* ret should = 0 */ | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | ret = stv680_newframe (stv680, 0); | ||
| 1326 | |||
| 1327 | if (!ret) { | ||
| 1328 | if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) { | ||
| 1329 | PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i); | ||
| 1330 | return -EFAULT; | ||
| 1331 | } | ||
| 1332 | } else { | ||
| 1333 | realcount = ret; | ||
| 1334 | } | ||
| 1335 | stv680->frame[0].grabstate = FRAME_UNUSED; | ||
| 1336 | return realcount; | ||
| 1337 | } /* stv680_read */ | ||
| 1338 | |||
| 1339 | static struct file_operations stv680_fops = { | ||
| 1340 | .owner = THIS_MODULE, | ||
| 1341 | .open = stv_open, | ||
| 1342 | .release = stv_close, | ||
| 1343 | .read = stv680_read, | ||
| 1344 | .mmap = stv680_mmap, | ||
| 1345 | .ioctl = stv680_ioctl, | ||
| 1346 | .compat_ioctl = v4l_compat_ioctl32, | ||
| 1347 | .llseek = no_llseek, | ||
| 1348 | }; | ||
| 1349 | static struct video_device stv680_template = { | ||
| 1350 | .owner = THIS_MODULE, | ||
| 1351 | .name = "STV0680 USB camera", | ||
| 1352 | .type = VID_TYPE_CAPTURE, | ||
| 1353 | .hardware = VID_HARDWARE_SE401, | ||
| 1354 | .fops = &stv680_fops, | ||
| 1355 | .release = video_device_release, | ||
| 1356 | .minor = -1, | ||
| 1357 | }; | ||
| 1358 | |||
| 1359 | static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id) | ||
| 1360 | { | ||
| 1361 | struct usb_device *dev = interface_to_usbdev(intf); | ||
| 1362 | struct usb_host_interface *interface; | ||
| 1363 | struct usb_stv *stv680 = NULL; | ||
| 1364 | char *camera_name = NULL; | ||
| 1365 | int retval = 0; | ||
| 1366 | |||
| 1367 | /* We don't handle multi-config cameras */ | ||
| 1368 | if (dev->descriptor.bNumConfigurations != 1) { | ||
| 1369 | PDEBUG (0, "STV(e): Number of Configurations != 1"); | ||
| 1370 | return -ENODEV; | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | interface = &intf->altsetting[0]; | ||
| 1374 | /* Is it a STV680? */ | ||
| 1375 | if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) && | ||
| 1376 | (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) { | ||
| 1377 | camera_name = "STV0680"; | ||
| 1378 | PDEBUG (0, "STV(i): STV0680 camera found."); | ||
| 1379 | } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) && | ||
| 1380 | (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) { | ||
| 1381 | camera_name = "Creative WebCam Go Mini"; | ||
| 1382 | PDEBUG (0, "STV(i): Creative WebCam Go Mini found."); | ||
| 1383 | } else { | ||
| 1384 | PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values."); | ||
| 1385 | PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer."); | ||
| 1386 | retval = -ENODEV; | ||
| 1387 | goto error; | ||
| 1388 | } | ||
| 1389 | /* We found one */ | ||
| 1390 | if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { | ||
| 1391 | PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct."); | ||
| 1392 | retval = -ENOMEM; | ||
| 1393 | goto error; | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | stv680->udev = dev; | ||
| 1397 | stv680->camera_name = camera_name; | ||
| 1398 | |||
| 1399 | stv680->vdev = video_device_alloc(); | ||
| 1400 | if (!stv680->vdev) { | ||
| 1401 | retval = -ENOMEM; | ||
| 1402 | goto error; | ||
| 1403 | } | ||
| 1404 | memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template)); | ||
| 1405 | stv680->vdev->dev = &intf->dev; | ||
| 1406 | video_set_drvdata(stv680->vdev, stv680); | ||
| 1407 | |||
| 1408 | memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name)); | ||
| 1409 | init_waitqueue_head (&stv680->wq); | ||
| 1410 | mutex_init (&stv680->lock); | ||
| 1411 | wmb (); | ||
| 1412 | |||
| 1413 | if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { | ||
| 1414 | PDEBUG (0, "STV(e): video_register_device failed"); | ||
| 1415 | retval = -EIO; | ||
| 1416 | goto error_vdev; | ||
| 1417 | } | ||
| 1418 | PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); | ||
| 1419 | |||
| 1420 | usb_set_intfdata (intf, stv680); | ||
| 1421 | stv680_create_sysfs_files(stv680->vdev); | ||
| 1422 | return 0; | ||
| 1423 | |||
| 1424 | error_vdev: | ||
| 1425 | video_device_release(stv680->vdev); | ||
| 1426 | error: | ||
| 1427 | kfree(stv680); | ||
| 1428 | return retval; | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) | ||
| 1432 | { | ||
| 1433 | int i; | ||
| 1434 | |||
| 1435 | stv680->udev = NULL; | ||
| 1436 | stv680->frame[0].grabstate = FRAME_ERROR; | ||
| 1437 | stv680->frame[1].grabstate = FRAME_ERROR; | ||
| 1438 | stv680->streaming = 0; | ||
| 1439 | |||
| 1440 | wake_up_interruptible (&stv680->wq); | ||
| 1441 | |||
| 1442 | for (i = 0; i < STV680_NUMSBUF; i++) | ||
| 1443 | if (stv680->urb[i]) { | ||
| 1444 | usb_kill_urb (stv680->urb[i]); | ||
| 1445 | usb_free_urb (stv680->urb[i]); | ||
| 1446 | stv680->urb[i] = NULL; | ||
| 1447 | kfree(stv680->sbuf[i].data); | ||
| 1448 | } | ||
| 1449 | for (i = 0; i < STV680_NUMSCRATCH; i++) | ||
| 1450 | kfree(stv680->scratch[i].data); | ||
| 1451 | PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); | ||
| 1452 | |||
| 1453 | /* Free the memory */ | ||
| 1454 | kfree(stv680); | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | static void stv680_disconnect (struct usb_interface *intf) | ||
| 1458 | { | ||
| 1459 | struct usb_stv *stv680 = usb_get_intfdata (intf); | ||
| 1460 | |||
| 1461 | usb_set_intfdata (intf, NULL); | ||
| 1462 | |||
| 1463 | if (stv680) { | ||
| 1464 | /* We don't want people trying to open up the device */ | ||
| 1465 | if (stv680->vdev) { | ||
| 1466 | stv680_remove_sysfs_files(stv680->vdev); | ||
| 1467 | video_unregister_device(stv680->vdev); | ||
| 1468 | stv680->vdev = NULL; | ||
| 1469 | } | ||
| 1470 | if (!stv680->user) { | ||
| 1471 | usb_stv680_remove_disconnected (stv680); | ||
| 1472 | } else { | ||
| 1473 | stv680->removed = 1; | ||
| 1474 | } | ||
| 1475 | } | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | static struct usb_driver stv680_driver = { | ||
| 1479 | .name = "stv680", | ||
| 1480 | .probe = stv680_probe, | ||
| 1481 | .disconnect = stv680_disconnect, | ||
| 1482 | .id_table = device_table | ||
| 1483 | }; | ||
| 1484 | |||
| 1485 | /******************************************************************** | ||
| 1486 | * Module routines | ||
| 1487 | ********************************************************************/ | ||
| 1488 | |||
| 1489 | static int __init usb_stv680_init (void) | ||
| 1490 | { | ||
| 1491 | if (usb_register (&stv680_driver) < 0) { | ||
| 1492 | PDEBUG (0, "STV(e): Could not setup STV0680 driver"); | ||
| 1493 | return -1; | ||
| 1494 | } | ||
| 1495 | PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION); | ||
| 1496 | |||
| 1497 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
| 1498 | return 0; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | static void __exit usb_stv680_exit (void) | ||
| 1502 | { | ||
| 1503 | usb_deregister (&stv680_driver); | ||
| 1504 | PDEBUG (0, "STV(i): driver deregistered"); | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | module_init (usb_stv680_init); | ||
| 1508 | module_exit (usb_stv680_exit); | ||
diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h deleted file mode 100644 index ea46e0001e6d..000000000000 --- a/drivers/usb/media/stv680.h +++ /dev/null | |||
| @@ -1,227 +0,0 @@ | |||
| 1 | /**************************************************************************** | ||
| 2 | * | ||
| 3 | * Filename: stv680.h | ||
| 4 | * | ||
| 5 | * Description: | ||
| 6 | * This is a USB driver for STV0680 based usb video cameras. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | * | ||
| 22 | ****************************************************************************/ | ||
| 23 | |||
| 24 | /* size of usb transfers */ | ||
| 25 | #define STV680_PACKETSIZE 4096 | ||
| 26 | |||
| 27 | /* number of queued bulk transfers to use, may have problems if > 1 */ | ||
| 28 | #define STV680_NUMSBUF 1 | ||
| 29 | |||
| 30 | /* number of frames supported by the v4l part */ | ||
| 31 | #define STV680_NUMFRAMES 2 | ||
| 32 | |||
| 33 | /* scratch buffers for passing data to the decoders: 2 or 4 are good */ | ||
| 34 | #define STV680_NUMSCRATCH 2 | ||
| 35 | |||
| 36 | /* number of nul sized packets to receive before kicking the camera */ | ||
| 37 | #define STV680_MAX_NULLPACKETS 200 | ||
| 38 | |||
| 39 | /* number of decoding errors before kicking the camera */ | ||
| 40 | #define STV680_MAX_ERRORS 100 | ||
| 41 | |||
| 42 | #define USB_PENCAM_VENDOR_ID 0x0553 | ||
| 43 | #define USB_PENCAM_PRODUCT_ID 0x0202 | ||
| 44 | |||
| 45 | #define USB_CREATIVEGOMINI_VENDOR_ID 0x041e | ||
| 46 | #define USB_CREATIVEGOMINI_PRODUCT_ID 0x4007 | ||
| 47 | |||
| 48 | #define PENCAM_TIMEOUT 1000 | ||
| 49 | /* fmt 4 */ | ||
| 50 | #define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24 | ||
| 51 | |||
| 52 | static struct usb_device_id device_table[] = { | ||
| 53 | {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)}, | ||
| 54 | {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)}, | ||
| 55 | {} | ||
| 56 | }; | ||
| 57 | MODULE_DEVICE_TABLE (usb, device_table); | ||
| 58 | |||
| 59 | struct stv680_sbuf { | ||
| 60 | unsigned char *data; | ||
| 61 | }; | ||
| 62 | |||
| 63 | enum { | ||
| 64 | FRAME_UNUSED, /* Unused (no MCAPTURE) */ | ||
| 65 | FRAME_READY, /* Ready to start grabbing */ | ||
| 66 | FRAME_GRABBING, /* In the process of being grabbed into */ | ||
| 67 | FRAME_DONE, /* Finished grabbing, but not been synced yet */ | ||
| 68 | FRAME_ERROR, /* Something bad happened while processing */ | ||
| 69 | }; | ||
| 70 | |||
| 71 | enum { | ||
| 72 | BUFFER_UNUSED, | ||
| 73 | BUFFER_READY, | ||
| 74 | BUFFER_BUSY, | ||
| 75 | BUFFER_DONE, | ||
| 76 | }; | ||
| 77 | |||
| 78 | /* raw camera data <- sbuf (urb transfer buf) */ | ||
| 79 | struct stv680_scratch { | ||
| 80 | unsigned char *data; | ||
| 81 | volatile int state; | ||
| 82 | int offset; | ||
| 83 | int length; | ||
| 84 | }; | ||
| 85 | |||
| 86 | /* processed data for display ends up here, after bayer */ | ||
| 87 | struct stv680_frame { | ||
| 88 | unsigned char *data; /* Frame buffer */ | ||
| 89 | volatile int grabstate; /* State of grabbing */ | ||
| 90 | unsigned char *curline; | ||
| 91 | int curlinepix; | ||
| 92 | int curpix; | ||
| 93 | }; | ||
| 94 | |||
| 95 | /* this is almost the video structure uvd_t, with extra parameters for stv */ | ||
| 96 | struct usb_stv { | ||
| 97 | struct video_device *vdev; | ||
| 98 | |||
| 99 | struct usb_device *udev; | ||
| 100 | |||
| 101 | unsigned char bulk_in_endpointAddr; /* __u8 the address of the bulk in endpoint */ | ||
| 102 | char *camera_name; | ||
| 103 | |||
| 104 | unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */ | ||
| 105 | int SupportedModes; | ||
| 106 | int CIF; | ||
| 107 | int VGA; | ||
| 108 | int QVGA; | ||
| 109 | int cwidth; /* camera width */ | ||
| 110 | int cheight; /* camera height */ | ||
| 111 | int maxwidth; /* max video width */ | ||
| 112 | int maxheight; /* max video height */ | ||
| 113 | int vwidth; /* current width for video window */ | ||
| 114 | int vheight; /* current height for video window */ | ||
| 115 | unsigned long int rawbufsize; | ||
| 116 | unsigned long int maxframesize; /* rawbufsize * 3 for RGB */ | ||
| 117 | |||
| 118 | int origGain; | ||
| 119 | int origMode; /* original camera mode */ | ||
| 120 | |||
| 121 | struct mutex lock; /* to lock the structure */ | ||
| 122 | int user; /* user count for exclusive use */ | ||
| 123 | int removed; /* device disconnected */ | ||
| 124 | int streaming; /* Are we streaming video? */ | ||
| 125 | char *fbuf; /* Videodev buffer area */ | ||
| 126 | struct urb *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */ | ||
| 127 | int curframe; /* Current receiving frame */ | ||
| 128 | struct stv680_frame frame[STV680_NUMFRAMES]; /* # frames supported by v4l part */ | ||
| 129 | int readcount; | ||
| 130 | int framecount; | ||
| 131 | int error; | ||
| 132 | int dropped; | ||
| 133 | int scratch_next; | ||
| 134 | int scratch_use; | ||
| 135 | int scratch_overflow; | ||
| 136 | struct stv680_scratch scratch[STV680_NUMSCRATCH]; /* for decoders */ | ||
| 137 | struct stv680_sbuf sbuf[STV680_NUMSBUF]; | ||
| 138 | |||
| 139 | unsigned int brightness; | ||
| 140 | unsigned int chgbright; | ||
| 141 | unsigned int whiteness; | ||
| 142 | unsigned int colour; | ||
| 143 | unsigned int contrast; | ||
| 144 | unsigned int hue; | ||
| 145 | unsigned int palette; | ||
| 146 | unsigned int depth; /* rgb24 in bits */ | ||
| 147 | |||
| 148 | wait_queue_head_t wq; /* Processes waiting */ | ||
| 149 | |||
| 150 | int nullpackets; | ||
| 151 | }; | ||
| 152 | |||
| 153 | |||
| 154 | static const unsigned char red[256] = { | ||
| 155 | 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, | ||
| 156 | 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, | ||
| 157 | 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, | ||
| 158 | 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, | ||
| 159 | 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, | ||
| 160 | 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, | ||
| 161 | 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, | ||
| 162 | 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, | ||
| 163 | 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, | ||
| 164 | 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, | ||
| 165 | 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, | ||
| 166 | 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, | ||
| 167 | 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, | ||
| 168 | 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, | ||
| 169 | 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, | ||
| 170 | 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, | ||
| 171 | 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, | ||
| 172 | 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, | ||
| 173 | 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, | ||
| 174 | 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, | ||
| 175 | 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, | ||
| 176 | 220, 220, 221, 221 | ||
| 177 | }; | ||
| 178 | |||
| 179 | static const unsigned char green[256] = { | ||
| 180 | 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, | ||
| 181 | 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, | ||
| 182 | 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, | ||
| 183 | 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, | ||
| 184 | 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, | ||
| 185 | 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, | ||
| 186 | 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, | ||
| 187 | 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, | ||
| 188 | 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, | ||
| 189 | 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, | ||
| 190 | 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, | ||
| 191 | 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, | ||
| 192 | 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, | ||
| 193 | 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, | ||
| 194 | 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, | ||
| 195 | 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, | ||
| 196 | 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, | ||
| 197 | 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, | ||
| 198 | 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, | ||
| 199 | 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, | ||
| 200 | 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, | ||
| 201 | 245, 245, 246, 246 | ||
| 202 | }; | ||
| 203 | |||
| 204 | static const unsigned char blue[256] = { | ||
| 205 | 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, | ||
| 206 | 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, | ||
| 207 | 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, | ||
| 208 | 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, | ||
| 209 | 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, | ||
| 210 | 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, | ||
| 211 | 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, | ||
| 212 | 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, | ||
| 213 | 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, | ||
| 214 | 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, | ||
| 215 | 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, | ||
| 216 | 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, | ||
| 217 | 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, | ||
| 218 | 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, | ||
| 219 | 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, | ||
| 220 | 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, | ||
| 221 | 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, | ||
| 222 | 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, | ||
| 223 | 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, | ||
| 224 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||
| 225 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||
| 226 | 255, 255, 255, 255 | ||
| 227 | }; | ||
diff --git a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c deleted file mode 100644 index 75ff755224df..000000000000 --- a/drivers/usb/media/ultracam.c +++ /dev/null | |||
| @@ -1,679 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * USB NB Camera driver | ||
| 3 | * | ||
| 4 | * HISTORY: | ||
| 5 | * 25-Dec-2002 Dmitri Removed lighting, sharpness parameters, methods. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/sched.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/init.h> | ||
| 12 | |||
| 13 | #include "usbvideo.h" | ||
| 14 | |||
| 15 | #define ULTRACAM_VENDOR_ID 0x0461 | ||
| 16 | #define ULTRACAM_PRODUCT_ID 0x0813 | ||
| 17 | |||
| 18 | #define MAX_CAMERAS 4 /* How many devices we allow to connect */ | ||
| 19 | |||
| 20 | /* | ||
| 21 | * This structure lives in uvd_t->user field. | ||
| 22 | */ | ||
| 23 | typedef struct { | ||
| 24 | int initialized; /* Had we already sent init sequence? */ | ||
| 25 | int camera_model; /* What type of IBM camera we got? */ | ||
| 26 | int has_hdr; | ||
| 27 | } ultracam_t; | ||
| 28 | #define ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data)) | ||
| 29 | |||
| 30 | static struct usbvideo *cams = NULL; | ||
| 31 | |||
| 32 | static int debug = 0; | ||
| 33 | |||
| 34 | static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ | ||
| 35 | |||
| 36 | static const int min_canvasWidth = 8; | ||
| 37 | static const int min_canvasHeight = 4; | ||
| 38 | |||
| 39 | #define FRAMERATE_MIN 0 | ||
| 40 | #define FRAMERATE_MAX 6 | ||
| 41 | static int framerate = -1; | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Here we define several initialization variables. They may | ||
| 45 | * be used to automatically set color, hue, brightness and | ||
| 46 | * contrast to desired values. This is particularly useful in | ||
| 47 | * case of webcams (which have no controls and no on-screen | ||
| 48 | * output) and also when a client V4L software is used that | ||
| 49 | * does not have some of those controls. In any case it's | ||
| 50 | * good to have startup values as options. | ||
| 51 | * | ||
| 52 | * These values are all in [0..255] range. This simplifies | ||
| 53 | * operation. Note that actual values of V4L variables may | ||
| 54 | * be scaled up (as much as << 8). User can see that only | ||
| 55 | * on overlay output, however, or through a V4L client. | ||
| 56 | */ | ||
| 57 | static int init_brightness = 128; | ||
| 58 | static int init_contrast = 192; | ||
| 59 | static int init_color = 128; | ||
| 60 | static int init_hue = 128; | ||
| 61 | static int hue_correction = 128; | ||
| 62 | |||
| 63 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
| 64 | MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); | ||
| 65 | module_param(flags, int, 0); | ||
| 66 | MODULE_PARM_DESC(flags, | ||
| 67 | "Bitfield: 0=VIDIOCSYNC, " | ||
| 68 | "1=B/W, " | ||
| 69 | "2=show hints, " | ||
| 70 | "3=show stats, " | ||
| 71 | "4=test pattern, " | ||
| 72 | "5=separate frames, " | ||
| 73 | "6=clean frames"); | ||
| 74 | module_param(framerate, int, 0); | ||
| 75 | MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); | ||
| 76 | |||
| 77 | module_param(init_brightness, int, 0); | ||
| 78 | MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); | ||
| 79 | module_param(init_contrast, int, 0); | ||
| 80 | MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); | ||
| 81 | module_param(init_color, int, 0); | ||
| 82 | MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); | ||
| 83 | module_param(init_hue, int, 0); | ||
| 84 | MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); | ||
| 85 | module_param(hue_correction, int, 0); | ||
| 86 | MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); | ||
| 87 | |||
| 88 | /* | ||
| 89 | * ultracam_ProcessIsocData() | ||
| 90 | * | ||
| 91 | * Generic routine to parse the ring queue data. It employs either | ||
| 92 | * ultracam_find_header() or ultracam_parse_lines() to do most | ||
| 93 | * of work. | ||
| 94 | * | ||
| 95 | * 02-Nov-2000 First (mostly dummy) version. | ||
| 96 | * 06-Nov-2000 Rewrote to dump all data into frame. | ||
| 97 | */ | ||
| 98 | static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame) | ||
| 99 | { | ||
| 100 | int n; | ||
| 101 | |||
| 102 | assert(uvd != NULL); | ||
| 103 | assert(frame != NULL); | ||
| 104 | |||
| 105 | /* Try to move data from queue into frame buffer */ | ||
| 106 | n = RingQueue_GetLength(&uvd->dp); | ||
| 107 | if (n > 0) { | ||
| 108 | int m; | ||
| 109 | /* See how much spare we have left */ | ||
| 110 | m = uvd->max_frame_size - frame->seqRead_Length; | ||
| 111 | if (n > m) | ||
| 112 | n = m; | ||
| 113 | /* Now move that much data into frame buffer */ | ||
| 114 | RingQueue_Dequeue( | ||
| 115 | &uvd->dp, | ||
| 116 | frame->data + frame->seqRead_Length, | ||
| 117 | m); | ||
| 118 | frame->seqRead_Length += m; | ||
| 119 | } | ||
| 120 | /* See if we filled the frame */ | ||
| 121 | if (frame->seqRead_Length >= uvd->max_frame_size) { | ||
| 122 | frame->frameState = FrameState_Done; | ||
| 123 | uvd->curframe = -1; | ||
| 124 | uvd->stats.frame_num++; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | /* | ||
| 129 | * ultracam_veio() | ||
| 130 | * | ||
| 131 | * History: | ||
| 132 | * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. | ||
| 133 | */ | ||
| 134 | static int ultracam_veio( | ||
| 135 | struct uvd *uvd, | ||
| 136 | unsigned char req, | ||
| 137 | unsigned short value, | ||
| 138 | unsigned short index, | ||
| 139 | int is_out) | ||
| 140 | { | ||
| 141 | static const char proc[] = "ultracam_veio"; | ||
| 142 | unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; | ||
| 143 | int i; | ||
| 144 | |||
| 145 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
| 146 | return 0; | ||
| 147 | |||
| 148 | if (!is_out) { | ||
| 149 | i = usb_control_msg( | ||
| 150 | uvd->dev, | ||
| 151 | usb_rcvctrlpipe(uvd->dev, 0), | ||
| 152 | req, | ||
| 153 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 154 | value, | ||
| 155 | index, | ||
| 156 | cp, | ||
| 157 | sizeof(cp), | ||
| 158 | 1000); | ||
| 159 | #if 1 | ||
| 160 | info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " | ||
| 161 | "(req=$%02x val=$%04x ind=$%04x)", | ||
| 162 | cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], | ||
| 163 | req, value, index); | ||
| 164 | #endif | ||
| 165 | } else { | ||
| 166 | i = usb_control_msg( | ||
| 167 | uvd->dev, | ||
| 168 | usb_sndctrlpipe(uvd->dev, 0), | ||
| 169 | req, | ||
| 170 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 171 | value, | ||
| 172 | index, | ||
| 173 | NULL, | ||
| 174 | 0, | ||
| 175 | 1000); | ||
| 176 | } | ||
| 177 | if (i < 0) { | ||
| 178 | err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", | ||
| 179 | proc, i); | ||
| 180 | uvd->last_error = i; | ||
| 181 | } | ||
| 182 | return i; | ||
| 183 | } | ||
| 184 | |||
| 185 | /* | ||
| 186 | * ultracam_calculate_fps() | ||
| 187 | */ | ||
| 188 | static int ultracam_calculate_fps(struct uvd *uvd) | ||
| 189 | { | ||
| 190 | return 3 + framerate*4 + framerate/2; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* | ||
| 194 | * ultracam_adjust_contrast() | ||
| 195 | */ | ||
| 196 | static void ultracam_adjust_contrast(struct uvd *uvd) | ||
| 197 | { | ||
| 198 | } | ||
| 199 | |||
| 200 | /* | ||
| 201 | * ultracam_set_brightness() | ||
| 202 | * | ||
| 203 | * This procedure changes brightness of the picture. | ||
| 204 | */ | ||
| 205 | static void ultracam_set_brightness(struct uvd *uvd) | ||
| 206 | { | ||
| 207 | } | ||
| 208 | |||
| 209 | static void ultracam_set_hue(struct uvd *uvd) | ||
| 210 | { | ||
| 211 | } | ||
| 212 | |||
| 213 | /* | ||
| 214 | * ultracam_adjust_picture() | ||
| 215 | * | ||
| 216 | * This procedure gets called from V4L interface to update picture settings. | ||
| 217 | * Here we change brightness and contrast. | ||
| 218 | */ | ||
| 219 | static void ultracam_adjust_picture(struct uvd *uvd) | ||
| 220 | { | ||
| 221 | ultracam_adjust_contrast(uvd); | ||
| 222 | ultracam_set_brightness(uvd); | ||
| 223 | ultracam_set_hue(uvd); | ||
| 224 | } | ||
| 225 | |||
| 226 | /* | ||
| 227 | * ultracam_video_stop() | ||
| 228 | * | ||
| 229 | * This code tells camera to stop streaming. The interface remains | ||
| 230 | * configured and bandwidth - claimed. | ||
| 231 | */ | ||
| 232 | static void ultracam_video_stop(struct uvd *uvd) | ||
| 233 | { | ||
| 234 | } | ||
| 235 | |||
| 236 | /* | ||
| 237 | * ultracam_reinit_iso() | ||
| 238 | * | ||
| 239 | * This procedure sends couple of commands to the camera and then | ||
| 240 | * resets the video pipe. This sequence was observed to reinit the | ||
| 241 | * camera or, at least, to initiate ISO data stream. | ||
| 242 | */ | ||
| 243 | static void ultracam_reinit_iso(struct uvd *uvd, int do_stop) | ||
| 244 | { | ||
| 245 | } | ||
| 246 | |||
| 247 | static void ultracam_video_start(struct uvd *uvd) | ||
| 248 | { | ||
| 249 | ultracam_reinit_iso(uvd, 0); | ||
| 250 | } | ||
| 251 | |||
| 252 | static int ultracam_resetPipe(struct uvd *uvd) | ||
| 253 | { | ||
| 254 | usb_clear_halt(uvd->dev, uvd->video_endp); | ||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | static int ultracam_alternateSetting(struct uvd *uvd, int setting) | ||
| 259 | { | ||
| 260 | static const char proc[] = "ultracam_alternateSetting"; | ||
| 261 | int i; | ||
| 262 | i = usb_set_interface(uvd->dev, uvd->iface, setting); | ||
| 263 | if (i < 0) { | ||
| 264 | err("%s: usb_set_interface error", proc); | ||
| 265 | uvd->last_error = i; | ||
| 266 | return -EBUSY; | ||
| 267 | } | ||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* | ||
| 272 | * Return negative code on failure, 0 on success. | ||
| 273 | */ | ||
| 274 | static int ultracam_setup_on_open(struct uvd *uvd) | ||
| 275 | { | ||
| 276 | int setup_ok = 0; /* Success by default */ | ||
| 277 | /* Send init sequence only once, it's large! */ | ||
| 278 | if (!ULTRACAM_T(uvd)->initialized) { | ||
| 279 | ultracam_alternateSetting(uvd, 0x04); | ||
| 280 | ultracam_alternateSetting(uvd, 0x00); | ||
| 281 | ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1); | ||
| 282 | ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1); | ||
| 283 | ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1); | ||
| 284 | ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); | ||
| 285 | ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1); | ||
| 286 | ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1); | ||
| 287 | ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1); | ||
| 288 | ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1); | ||
| 289 | ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1); | ||
| 290 | ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1); | ||
| 291 | ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1); | ||
| 292 | ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1); | ||
| 293 | ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1); | ||
| 294 | ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1); | ||
| 295 | ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1); | ||
| 296 | ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1); | ||
| 297 | ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1); | ||
| 298 | ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1); | ||
| 299 | ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1); | ||
| 300 | ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1); | ||
| 301 | ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1); | ||
| 302 | ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); | ||
| 303 | ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); | ||
| 304 | ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); | ||
| 305 | ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); | ||
| 306 | ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); | ||
| 307 | ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); | ||
| 308 | ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); | ||
| 309 | ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); | ||
| 310 | ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); | ||
| 311 | ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1); | ||
| 312 | ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1); | ||
| 313 | ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1); | ||
| 314 | ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1); | ||
| 315 | ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1); | ||
| 316 | ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1); | ||
| 317 | ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1); | ||
| 318 | ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1); | ||
| 319 | ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1); | ||
| 320 | ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1); | ||
| 321 | ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1); | ||
| 322 | ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1); | ||
| 323 | ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1); | ||
| 324 | ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1); | ||
| 325 | ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1); | ||
| 326 | ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1); | ||
| 327 | ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1); | ||
| 328 | ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1); | ||
| 329 | ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1); | ||
| 330 | ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1); | ||
| 331 | ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1); | ||
| 332 | ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1); | ||
| 333 | ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1); | ||
| 334 | ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1); | ||
| 335 | ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1); | ||
| 336 | ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1); | ||
| 337 | ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); | ||
| 338 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); | ||
| 339 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
| 340 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 341 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 342 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 343 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 344 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 345 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 346 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 347 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 348 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 349 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 350 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 351 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 352 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 353 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 354 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 355 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 356 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 357 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 358 | ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); | ||
| 359 | ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1); | ||
| 360 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
| 361 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 362 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 363 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 364 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 365 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 366 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 367 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 368 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 369 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 370 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 371 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 372 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 373 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 374 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 375 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 376 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 377 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 378 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 379 | ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1); | ||
| 380 | ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1); | ||
| 381 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
| 382 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | ||
| 383 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | ||
| 384 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | ||
| 385 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | ||
| 386 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | ||
| 387 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | ||
| 388 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 389 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | ||
| 390 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | ||
| 391 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | ||
| 392 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | ||
| 393 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | ||
| 394 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | ||
| 395 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 396 | ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1); | ||
| 397 | ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1); | ||
| 398 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
| 399 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | ||
| 400 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | ||
| 401 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | ||
| 402 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | ||
| 403 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | ||
| 404 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | ||
| 405 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 406 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | ||
| 407 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | ||
| 408 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | ||
| 409 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | ||
| 410 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | ||
| 411 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | ||
| 412 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
| 413 | ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1); | ||
| 414 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); | ||
| 415 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
| 416 | ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1); | ||
| 417 | ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0); | ||
| 418 | ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0); | ||
| 419 | ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0); | ||
| 420 | ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0); | ||
| 421 | ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0); | ||
| 422 | ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0); | ||
| 423 | ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0); | ||
| 424 | ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0); | ||
| 425 | ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0); | ||
| 426 | ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); | ||
| 427 | ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); | ||
| 428 | ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); | ||
| 429 | ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); | ||
| 430 | ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); | ||
| 431 | ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); | ||
| 432 | ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); | ||
| 433 | ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); | ||
| 434 | ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); | ||
| 435 | ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0); | ||
| 436 | ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1); | ||
| 437 | ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1); | ||
| 438 | ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1); | ||
| 439 | ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1); | ||
| 440 | ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1); | ||
| 441 | ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1); | ||
| 442 | ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1); | ||
| 443 | ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1); | ||
| 444 | ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1); | ||
| 445 | ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); | ||
| 446 | ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1); | ||
| 447 | ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1); | ||
| 448 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
| 449 | ultracam_alternateSetting(uvd, 0x04); | ||
| 450 | ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); | ||
| 451 | ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); | ||
| 452 | ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1); | ||
| 453 | ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1); | ||
| 454 | ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1); | ||
| 455 | ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0); | ||
| 456 | ultracam_resetPipe(uvd); | ||
| 457 | ULTRACAM_T(uvd)->initialized = (setup_ok != 0); | ||
| 458 | } | ||
| 459 | return setup_ok; | ||
| 460 | } | ||
| 461 | |||
| 462 | static void ultracam_configure_video(struct uvd *uvd) | ||
| 463 | { | ||
| 464 | if (uvd == NULL) | ||
| 465 | return; | ||
| 466 | |||
| 467 | RESTRICT_TO_RANGE(init_brightness, 0, 255); | ||
| 468 | RESTRICT_TO_RANGE(init_contrast, 0, 255); | ||
| 469 | RESTRICT_TO_RANGE(init_color, 0, 255); | ||
| 470 | RESTRICT_TO_RANGE(init_hue, 0, 255); | ||
| 471 | RESTRICT_TO_RANGE(hue_correction, 0, 255); | ||
| 472 | |||
| 473 | memset(&uvd->vpic, 0, sizeof(uvd->vpic)); | ||
| 474 | memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); | ||
| 475 | |||
| 476 | uvd->vpic.colour = init_color << 8; | ||
| 477 | uvd->vpic.hue = init_hue << 8; | ||
| 478 | uvd->vpic.brightness = init_brightness << 8; | ||
| 479 | uvd->vpic.contrast = init_contrast << 8; | ||
| 480 | uvd->vpic.whiteness = 105 << 8; /* This one isn't used */ | ||
| 481 | uvd->vpic.depth = 24; | ||
| 482 | uvd->vpic.palette = VIDEO_PALETTE_RGB24; | ||
| 483 | |||
| 484 | memset(&uvd->vcap, 0, sizeof(uvd->vcap)); | ||
| 485 | strcpy(uvd->vcap.name, "IBM Ultra Camera"); | ||
| 486 | uvd->vcap.type = VID_TYPE_CAPTURE; | ||
| 487 | uvd->vcap.channels = 1; | ||
| 488 | uvd->vcap.audios = 0; | ||
| 489 | uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas); | ||
| 490 | uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas); | ||
| 491 | uvd->vcap.minwidth = min_canvasWidth; | ||
| 492 | uvd->vcap.minheight = min_canvasHeight; | ||
| 493 | |||
| 494 | memset(&uvd->vchan, 0, sizeof(uvd->vchan)); | ||
| 495 | uvd->vchan.flags = 0; | ||
| 496 | uvd->vchan.tuners = 0; | ||
| 497 | uvd->vchan.channel = 0; | ||
| 498 | uvd->vchan.type = VIDEO_TYPE_CAMERA; | ||
| 499 | strcpy(uvd->vchan.name, "Camera"); | ||
| 500 | } | ||
| 501 | |||
| 502 | /* | ||
| 503 | * ultracam_probe() | ||
| 504 | * | ||
| 505 | * This procedure queries device descriptor and accepts the interface | ||
| 506 | * if it looks like our camera. | ||
| 507 | * | ||
| 508 | * History: | ||
| 509 | * 12-Nov-2000 Reworked to comply with new probe() signature. | ||
| 510 | * 23-Jan-2001 Added compatibility with 2.2.x kernels. | ||
| 511 | */ | ||
| 512 | static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid) | ||
| 513 | { | ||
| 514 | struct usb_device *dev = interface_to_usbdev(intf); | ||
| 515 | struct uvd *uvd = NULL; | ||
| 516 | int ix, i, nas; | ||
| 517 | int actInterface=-1, inactInterface=-1, maxPS=0; | ||
| 518 | unsigned char video_ep = 0; | ||
| 519 | |||
| 520 | if (debug >= 1) | ||
| 521 | info("ultracam_probe(%p)", intf); | ||
| 522 | |||
| 523 | /* We don't handle multi-config cameras */ | ||
| 524 | if (dev->descriptor.bNumConfigurations != 1) | ||
| 525 | return -ENODEV; | ||
| 526 | |||
| 527 | info("IBM Ultra camera found (rev. 0x%04x)", | ||
| 528 | le16_to_cpu(dev->descriptor.bcdDevice)); | ||
| 529 | |||
| 530 | /* Validate found interface: must have one ISO endpoint */ | ||
| 531 | nas = intf->num_altsetting; | ||
| 532 | if (debug > 0) | ||
| 533 | info("Number of alternate settings=%d.", nas); | ||
| 534 | if (nas < 8) { | ||
| 535 | err("Too few alternate settings for this camera!"); | ||
| 536 | return -ENODEV; | ||
| 537 | } | ||
| 538 | /* Validate all alternate settings */ | ||
| 539 | for (ix=0; ix < nas; ix++) { | ||
| 540 | const struct usb_host_interface *interface; | ||
| 541 | const struct usb_endpoint_descriptor *endpoint; | ||
| 542 | |||
| 543 | interface = &intf->altsetting[ix]; | ||
| 544 | i = interface->desc.bAlternateSetting; | ||
| 545 | if (interface->desc.bNumEndpoints != 1) { | ||
| 546 | err("Interface %d. has %u. endpoints!", | ||
| 547 | interface->desc.bInterfaceNumber, | ||
| 548 | (unsigned)(interface->desc.bNumEndpoints)); | ||
| 549 | return -ENODEV; | ||
| 550 | } | ||
| 551 | endpoint = &interface->endpoint[0].desc; | ||
| 552 | if (video_ep == 0) | ||
| 553 | video_ep = endpoint->bEndpointAddress; | ||
| 554 | else if (video_ep != endpoint->bEndpointAddress) { | ||
| 555 | err("Alternate settings have different endpoint addresses!"); | ||
| 556 | return -ENODEV; | ||
| 557 | } | ||
| 558 | if ((endpoint->bmAttributes & 0x03) != 0x01) { | ||
| 559 | err("Interface %d. has non-ISO endpoint!", | ||
| 560 | interface->desc.bInterfaceNumber); | ||
| 561 | return -ENODEV; | ||
| 562 | } | ||
| 563 | if ((endpoint->bEndpointAddress & 0x80) == 0) { | ||
| 564 | err("Interface %d. has ISO OUT endpoint!", | ||
| 565 | interface->desc.bInterfaceNumber); | ||
| 566 | return -ENODEV; | ||
| 567 | } | ||
| 568 | if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { | ||
| 569 | if (inactInterface < 0) | ||
| 570 | inactInterface = i; | ||
| 571 | else { | ||
| 572 | err("More than one inactive alt. setting!"); | ||
| 573 | return -ENODEV; | ||
| 574 | } | ||
| 575 | } else { | ||
| 576 | if (actInterface < 0) { | ||
| 577 | actInterface = i; | ||
| 578 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | ||
| 579 | if (debug > 0) | ||
| 580 | info("Active setting=%d. maxPS=%d.", i, maxPS); | ||
| 581 | } else { | ||
| 582 | /* Got another active alt. setting */ | ||
| 583 | if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) { | ||
| 584 | /* This one is better! */ | ||
| 585 | actInterface = i; | ||
| 586 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | ||
| 587 | if (debug > 0) { | ||
| 588 | info("Even better ctive setting=%d. maxPS=%d.", | ||
| 589 | i, maxPS); | ||
| 590 | } | ||
| 591 | } | ||
| 592 | } | ||
| 593 | } | ||
| 594 | } | ||
| 595 | if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { | ||
| 596 | err("Failed to recognize the camera!"); | ||
| 597 | return -ENODEV; | ||
| 598 | } | ||
| 599 | |||
| 600 | uvd = usbvideo_AllocateDevice(cams); | ||
| 601 | if (uvd != NULL) { | ||
| 602 | /* Here uvd is a fully allocated uvd object */ | ||
| 603 | uvd->flags = flags; | ||
| 604 | uvd->debug = debug; | ||
| 605 | uvd->dev = dev; | ||
| 606 | uvd->iface = intf->altsetting->desc.bInterfaceNumber; | ||
| 607 | uvd->ifaceAltInactive = inactInterface; | ||
| 608 | uvd->ifaceAltActive = actInterface; | ||
| 609 | uvd->video_endp = video_ep; | ||
| 610 | uvd->iso_packet_len = maxPS; | ||
| 611 | uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; | ||
| 612 | uvd->defaultPalette = VIDEO_PALETTE_RGB24; | ||
| 613 | uvd->canvas = VIDEOSIZE(640, 480); /* FIXME */ | ||
| 614 | uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/ | ||
| 615 | |||
| 616 | /* Initialize ibmcam-specific data */ | ||
| 617 | assert(ULTRACAM_T(uvd) != NULL); | ||
| 618 | ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */ | ||
| 619 | ULTRACAM_T(uvd)->initialized = 0; | ||
| 620 | |||
| 621 | ultracam_configure_video(uvd); | ||
| 622 | |||
| 623 | i = usbvideo_RegisterVideoDevice(uvd); | ||
| 624 | if (i != 0) { | ||
| 625 | err("usbvideo_RegisterVideoDevice() failed."); | ||
| 626 | uvd = NULL; | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | if (uvd) { | ||
| 631 | usb_set_intfdata (intf, uvd); | ||
| 632 | return 0; | ||
| 633 | } | ||
| 634 | return -EIO; | ||
| 635 | } | ||
| 636 | |||
| 637 | |||
| 638 | static struct usb_device_id id_table[] = { | ||
| 639 | { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) }, | ||
| 640 | { } /* Terminating entry */ | ||
| 641 | }; | ||
| 642 | |||
| 643 | /* | ||
| 644 | * ultracam_init() | ||
| 645 | * | ||
| 646 | * This code is run to initialize the driver. | ||
| 647 | */ | ||
| 648 | static int __init ultracam_init(void) | ||
| 649 | { | ||
| 650 | struct usbvideo_cb cbTbl; | ||
| 651 | memset(&cbTbl, 0, sizeof(cbTbl)); | ||
| 652 | cbTbl.probe = ultracam_probe; | ||
| 653 | cbTbl.setupOnOpen = ultracam_setup_on_open; | ||
| 654 | cbTbl.videoStart = ultracam_video_start; | ||
| 655 | cbTbl.videoStop = ultracam_video_stop; | ||
| 656 | cbTbl.processData = ultracam_ProcessIsocData; | ||
| 657 | cbTbl.postProcess = usbvideo_DeinterlaceFrame; | ||
| 658 | cbTbl.adjustPicture = ultracam_adjust_picture; | ||
| 659 | cbTbl.getFPS = ultracam_calculate_fps; | ||
| 660 | return usbvideo_register( | ||
| 661 | &cams, | ||
| 662 | MAX_CAMERAS, | ||
| 663 | sizeof(ultracam_t), | ||
| 664 | "ultracam", | ||
| 665 | &cbTbl, | ||
| 666 | THIS_MODULE, | ||
| 667 | id_table); | ||
| 668 | } | ||
| 669 | |||
| 670 | static void __exit ultracam_cleanup(void) | ||
| 671 | { | ||
| 672 | usbvideo_Deregister(&cams); | ||
| 673 | } | ||
| 674 | |||
| 675 | MODULE_DEVICE_TABLE(usb, id_table); | ||
| 676 | MODULE_LICENSE("GPL"); | ||
| 677 | |||
| 678 | module_init(ultracam_init); | ||
| 679 | module_exit(ultracam_cleanup); | ||
diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c deleted file mode 100644 index 0b51fae720a9..000000000000 --- a/drivers/usb/media/usbvideo.c +++ /dev/null | |||
| @@ -1,2190 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * This program is free software; you can redistribute it and/or modify | ||
| 3 | * it under the terms of the GNU General Public License as published by | ||
| 4 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 5 | * any later version. | ||
| 6 | * | ||
| 7 | * This program is distributed in the hope that it will be useful, | ||
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | * GNU General Public License for more details. | ||
| 11 | * | ||
| 12 | * You should have received a copy of the GNU General Public License | ||
| 13 | * along with this program; if not, write to the Free Software | ||
| 14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/sched.h> | ||
| 19 | #include <linux/list.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/mm.h> | ||
| 23 | #include <linux/smp_lock.h> | ||
| 24 | #include <linux/vmalloc.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/spinlock.h> | ||
| 27 | |||
| 28 | #include <asm/io.h> | ||
| 29 | |||
| 30 | #include "usbvideo.h" | ||
| 31 | |||
| 32 | #if defined(MAP_NR) | ||
| 33 | #define virt_to_page(v) MAP_NR(v) /* Kernels 2.2.x */ | ||
| 34 | #endif | ||
| 35 | |||
| 36 | static int video_nr = -1; | ||
| 37 | module_param(video_nr, int, 0); | ||
| 38 | |||
| 39 | /* | ||
| 40 | * Local prototypes. | ||
| 41 | */ | ||
| 42 | static void usbvideo_Disconnect(struct usb_interface *intf); | ||
| 43 | static void usbvideo_CameraRelease(struct uvd *uvd); | ||
| 44 | |||
| 45 | static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file, | ||
| 46 | unsigned int cmd, unsigned long arg); | ||
| 47 | static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma); | ||
| 48 | static int usbvideo_v4l_open(struct inode *inode, struct file *file); | ||
| 49 | static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, | ||
| 50 | size_t count, loff_t *ppos); | ||
| 51 | static int usbvideo_v4l_close(struct inode *inode, struct file *file); | ||
| 52 | |||
| 53 | static int usbvideo_StartDataPump(struct uvd *uvd); | ||
| 54 | static void usbvideo_StopDataPump(struct uvd *uvd); | ||
| 55 | static int usbvideo_GetFrame(struct uvd *uvd, int frameNum); | ||
| 56 | static int usbvideo_NewFrame(struct uvd *uvd, int framenum); | ||
| 57 | static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, | ||
| 58 | struct usbvideo_frame *frame); | ||
| 59 | |||
| 60 | /*******************************/ | ||
| 61 | /* Memory management functions */ | ||
| 62 | /*******************************/ | ||
| 63 | static void *usbvideo_rvmalloc(unsigned long size) | ||
| 64 | { | ||
| 65 | void *mem; | ||
| 66 | unsigned long adr; | ||
| 67 | |||
| 68 | size = PAGE_ALIGN(size); | ||
| 69 | mem = vmalloc_32(size); | ||
| 70 | if (!mem) | ||
| 71 | return NULL; | ||
| 72 | |||
| 73 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
| 74 | adr = (unsigned long) mem; | ||
| 75 | while (size > 0) { | ||
| 76 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
| 77 | adr += PAGE_SIZE; | ||
| 78 | size -= PAGE_SIZE; | ||
| 79 | } | ||
| 80 | |||
| 81 | return mem; | ||
| 82 | } | ||
| 83 | |||
| 84 | static void usbvideo_rvfree(void *mem, unsigned long size) | ||
| 85 | { | ||
| 86 | unsigned long adr; | ||
| 87 | |||
| 88 | if (!mem) | ||
| 89 | return; | ||
| 90 | |||
| 91 | adr = (unsigned long) mem; | ||
| 92 | while ((long) size > 0) { | ||
| 93 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
| 94 | adr += PAGE_SIZE; | ||
| 95 | size -= PAGE_SIZE; | ||
| 96 | } | ||
| 97 | vfree(mem); | ||
| 98 | } | ||
| 99 | |||
| 100 | static void RingQueue_Initialize(struct RingQueue *rq) | ||
| 101 | { | ||
| 102 | assert(rq != NULL); | ||
| 103 | init_waitqueue_head(&rq->wqh); | ||
| 104 | } | ||
| 105 | |||
| 106 | static void RingQueue_Allocate(struct RingQueue *rq, int rqLen) | ||
| 107 | { | ||
| 108 | /* Make sure the requested size is a power of 2 and | ||
| 109 | round up if necessary. This allows index wrapping | ||
| 110 | using masks rather than modulo */ | ||
| 111 | |||
| 112 | int i = 1; | ||
| 113 | assert(rq != NULL); | ||
| 114 | assert(rqLen > 0); | ||
| 115 | |||
| 116 | while(rqLen >> i) | ||
| 117 | i++; | ||
| 118 | if(rqLen != 1 << (i-1)) | ||
| 119 | rqLen = 1 << i; | ||
| 120 | |||
| 121 | rq->length = rqLen; | ||
| 122 | rq->ri = rq->wi = 0; | ||
| 123 | rq->queue = usbvideo_rvmalloc(rq->length); | ||
| 124 | assert(rq->queue != NULL); | ||
| 125 | } | ||
| 126 | |||
| 127 | static int RingQueue_IsAllocated(const struct RingQueue *rq) | ||
| 128 | { | ||
| 129 | if (rq == NULL) | ||
| 130 | return 0; | ||
| 131 | return (rq->queue != NULL) && (rq->length > 0); | ||
| 132 | } | ||
| 133 | |||
| 134 | static void RingQueue_Free(struct RingQueue *rq) | ||
| 135 | { | ||
| 136 | assert(rq != NULL); | ||
| 137 | if (RingQueue_IsAllocated(rq)) { | ||
| 138 | usbvideo_rvfree(rq->queue, rq->length); | ||
| 139 | rq->queue = NULL; | ||
| 140 | rq->length = 0; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len) | ||
| 145 | { | ||
| 146 | int rql, toread; | ||
| 147 | |||
| 148 | assert(rq != NULL); | ||
| 149 | assert(dst != NULL); | ||
| 150 | |||
| 151 | rql = RingQueue_GetLength(rq); | ||
| 152 | if(!rql) | ||
| 153 | return 0; | ||
| 154 | |||
| 155 | /* Clip requested length to available data */ | ||
| 156 | if(len > rql) | ||
| 157 | len = rql; | ||
| 158 | |||
| 159 | toread = len; | ||
| 160 | if(rq->ri > rq->wi) { | ||
| 161 | /* Read data from tail */ | ||
| 162 | int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri; | ||
| 163 | memcpy(dst, rq->queue + rq->ri, read); | ||
| 164 | toread -= read; | ||
| 165 | dst += read; | ||
| 166 | rq->ri = (rq->ri + read) & (rq->length-1); | ||
| 167 | } | ||
| 168 | if(toread) { | ||
| 169 | /* Read data from head */ | ||
| 170 | memcpy(dst, rq->queue + rq->ri, toread); | ||
| 171 | rq->ri = (rq->ri + toread) & (rq->length-1); | ||
| 172 | } | ||
| 173 | return len; | ||
| 174 | } | ||
| 175 | |||
| 176 | EXPORT_SYMBOL(RingQueue_Dequeue); | ||
| 177 | |||
| 178 | int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n) | ||
| 179 | { | ||
| 180 | int enqueued = 0; | ||
| 181 | |||
| 182 | assert(rq != NULL); | ||
| 183 | assert(cdata != NULL); | ||
| 184 | assert(rq->length > 0); | ||
| 185 | while (n > 0) { | ||
| 186 | int m, q_avail; | ||
| 187 | |||
| 188 | /* Calculate the largest chunk that fits the tail of the ring */ | ||
| 189 | q_avail = rq->length - rq->wi; | ||
| 190 | if (q_avail <= 0) { | ||
| 191 | rq->wi = 0; | ||
| 192 | q_avail = rq->length; | ||
| 193 | } | ||
| 194 | m = n; | ||
| 195 | assert(q_avail > 0); | ||
| 196 | if (m > q_avail) | ||
| 197 | m = q_avail; | ||
| 198 | |||
| 199 | memcpy(rq->queue + rq->wi, cdata, m); | ||
| 200 | RING_QUEUE_ADVANCE_INDEX(rq, wi, m); | ||
| 201 | cdata += m; | ||
| 202 | enqueued += m; | ||
| 203 | n -= m; | ||
| 204 | } | ||
| 205 | return enqueued; | ||
| 206 | } | ||
| 207 | |||
| 208 | EXPORT_SYMBOL(RingQueue_Enqueue); | ||
| 209 | |||
| 210 | static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq) | ||
| 211 | { | ||
| 212 | assert(rq != NULL); | ||
| 213 | interruptible_sleep_on(&rq->wqh); | ||
| 214 | } | ||
| 215 | |||
| 216 | void RingQueue_WakeUpInterruptible(struct RingQueue *rq) | ||
| 217 | { | ||
| 218 | assert(rq != NULL); | ||
| 219 | if (waitqueue_active(&rq->wqh)) | ||
| 220 | wake_up_interruptible(&rq->wqh); | ||
| 221 | } | ||
| 222 | |||
| 223 | EXPORT_SYMBOL(RingQueue_WakeUpInterruptible); | ||
| 224 | |||
| 225 | void RingQueue_Flush(struct RingQueue *rq) | ||
| 226 | { | ||
| 227 | assert(rq != NULL); | ||
| 228 | rq->ri = 0; | ||
| 229 | rq->wi = 0; | ||
| 230 | } | ||
| 231 | |||
| 232 | EXPORT_SYMBOL(RingQueue_Flush); | ||
| 233 | |||
| 234 | |||
| 235 | /* | ||
| 236 | * usbvideo_VideosizeToString() | ||
| 237 | * | ||
| 238 | * This procedure converts given videosize value to readable string. | ||
| 239 | * | ||
| 240 | * History: | ||
| 241 | * 07-Aug-2000 Created. | ||
| 242 | * 19-Oct-2000 Reworked for usbvideo module. | ||
| 243 | */ | ||
| 244 | static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs) | ||
| 245 | { | ||
| 246 | char tmp[40]; | ||
| 247 | int n; | ||
| 248 | |||
| 249 | n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs)); | ||
| 250 | assert(n < sizeof(tmp)); | ||
| 251 | if ((buf == NULL) || (bufLen < n)) | ||
| 252 | err("usbvideo_VideosizeToString: buffer is too small."); | ||
| 253 | else | ||
| 254 | memmove(buf, tmp, n); | ||
| 255 | } | ||
| 256 | |||
| 257 | /* | ||
| 258 | * usbvideo_OverlayChar() | ||
| 259 | * | ||
| 260 | * History: | ||
| 261 | * 01-Feb-2000 Created. | ||
| 262 | */ | ||
| 263 | static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame, | ||
| 264 | int x, int y, int ch) | ||
| 265 | { | ||
| 266 | static const unsigned short digits[16] = { | ||
| 267 | 0xF6DE, /* 0 */ | ||
| 268 | 0x2492, /* 1 */ | ||
| 269 | 0xE7CE, /* 2 */ | ||
| 270 | 0xE79E, /* 3 */ | ||
| 271 | 0xB792, /* 4 */ | ||
| 272 | 0xF39E, /* 5 */ | ||
| 273 | 0xF3DE, /* 6 */ | ||
| 274 | 0xF492, /* 7 */ | ||
| 275 | 0xF7DE, /* 8 */ | ||
| 276 | 0xF79E, /* 9 */ | ||
| 277 | 0x77DA, /* a */ | ||
| 278 | 0xD75C, /* b */ | ||
| 279 | 0xF24E, /* c */ | ||
| 280 | 0xD6DC, /* d */ | ||
| 281 | 0xF34E, /* e */ | ||
| 282 | 0xF348 /* f */ | ||
| 283 | }; | ||
| 284 | unsigned short digit; | ||
| 285 | int ix, iy; | ||
| 286 | |||
| 287 | if ((uvd == NULL) || (frame == NULL)) | ||
| 288 | return; | ||
| 289 | |||
| 290 | if (ch >= '0' && ch <= '9') | ||
| 291 | ch -= '0'; | ||
| 292 | else if (ch >= 'A' && ch <= 'F') | ||
| 293 | ch = 10 + (ch - 'A'); | ||
| 294 | else if (ch >= 'a' && ch <= 'f') | ||
| 295 | ch = 10 + (ch - 'a'); | ||
| 296 | else | ||
| 297 | return; | ||
| 298 | digit = digits[ch]; | ||
| 299 | |||
| 300 | for (iy=0; iy < 5; iy++) { | ||
| 301 | for (ix=0; ix < 3; ix++) { | ||
| 302 | if (digit & 0x8000) { | ||
| 303 | if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) { | ||
| 304 | /* TODO */ RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | digit = digit << 1; | ||
| 308 | } | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | /* | ||
| 313 | * usbvideo_OverlayString() | ||
| 314 | * | ||
| 315 | * History: | ||
| 316 | * 01-Feb-2000 Created. | ||
| 317 | */ | ||
| 318 | static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame, | ||
| 319 | int x, int y, const char *str) | ||
| 320 | { | ||
| 321 | while (*str) { | ||
| 322 | usbvideo_OverlayChar(uvd, frame, x, y, *str); | ||
| 323 | str++; | ||
| 324 | x += 4; /* 3 pixels character + 1 space */ | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | /* | ||
| 329 | * usbvideo_OverlayStats() | ||
| 330 | * | ||
| 331 | * Overlays important debugging information. | ||
| 332 | * | ||
| 333 | * History: | ||
| 334 | * 01-Feb-2000 Created. | ||
| 335 | */ | ||
| 336 | static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame) | ||
| 337 | { | ||
| 338 | const int y_diff = 8; | ||
| 339 | char tmp[16]; | ||
| 340 | int x = 10, y=10; | ||
| 341 | long i, j, barLength; | ||
| 342 | const int qi_x1 = 60, qi_y1 = 10; | ||
| 343 | const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10; | ||
| 344 | |||
| 345 | /* Call the user callback, see if we may proceed after that */ | ||
| 346 | if (VALID_CALLBACK(uvd, overlayHook)) { | ||
| 347 | if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0) | ||
| 348 | return; | ||
| 349 | } | ||
| 350 | |||
| 351 | /* | ||
| 352 | * We draw a (mostly) hollow rectangle with qi_xxx coordinates. | ||
| 353 | * Left edge symbolizes the queue index 0; right edge symbolizes | ||
| 354 | * the full capacity of the queue. | ||
| 355 | */ | ||
| 356 | barLength = qi_x2 - qi_x1 - 2; | ||
| 357 | if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) { | ||
| 358 | /* TODO */ long u_lo, u_hi, q_used; | ||
| 359 | long m_ri, m_wi, m_lo, m_hi; | ||
| 360 | |||
| 361 | /* | ||
| 362 | * Determine fill zones (used areas of the queue): | ||
| 363 | * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length | ||
| 364 | * | ||
| 365 | * if u_lo < 0 then there is no first filler. | ||
| 366 | */ | ||
| 367 | |||
| 368 | q_used = RingQueue_GetLength(&uvd->dp); | ||
| 369 | if ((uvd->dp.ri + q_used) >= uvd->dp.length) { | ||
| 370 | u_hi = uvd->dp.length; | ||
| 371 | u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1); | ||
| 372 | } else { | ||
| 373 | u_hi = (q_used + uvd->dp.ri); | ||
| 374 | u_lo = -1; | ||
| 375 | } | ||
| 376 | |||
| 377 | /* Convert byte indices into screen units */ | ||
| 378 | m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length); | ||
| 379 | m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length); | ||
| 380 | m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1; | ||
| 381 | m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length); | ||
| 382 | |||
| 383 | for (j=qi_y1; j < (qi_y1 + qi_h); j++) { | ||
| 384 | for (i=qi_x1; i < qi_x2; i++) { | ||
| 385 | /* Draw border lines */ | ||
| 386 | if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) || | ||
| 387 | (i == qi_x1) || (i == (qi_x2 - 1))) { | ||
| 388 | RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF); | ||
| 389 | continue; | ||
| 390 | } | ||
| 391 | /* For all other points the Y coordinate does not matter */ | ||
| 392 | if ((i >= m_ri) && (i <= (m_ri + 3))) { | ||
| 393 | RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00); | ||
| 394 | } else if ((i >= m_wi) && (i <= (m_wi + 3))) { | ||
| 395 | RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00); | ||
| 396 | } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi))) | ||
| 397 | RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | sprintf(tmp, "%8lx", uvd->stats.frame_num); | ||
| 403 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 404 | y += y_diff; | ||
| 405 | |||
| 406 | sprintf(tmp, "%8lx", uvd->stats.urb_count); | ||
| 407 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 408 | y += y_diff; | ||
| 409 | |||
| 410 | sprintf(tmp, "%8lx", uvd->stats.urb_length); | ||
| 411 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 412 | y += y_diff; | ||
| 413 | |||
| 414 | sprintf(tmp, "%8lx", uvd->stats.data_count); | ||
| 415 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 416 | y += y_diff; | ||
| 417 | |||
| 418 | sprintf(tmp, "%8lx", uvd->stats.header_count); | ||
| 419 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 420 | y += y_diff; | ||
| 421 | |||
| 422 | sprintf(tmp, "%8lx", uvd->stats.iso_skip_count); | ||
| 423 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 424 | y += y_diff; | ||
| 425 | |||
| 426 | sprintf(tmp, "%8lx", uvd->stats.iso_err_count); | ||
| 427 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 428 | y += y_diff; | ||
| 429 | |||
| 430 | sprintf(tmp, "%8x", uvd->vpic.colour); | ||
| 431 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 432 | y += y_diff; | ||
| 433 | |||
| 434 | sprintf(tmp, "%8x", uvd->vpic.hue); | ||
| 435 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 436 | y += y_diff; | ||
| 437 | |||
| 438 | sprintf(tmp, "%8x", uvd->vpic.brightness >> 8); | ||
| 439 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 440 | y += y_diff; | ||
| 441 | |||
| 442 | sprintf(tmp, "%8x", uvd->vpic.contrast >> 12); | ||
| 443 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 444 | y += y_diff; | ||
| 445 | |||
| 446 | sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8); | ||
| 447 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
| 448 | y += y_diff; | ||
| 449 | } | ||
| 450 | |||
| 451 | /* | ||
| 452 | * usbvideo_ReportStatistics() | ||
| 453 | * | ||
| 454 | * This procedure prints packet and transfer statistics. | ||
| 455 | * | ||
| 456 | * History: | ||
| 457 | * 14-Jan-2000 Corrected default multiplier. | ||
| 458 | */ | ||
| 459 | static void usbvideo_ReportStatistics(const struct uvd *uvd) | ||
| 460 | { | ||
| 461 | if ((uvd != NULL) && (uvd->stats.urb_count > 0)) { | ||
| 462 | unsigned long allPackets, badPackets, goodPackets, percent; | ||
| 463 | allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES; | ||
| 464 | badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count; | ||
| 465 | goodPackets = allPackets - badPackets; | ||
| 466 | /* Calculate percentage wisely, remember integer limits */ | ||
| 467 | assert(allPackets != 0); | ||
| 468 | if (goodPackets < (((unsigned long)-1)/100)) | ||
| 469 | percent = (100 * goodPackets) / allPackets; | ||
| 470 | else | ||
| 471 | percent = goodPackets / (allPackets / 100); | ||
| 472 | info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%", | ||
| 473 | allPackets, badPackets, percent); | ||
| 474 | if (uvd->iso_packet_len > 0) { | ||
| 475 | unsigned long allBytes, xferBytes; | ||
| 476 | char multiplier = ' '; | ||
| 477 | allBytes = allPackets * uvd->iso_packet_len; | ||
| 478 | xferBytes = uvd->stats.data_count; | ||
| 479 | assert(allBytes != 0); | ||
| 480 | if (xferBytes < (((unsigned long)-1)/100)) | ||
| 481 | percent = (100 * xferBytes) / allBytes; | ||
| 482 | else | ||
| 483 | percent = xferBytes / (allBytes / 100); | ||
| 484 | /* Scale xferBytes for easy reading */ | ||
| 485 | if (xferBytes > 10*1024) { | ||
| 486 | xferBytes /= 1024; | ||
| 487 | multiplier = 'K'; | ||
| 488 | if (xferBytes > 10*1024) { | ||
| 489 | xferBytes /= 1024; | ||
| 490 | multiplier = 'M'; | ||
| 491 | if (xferBytes > 10*1024) { | ||
| 492 | xferBytes /= 1024; | ||
| 493 | multiplier = 'G'; | ||
| 494 | if (xferBytes > 10*1024) { | ||
| 495 | xferBytes /= 1024; | ||
| 496 | multiplier = 'T'; | ||
| 497 | } | ||
| 498 | } | ||
| 499 | } | ||
| 500 | } | ||
| 501 | info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%", | ||
| 502 | xferBytes, multiplier, percent); | ||
| 503 | } | ||
| 504 | } | ||
| 505 | } | ||
| 506 | |||
| 507 | /* | ||
| 508 | * usbvideo_TestPattern() | ||
| 509 | * | ||
| 510 | * Procedure forms a test pattern (yellow grid on blue background). | ||
| 511 | * | ||
| 512 | * Parameters: | ||
| 513 | * fullframe: if TRUE then entire frame is filled, otherwise the procedure | ||
| 514 | * continues from the current scanline. | ||
| 515 | * pmode 0: fill the frame with solid blue color (like on VCR or TV) | ||
| 516 | * 1: Draw a colored grid | ||
| 517 | * | ||
| 518 | * History: | ||
| 519 | * 01-Feb-2000 Created. | ||
| 520 | */ | ||
| 521 | void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode) | ||
| 522 | { | ||
| 523 | struct usbvideo_frame *frame; | ||
| 524 | int num_cell = 0; | ||
| 525 | int scan_length = 0; | ||
| 526 | static int num_pass = 0; | ||
| 527 | |||
| 528 | if (uvd == NULL) { | ||
| 529 | err("%s: uvd == NULL", __FUNCTION__); | ||
| 530 | return; | ||
| 531 | } | ||
| 532 | if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { | ||
| 533 | err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe); | ||
| 534 | return; | ||
| 535 | } | ||
| 536 | |||
| 537 | /* Grab the current frame */ | ||
| 538 | frame = &uvd->frame[uvd->curframe]; | ||
| 539 | |||
| 540 | /* Optionally start at the beginning */ | ||
| 541 | if (fullframe) { | ||
| 542 | frame->curline = 0; | ||
| 543 | frame->seqRead_Length = 0; | ||
| 544 | } | ||
| 545 | #if 0 | ||
| 546 | { /* For debugging purposes only */ | ||
| 547 | char tmp[20]; | ||
| 548 | usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request); | ||
| 549 | info("testpattern: frame=%s", tmp); | ||
| 550 | } | ||
| 551 | #endif | ||
| 552 | /* Form every scan line */ | ||
| 553 | for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) { | ||
| 554 | int i; | ||
| 555 | unsigned char *f = frame->data + | ||
| 556 | (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline); | ||
| 557 | for (i=0; i < VIDEOSIZE_X(frame->request); i++) { | ||
| 558 | unsigned char cb=0x80; | ||
| 559 | unsigned char cg = 0; | ||
| 560 | unsigned char cr = 0; | ||
| 561 | |||
| 562 | if (pmode == 1) { | ||
| 563 | if (frame->curline % 32 == 0) | ||
| 564 | cb = 0, cg = cr = 0xFF; | ||
| 565 | else if (i % 32 == 0) { | ||
| 566 | if (frame->curline % 32 == 1) | ||
| 567 | num_cell++; | ||
| 568 | cb = 0, cg = cr = 0xFF; | ||
| 569 | } else { | ||
| 570 | cb = ((num_cell*7) + num_pass) & 0xFF; | ||
| 571 | cg = ((num_cell*5) + num_pass*2) & 0xFF; | ||
| 572 | cr = ((num_cell*3) + num_pass*3) & 0xFF; | ||
| 573 | } | ||
| 574 | } else { | ||
| 575 | /* Just the blue screen */ | ||
| 576 | } | ||
| 577 | |||
| 578 | *f++ = cb; | ||
| 579 | *f++ = cg; | ||
| 580 | *f++ = cr; | ||
| 581 | scan_length += 3; | ||
| 582 | } | ||
| 583 | } | ||
| 584 | |||
| 585 | frame->frameState = FrameState_Done; | ||
| 586 | frame->seqRead_Length += scan_length; | ||
| 587 | ++num_pass; | ||
| 588 | |||
| 589 | /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */ | ||
| 590 | usbvideo_OverlayStats(uvd, frame); | ||
| 591 | } | ||
| 592 | |||
| 593 | EXPORT_SYMBOL(usbvideo_TestPattern); | ||
| 594 | |||
| 595 | |||
| 596 | #ifdef DEBUG | ||
| 597 | /* | ||
| 598 | * usbvideo_HexDump() | ||
| 599 | * | ||
| 600 | * A debugging tool. Prints hex dumps. | ||
| 601 | * | ||
| 602 | * History: | ||
| 603 | * 29-Jul-2000 Added printing of offsets. | ||
| 604 | */ | ||
| 605 | void usbvideo_HexDump(const unsigned char *data, int len) | ||
| 606 | { | ||
| 607 | const int bytes_per_line = 32; | ||
| 608 | char tmp[128]; /* 32*3 + 5 */ | ||
| 609 | int i, k; | ||
| 610 | |||
| 611 | for (i=k=0; len > 0; i++, len--) { | ||
| 612 | if (i > 0 && ((i % bytes_per_line) == 0)) { | ||
| 613 | printk("%s\n", tmp); | ||
| 614 | k=0; | ||
| 615 | } | ||
| 616 | if ((i % bytes_per_line) == 0) | ||
| 617 | k += sprintf(&tmp[k], "%04x: ", i); | ||
| 618 | k += sprintf(&tmp[k], "%02x ", data[i]); | ||
| 619 | } | ||
| 620 | if (k > 0) | ||
| 621 | printk("%s\n", tmp); | ||
| 622 | } | ||
| 623 | |||
| 624 | EXPORT_SYMBOL(usbvideo_HexDump); | ||
| 625 | |||
| 626 | #endif | ||
| 627 | |||
| 628 | /* ******************************************************************** */ | ||
| 629 | |||
| 630 | /* XXX: this piece of crap really wants some error handling.. */ | ||
| 631 | static void usbvideo_ClientIncModCount(struct uvd *uvd) | ||
| 632 | { | ||
| 633 | if (uvd == NULL) { | ||
| 634 | err("%s: uvd == NULL", __FUNCTION__); | ||
| 635 | return; | ||
| 636 | } | ||
| 637 | if (uvd->handle == NULL) { | ||
| 638 | err("%s: uvd->handle == NULL", __FUNCTION__); | ||
| 639 | return; | ||
| 640 | } | ||
| 641 | if (uvd->handle->md_module == NULL) { | ||
| 642 | err("%s: uvd->handle->md_module == NULL", __FUNCTION__); | ||
| 643 | return; | ||
| 644 | } | ||
| 645 | if (!try_module_get(uvd->handle->md_module)) { | ||
| 646 | err("%s: try_module_get() == 0", __FUNCTION__); | ||
| 647 | return; | ||
| 648 | } | ||
| 649 | } | ||
| 650 | |||
| 651 | static void usbvideo_ClientDecModCount(struct uvd *uvd) | ||
| 652 | { | ||
| 653 | if (uvd == NULL) { | ||
| 654 | err("%s: uvd == NULL", __FUNCTION__); | ||
| 655 | return; | ||
| 656 | } | ||
| 657 | if (uvd->handle == NULL) { | ||
| 658 | err("%s: uvd->handle == NULL", __FUNCTION__); | ||
| 659 | return; | ||
| 660 | } | ||
| 661 | if (uvd->handle->md_module == NULL) { | ||
| 662 | err("%s: uvd->handle->md_module == NULL", __FUNCTION__); | ||
| 663 | return; | ||
| 664 | } | ||
| 665 | module_put(uvd->handle->md_module); | ||
| 666 | } | ||
| 667 | |||
| 668 | int usbvideo_register( | ||
| 669 | struct usbvideo **pCams, | ||
| 670 | const int num_cams, | ||
| 671 | const int num_extra, | ||
| 672 | const char *driverName, | ||
| 673 | const struct usbvideo_cb *cbTbl, | ||
| 674 | struct module *md, | ||
| 675 | const struct usb_device_id *id_table) | ||
| 676 | { | ||
| 677 | struct usbvideo *cams; | ||
| 678 | int i, base_size, result; | ||
| 679 | |||
| 680 | /* Check parameters for sanity */ | ||
| 681 | if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) { | ||
| 682 | err("%s: Illegal call", __FUNCTION__); | ||
| 683 | return -EINVAL; | ||
| 684 | } | ||
| 685 | |||
| 686 | /* Check registration callback - must be set! */ | ||
| 687 | if (cbTbl->probe == NULL) { | ||
| 688 | err("%s: probe() is required!", __FUNCTION__); | ||
| 689 | return -EINVAL; | ||
| 690 | } | ||
| 691 | |||
| 692 | base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo); | ||
| 693 | cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL); | ||
| 694 | if (cams == NULL) { | ||
| 695 | err("Failed to allocate %d. bytes for usbvideo struct", base_size); | ||
| 696 | return -ENOMEM; | ||
| 697 | } | ||
| 698 | dbg("%s: Allocated $%p (%d. bytes) for %d. cameras", | ||
| 699 | __FUNCTION__, cams, base_size, num_cams); | ||
| 700 | |||
| 701 | /* Copy callbacks, apply defaults for those that are not set */ | ||
| 702 | memmove(&cams->cb, cbTbl, sizeof(cams->cb)); | ||
| 703 | if (cams->cb.getFrame == NULL) | ||
| 704 | cams->cb.getFrame = usbvideo_GetFrame; | ||
| 705 | if (cams->cb.disconnect == NULL) | ||
| 706 | cams->cb.disconnect = usbvideo_Disconnect; | ||
| 707 | if (cams->cb.startDataPump == NULL) | ||
| 708 | cams->cb.startDataPump = usbvideo_StartDataPump; | ||
| 709 | if (cams->cb.stopDataPump == NULL) | ||
| 710 | cams->cb.stopDataPump = usbvideo_StopDataPump; | ||
| 711 | |||
| 712 | cams->num_cameras = num_cams; | ||
| 713 | cams->cam = (struct uvd *) &cams[1]; | ||
| 714 | cams->md_module = md; | ||
| 715 | if (cams->md_module == NULL) | ||
| 716 | warn("%s: module == NULL!", __FUNCTION__); | ||
| 717 | mutex_init(&cams->lock); /* to 1 == available */ | ||
| 718 | |||
| 719 | for (i = 0; i < num_cams; i++) { | ||
| 720 | struct uvd *up = &cams->cam[i]; | ||
| 721 | |||
| 722 | up->handle = cams; | ||
| 723 | |||
| 724 | /* Allocate user_data separately because of kmalloc's limits */ | ||
| 725 | if (num_extra > 0) { | ||
| 726 | up->user_size = num_cams * num_extra; | ||
| 727 | up->user_data = kmalloc(up->user_size, GFP_KERNEL); | ||
| 728 | if (up->user_data == NULL) { | ||
| 729 | err("%s: Failed to allocate user_data (%d. bytes)", | ||
| 730 | __FUNCTION__, up->user_size); | ||
| 731 | while (i) { | ||
| 732 | up = &cams->cam[--i]; | ||
| 733 | kfree(up->user_data); | ||
| 734 | } | ||
| 735 | kfree(cams); | ||
| 736 | return -ENOMEM; | ||
| 737 | } | ||
| 738 | dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)", | ||
| 739 | __FUNCTION__, i, up->user_data, up->user_size); | ||
| 740 | } | ||
| 741 | } | ||
| 742 | |||
| 743 | /* | ||
| 744 | * Register ourselves with USB stack. | ||
| 745 | */ | ||
| 746 | strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown"); | ||
| 747 | cams->usbdrv.name = cams->drvName; | ||
| 748 | cams->usbdrv.probe = cams->cb.probe; | ||
| 749 | cams->usbdrv.disconnect = cams->cb.disconnect; | ||
| 750 | cams->usbdrv.id_table = id_table; | ||
| 751 | |||
| 752 | /* | ||
| 753 | * Update global handle to usbvideo. This is very important | ||
| 754 | * because probe() can be called before usb_register() returns. | ||
| 755 | * If the handle is not yet updated then the probe() will fail. | ||
| 756 | */ | ||
| 757 | *pCams = cams; | ||
| 758 | result = usb_register(&cams->usbdrv); | ||
| 759 | if (result) { | ||
| 760 | for (i = 0; i < num_cams; i++) { | ||
| 761 | struct uvd *up = &cams->cam[i]; | ||
| 762 | kfree(up->user_data); | ||
| 763 | } | ||
| 764 | kfree(cams); | ||
| 765 | } | ||
| 766 | |||
| 767 | return result; | ||
| 768 | } | ||
| 769 | |||
| 770 | EXPORT_SYMBOL(usbvideo_register); | ||
| 771 | |||
| 772 | /* | ||
| 773 | * usbvideo_Deregister() | ||
| 774 | * | ||
| 775 | * Procedure frees all usbvideo and user data structures. Be warned that | ||
| 776 | * if you had some dynamically allocated components in ->user field then | ||
| 777 | * you should free them before calling here. | ||
| 778 | */ | ||
| 779 | void usbvideo_Deregister(struct usbvideo **pCams) | ||
| 780 | { | ||
| 781 | struct usbvideo *cams; | ||
| 782 | int i; | ||
| 783 | |||
| 784 | if (pCams == NULL) { | ||
| 785 | err("%s: pCams == NULL", __FUNCTION__); | ||
| 786 | return; | ||
| 787 | } | ||
| 788 | cams = *pCams; | ||
| 789 | if (cams == NULL) { | ||
| 790 | err("%s: cams == NULL", __FUNCTION__); | ||
| 791 | return; | ||
| 792 | } | ||
| 793 | |||
| 794 | dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName); | ||
| 795 | usb_deregister(&cams->usbdrv); | ||
| 796 | |||
| 797 | dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras); | ||
| 798 | for (i=0; i < cams->num_cameras; i++) { | ||
| 799 | struct uvd *up = &cams->cam[i]; | ||
| 800 | int warning = 0; | ||
| 801 | |||
| 802 | if (up->user_data != NULL) { | ||
| 803 | if (up->user_size <= 0) | ||
| 804 | ++warning; | ||
| 805 | } else { | ||
| 806 | if (up->user_size > 0) | ||
| 807 | ++warning; | ||
| 808 | } | ||
| 809 | if (warning) { | ||
| 810 | err("%s: Warning: user_data=$%p user_size=%d.", | ||
| 811 | __FUNCTION__, up->user_data, up->user_size); | ||
| 812 | } else { | ||
| 813 | dbg("%s: Freeing %d. $%p->user_data=$%p", | ||
| 814 | __FUNCTION__, i, up, up->user_data); | ||
| 815 | kfree(up->user_data); | ||
| 816 | } | ||
| 817 | } | ||
| 818 | /* Whole array was allocated in one chunk */ | ||
| 819 | dbg("%s: Freed %d uvd structures", | ||
| 820 | __FUNCTION__, cams->num_cameras); | ||
| 821 | kfree(cams); | ||
| 822 | *pCams = NULL; | ||
| 823 | } | ||
| 824 | |||
| 825 | EXPORT_SYMBOL(usbvideo_Deregister); | ||
| 826 | |||
| 827 | /* | ||
| 828 | * usbvideo_Disconnect() | ||
| 829 | * | ||
| 830 | * This procedure stops all driver activity. Deallocation of | ||
| 831 | * the interface-private structure (pointed by 'ptr') is done now | ||
| 832 | * (if we don't have any open files) or later, when those files | ||
| 833 | * are closed. After that driver should be removable. | ||
| 834 | * | ||
| 835 | * This code handles surprise removal. The uvd->user is a counter which | ||
| 836 | * increments on open() and decrements on close(). If we see here that | ||
| 837 | * this counter is not 0 then we have a client who still has us opened. | ||
| 838 | * We set uvd->remove_pending flag as early as possible, and after that | ||
| 839 | * all access to the camera will gracefully fail. These failures should | ||
| 840 | * prompt client to (eventually) close the video device, and then - in | ||
| 841 | * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter. | ||
| 842 | * | ||
| 843 | * History: | ||
| 844 | * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone. | ||
| 845 | * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close() | ||
| 846 | * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). | ||
| 847 | * 19-Oct-2000 Moved to usbvideo module. | ||
| 848 | */ | ||
| 849 | static void usbvideo_Disconnect(struct usb_interface *intf) | ||
| 850 | { | ||
| 851 | struct uvd *uvd = usb_get_intfdata (intf); | ||
| 852 | int i; | ||
| 853 | |||
| 854 | if (uvd == NULL) { | ||
| 855 | err("%s($%p): Illegal call.", __FUNCTION__, intf); | ||
| 856 | return; | ||
| 857 | } | ||
| 858 | |||
| 859 | usb_set_intfdata (intf, NULL); | ||
| 860 | |||
| 861 | usbvideo_ClientIncModCount(uvd); | ||
| 862 | if (uvd->debug > 0) | ||
| 863 | info("%s(%p.)", __FUNCTION__, intf); | ||
| 864 | |||
| 865 | mutex_lock(&uvd->lock); | ||
| 866 | uvd->remove_pending = 1; /* Now all ISO data will be ignored */ | ||
| 867 | |||
| 868 | /* At this time we ask to cancel outstanding URBs */ | ||
| 869 | GET_CALLBACK(uvd, stopDataPump)(uvd); | ||
| 870 | |||
| 871 | for (i=0; i < USBVIDEO_NUMSBUF; i++) | ||
| 872 | usb_free_urb(uvd->sbuf[i].urb); | ||
| 873 | |||
| 874 | usb_put_dev(uvd->dev); | ||
| 875 | uvd->dev = NULL; /* USB device is no more */ | ||
| 876 | |||
| 877 | video_unregister_device(&uvd->vdev); | ||
| 878 | if (uvd->debug > 0) | ||
| 879 | info("%s: Video unregistered.", __FUNCTION__); | ||
| 880 | |||
| 881 | if (uvd->user) | ||
| 882 | info("%s: In use, disconnect pending.", __FUNCTION__); | ||
| 883 | else | ||
| 884 | usbvideo_CameraRelease(uvd); | ||
| 885 | mutex_unlock(&uvd->lock); | ||
| 886 | info("USB camera disconnected."); | ||
| 887 | |||
| 888 | usbvideo_ClientDecModCount(uvd); | ||
| 889 | } | ||
| 890 | |||
| 891 | /* | ||
| 892 | * usbvideo_CameraRelease() | ||
| 893 | * | ||
| 894 | * This code does final release of uvd. This happens | ||
| 895 | * after the device is disconnected -and- all clients | ||
| 896 | * closed their files. | ||
| 897 | * | ||
| 898 | * History: | ||
| 899 | * 27-Jan-2000 Created. | ||
| 900 | */ | ||
| 901 | static void usbvideo_CameraRelease(struct uvd *uvd) | ||
| 902 | { | ||
| 903 | if (uvd == NULL) { | ||
| 904 | err("%s: Illegal call", __FUNCTION__); | ||
| 905 | return; | ||
| 906 | } | ||
| 907 | |||
| 908 | RingQueue_Free(&uvd->dp); | ||
| 909 | if (VALID_CALLBACK(uvd, userFree)) | ||
| 910 | GET_CALLBACK(uvd, userFree)(uvd); | ||
| 911 | uvd->uvd_used = 0; /* This is atomic, no need to take mutex */ | ||
| 912 | } | ||
| 913 | |||
| 914 | /* | ||
| 915 | * usbvideo_find_struct() | ||
| 916 | * | ||
| 917 | * This code searches the array of preallocated (static) structures | ||
| 918 | * and returns index of the first one that isn't in use. Returns -1 | ||
| 919 | * if there are no free structures. | ||
| 920 | * | ||
| 921 | * History: | ||
| 922 | * 27-Jan-2000 Created. | ||
| 923 | */ | ||
| 924 | static int usbvideo_find_struct(struct usbvideo *cams) | ||
| 925 | { | ||
| 926 | int u, rv = -1; | ||
| 927 | |||
| 928 | if (cams == NULL) { | ||
| 929 | err("No usbvideo handle?"); | ||
| 930 | return -1; | ||
| 931 | } | ||
| 932 | mutex_lock(&cams->lock); | ||
| 933 | for (u = 0; u < cams->num_cameras; u++) { | ||
| 934 | struct uvd *uvd = &cams->cam[u]; | ||
| 935 | if (!uvd->uvd_used) /* This one is free */ | ||
| 936 | { | ||
| 937 | uvd->uvd_used = 1; /* In use now */ | ||
| 938 | mutex_init(&uvd->lock); /* to 1 == available */ | ||
| 939 | uvd->dev = NULL; | ||
| 940 | rv = u; | ||
| 941 | break; | ||
| 942 | } | ||
| 943 | } | ||
| 944 | mutex_unlock(&cams->lock); | ||
| 945 | return rv; | ||
| 946 | } | ||
| 947 | |||
| 948 | static struct file_operations usbvideo_fops = { | ||
| 949 | .owner = THIS_MODULE, | ||
| 950 | .open = usbvideo_v4l_open, | ||
| 951 | .release =usbvideo_v4l_close, | ||
| 952 | .read = usbvideo_v4l_read, | ||
| 953 | .mmap = usbvideo_v4l_mmap, | ||
| 954 | .ioctl = usbvideo_v4l_ioctl, | ||
| 955 | .compat_ioctl = v4l_compat_ioctl32, | ||
| 956 | .llseek = no_llseek, | ||
| 957 | }; | ||
| 958 | static const struct video_device usbvideo_template = { | ||
| 959 | .owner = THIS_MODULE, | ||
| 960 | .type = VID_TYPE_CAPTURE, | ||
| 961 | .hardware = VID_HARDWARE_CPIA, | ||
| 962 | .fops = &usbvideo_fops, | ||
| 963 | }; | ||
| 964 | |||
| 965 | struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams) | ||
| 966 | { | ||
| 967 | int i, devnum; | ||
| 968 | struct uvd *uvd = NULL; | ||
| 969 | |||
| 970 | if (cams == NULL) { | ||
| 971 | err("No usbvideo handle?"); | ||
| 972 | return NULL; | ||
| 973 | } | ||
| 974 | |||
| 975 | devnum = usbvideo_find_struct(cams); | ||
| 976 | if (devnum == -1) { | ||
| 977 | err("IBM USB camera driver: Too many devices!"); | ||
| 978 | return NULL; | ||
| 979 | } | ||
| 980 | uvd = &cams->cam[devnum]; | ||
| 981 | dbg("Device entry #%d. at $%p", devnum, uvd); | ||
| 982 | |||
| 983 | /* Not relying upon caller we increase module counter ourselves */ | ||
| 984 | usbvideo_ClientIncModCount(uvd); | ||
| 985 | |||
| 986 | mutex_lock(&uvd->lock); | ||
| 987 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 988 | uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); | ||
| 989 | if (uvd->sbuf[i].urb == NULL) { | ||
| 990 | err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC); | ||
| 991 | uvd->uvd_used = 0; | ||
| 992 | uvd = NULL; | ||
| 993 | goto allocate_done; | ||
| 994 | } | ||
| 995 | } | ||
| 996 | uvd->user=0; | ||
| 997 | uvd->remove_pending = 0; | ||
| 998 | uvd->last_error = 0; | ||
| 999 | RingQueue_Initialize(&uvd->dp); | ||
| 1000 | |||
| 1001 | /* Initialize video device structure */ | ||
| 1002 | uvd->vdev = usbvideo_template; | ||
| 1003 | sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName); | ||
| 1004 | /* | ||
| 1005 | * The client is free to overwrite those because we | ||
| 1006 | * return control to the client's probe function right now. | ||
| 1007 | */ | ||
| 1008 | allocate_done: | ||
| 1009 | mutex_unlock(&uvd->lock); | ||
| 1010 | usbvideo_ClientDecModCount(uvd); | ||
| 1011 | return uvd; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | EXPORT_SYMBOL(usbvideo_AllocateDevice); | ||
| 1015 | |||
| 1016 | int usbvideo_RegisterVideoDevice(struct uvd *uvd) | ||
| 1017 | { | ||
| 1018 | char tmp1[20], tmp2[20]; /* Buffers for printing */ | ||
| 1019 | |||
| 1020 | if (uvd == NULL) { | ||
| 1021 | err("%s: Illegal call.", __FUNCTION__); | ||
| 1022 | return -EINVAL; | ||
| 1023 | } | ||
| 1024 | if (uvd->video_endp == 0) { | ||
| 1025 | info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__); | ||
| 1026 | } | ||
| 1027 | if (uvd->paletteBits == 0) { | ||
| 1028 | err("%s: No palettes specified!", __FUNCTION__); | ||
| 1029 | return -EINVAL; | ||
| 1030 | } | ||
| 1031 | if (uvd->defaultPalette == 0) { | ||
| 1032 | info("%s: No default palette!", __FUNCTION__); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) * | ||
| 1036 | VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL; | ||
| 1037 | usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize); | ||
| 1038 | usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas); | ||
| 1039 | |||
| 1040 | if (uvd->debug > 0) { | ||
| 1041 | info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx", | ||
| 1042 | __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits); | ||
| 1043 | } | ||
| 1044 | if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { | ||
| 1045 | err("%s: video_register_device failed", __FUNCTION__); | ||
| 1046 | return -EPIPE; | ||
| 1047 | } | ||
| 1048 | if (uvd->debug > 1) { | ||
| 1049 | info("%s: video_register_device() successful", __FUNCTION__); | ||
| 1050 | } | ||
| 1051 | if (uvd->dev == NULL) { | ||
| 1052 | err("%s: uvd->dev == NULL", __FUNCTION__); | ||
| 1053 | return -EINVAL; | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | info("%s on /dev/video%d: canvas=%s videosize=%s", | ||
| 1057 | (uvd->handle != NULL) ? uvd->handle->drvName : "???", | ||
| 1058 | uvd->vdev.minor, tmp2, tmp1); | ||
| 1059 | |||
| 1060 | usb_get_dev(uvd->dev); | ||
| 1061 | return 0; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | EXPORT_SYMBOL(usbvideo_RegisterVideoDevice); | ||
| 1065 | |||
| 1066 | /* ******************************************************************** */ | ||
| 1067 | |||
| 1068 | static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 1069 | { | ||
| 1070 | struct uvd *uvd = file->private_data; | ||
| 1071 | unsigned long start = vma->vm_start; | ||
| 1072 | unsigned long size = vma->vm_end-vma->vm_start; | ||
| 1073 | unsigned long page, pos; | ||
| 1074 | |||
| 1075 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
| 1076 | return -EFAULT; | ||
| 1077 | |||
| 1078 | if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) | ||
| 1079 | return -EINVAL; | ||
| 1080 | |||
| 1081 | pos = (unsigned long) uvd->fbuf; | ||
| 1082 | while (size > 0) { | ||
| 1083 | page = vmalloc_to_pfn((void *)pos); | ||
| 1084 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) | ||
| 1085 | return -EAGAIN; | ||
| 1086 | |||
| 1087 | start += PAGE_SIZE; | ||
| 1088 | pos += PAGE_SIZE; | ||
| 1089 | if (size > PAGE_SIZE) | ||
| 1090 | size -= PAGE_SIZE; | ||
| 1091 | else | ||
| 1092 | size = 0; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | return 0; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | /* | ||
| 1099 | * usbvideo_v4l_open() | ||
| 1100 | * | ||
| 1101 | * This is part of Video 4 Linux API. The driver can be opened by one | ||
| 1102 | * client only (checks internal counter 'uvdser'). The procedure | ||
| 1103 | * then allocates buffers needed for video processing. | ||
| 1104 | * | ||
| 1105 | * History: | ||
| 1106 | * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the | ||
| 1107 | * camera is also initialized here (once per connect), at | ||
| 1108 | * expense of V4L client (it waits on open() call). | ||
| 1109 | * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. | ||
| 1110 | * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). | ||
| 1111 | */ | ||
| 1112 | static int usbvideo_v4l_open(struct inode *inode, struct file *file) | ||
| 1113 | { | ||
| 1114 | struct video_device *dev = video_devdata(file); | ||
| 1115 | struct uvd *uvd = (struct uvd *) dev; | ||
| 1116 | const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len; | ||
| 1117 | int i, errCode = 0; | ||
| 1118 | |||
| 1119 | if (uvd->debug > 1) | ||
| 1120 | info("%s($%p)", __FUNCTION__, dev); | ||
| 1121 | |||
| 1122 | usbvideo_ClientIncModCount(uvd); | ||
| 1123 | mutex_lock(&uvd->lock); | ||
| 1124 | |||
| 1125 | if (uvd->user) { | ||
| 1126 | err("%s: Someone tried to open an already opened device!", __FUNCTION__); | ||
| 1127 | errCode = -EBUSY; | ||
| 1128 | } else { | ||
| 1129 | /* Clear statistics */ | ||
| 1130 | memset(&uvd->stats, 0, sizeof(uvd->stats)); | ||
| 1131 | |||
| 1132 | /* Clean pointers so we know if we allocated something */ | ||
| 1133 | for (i=0; i < USBVIDEO_NUMSBUF; i++) | ||
| 1134 | uvd->sbuf[i].data = NULL; | ||
| 1135 | |||
| 1136 | /* Allocate memory for the frame buffers */ | ||
| 1137 | uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size; | ||
| 1138 | uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size); | ||
| 1139 | RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE); | ||
| 1140 | if ((uvd->fbuf == NULL) || | ||
| 1141 | (!RingQueue_IsAllocated(&uvd->dp))) { | ||
| 1142 | err("%s: Failed to allocate fbuf or dp", __FUNCTION__); | ||
| 1143 | errCode = -ENOMEM; | ||
| 1144 | } else { | ||
| 1145 | /* Allocate all buffers */ | ||
| 1146 | for (i=0; i < USBVIDEO_NUMFRAMES; i++) { | ||
| 1147 | uvd->frame[i].frameState = FrameState_Unused; | ||
| 1148 | uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size); | ||
| 1149 | /* | ||
| 1150 | * Set default sizes in case IOCTL (VIDIOCMCAPTURE) | ||
| 1151 | * is not used (using read() instead). | ||
| 1152 | */ | ||
| 1153 | uvd->frame[i].canvas = uvd->canvas; | ||
| 1154 | uvd->frame[i].seqRead_Index = 0; | ||
| 1155 | } | ||
| 1156 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 1157 | uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL); | ||
| 1158 | if (uvd->sbuf[i].data == NULL) { | ||
| 1159 | errCode = -ENOMEM; | ||
| 1160 | break; | ||
| 1161 | } | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | if (errCode != 0) { | ||
| 1165 | /* Have to free all that memory */ | ||
| 1166 | if (uvd->fbuf != NULL) { | ||
| 1167 | usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); | ||
| 1168 | uvd->fbuf = NULL; | ||
| 1169 | } | ||
| 1170 | RingQueue_Free(&uvd->dp); | ||
| 1171 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 1172 | kfree(uvd->sbuf[i].data); | ||
| 1173 | uvd->sbuf[i].data = NULL; | ||
| 1174 | } | ||
| 1175 | } | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | /* If so far no errors then we shall start the camera */ | ||
| 1179 | if (errCode == 0) { | ||
| 1180 | /* Start data pump if we have valid endpoint */ | ||
| 1181 | if (uvd->video_endp != 0) | ||
| 1182 | errCode = GET_CALLBACK(uvd, startDataPump)(uvd); | ||
| 1183 | if (errCode == 0) { | ||
| 1184 | if (VALID_CALLBACK(uvd, setupOnOpen)) { | ||
| 1185 | if (uvd->debug > 1) | ||
| 1186 | info("%s: setupOnOpen callback", __FUNCTION__); | ||
| 1187 | errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd); | ||
| 1188 | if (errCode < 0) { | ||
| 1189 | err("%s: setupOnOpen callback failed (%d.).", | ||
| 1190 | __FUNCTION__, errCode); | ||
| 1191 | } else if (uvd->debug > 1) { | ||
| 1192 | info("%s: setupOnOpen callback successful", __FUNCTION__); | ||
| 1193 | } | ||
| 1194 | } | ||
| 1195 | if (errCode == 0) { | ||
| 1196 | uvd->settingsAdjusted = 0; | ||
| 1197 | if (uvd->debug > 1) | ||
| 1198 | info("%s: Open succeeded.", __FUNCTION__); | ||
| 1199 | uvd->user++; | ||
| 1200 | file->private_data = uvd; | ||
| 1201 | } | ||
| 1202 | } | ||
| 1203 | } | ||
| 1204 | mutex_unlock(&uvd->lock); | ||
| 1205 | if (errCode != 0) | ||
| 1206 | usbvideo_ClientDecModCount(uvd); | ||
| 1207 | if (uvd->debug > 0) | ||
| 1208 | info("%s: Returning %d.", __FUNCTION__, errCode); | ||
| 1209 | return errCode; | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | /* | ||
| 1213 | * usbvideo_v4l_close() | ||
| 1214 | * | ||
| 1215 | * This is part of Video 4 Linux API. The procedure | ||
| 1216 | * stops streaming and deallocates all buffers that were earlier | ||
| 1217 | * allocated in usbvideo_v4l_open(). | ||
| 1218 | * | ||
| 1219 | * History: | ||
| 1220 | * 22-Jan-2000 Moved scratch buffer deallocation here. | ||
| 1221 | * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. | ||
| 1222 | * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep. | ||
| 1223 | */ | ||
| 1224 | static int usbvideo_v4l_close(struct inode *inode, struct file *file) | ||
| 1225 | { | ||
| 1226 | struct video_device *dev = file->private_data; | ||
| 1227 | struct uvd *uvd = (struct uvd *) dev; | ||
| 1228 | int i; | ||
| 1229 | |||
| 1230 | if (uvd->debug > 1) | ||
| 1231 | info("%s($%p)", __FUNCTION__, dev); | ||
| 1232 | |||
| 1233 | mutex_lock(&uvd->lock); | ||
| 1234 | GET_CALLBACK(uvd, stopDataPump)(uvd); | ||
| 1235 | usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); | ||
| 1236 | uvd->fbuf = NULL; | ||
| 1237 | RingQueue_Free(&uvd->dp); | ||
| 1238 | |||
| 1239 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 1240 | kfree(uvd->sbuf[i].data); | ||
| 1241 | uvd->sbuf[i].data = NULL; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | #if USBVIDEO_REPORT_STATS | ||
| 1245 | usbvideo_ReportStatistics(uvd); | ||
| 1246 | #endif | ||
| 1247 | |||
| 1248 | uvd->user--; | ||
| 1249 | if (uvd->remove_pending) { | ||
| 1250 | if (uvd->debug > 0) | ||
| 1251 | info("usbvideo_v4l_close: Final disconnect."); | ||
| 1252 | usbvideo_CameraRelease(uvd); | ||
| 1253 | } | ||
| 1254 | mutex_unlock(&uvd->lock); | ||
| 1255 | usbvideo_ClientDecModCount(uvd); | ||
| 1256 | |||
| 1257 | if (uvd->debug > 1) | ||
| 1258 | info("%s: Completed.", __FUNCTION__); | ||
| 1259 | file->private_data = NULL; | ||
| 1260 | return 0; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | /* | ||
| 1264 | * usbvideo_v4l_ioctl() | ||
| 1265 | * | ||
| 1266 | * This is part of Video 4 Linux API. The procedure handles ioctl() calls. | ||
| 1267 | * | ||
| 1268 | * History: | ||
| 1269 | * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. | ||
| 1270 | */ | ||
| 1271 | static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file, | ||
| 1272 | unsigned int cmd, void *arg) | ||
| 1273 | { | ||
| 1274 | struct uvd *uvd = file->private_data; | ||
| 1275 | |||
| 1276 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
| 1277 | return -EIO; | ||
| 1278 | |||
| 1279 | switch (cmd) { | ||
| 1280 | case VIDIOCGCAP: | ||
| 1281 | { | ||
| 1282 | struct video_capability *b = arg; | ||
| 1283 | *b = uvd->vcap; | ||
| 1284 | return 0; | ||
| 1285 | } | ||
| 1286 | case VIDIOCGCHAN: | ||
| 1287 | { | ||
| 1288 | struct video_channel *v = arg; | ||
| 1289 | *v = uvd->vchan; | ||
| 1290 | return 0; | ||
| 1291 | } | ||
| 1292 | case VIDIOCSCHAN: | ||
| 1293 | { | ||
| 1294 | struct video_channel *v = arg; | ||
| 1295 | if (v->channel != 0) | ||
| 1296 | return -EINVAL; | ||
| 1297 | return 0; | ||
| 1298 | } | ||
| 1299 | case VIDIOCGPICT: | ||
| 1300 | { | ||
| 1301 | struct video_picture *pic = arg; | ||
| 1302 | *pic = uvd->vpic; | ||
| 1303 | return 0; | ||
| 1304 | } | ||
| 1305 | case VIDIOCSPICT: | ||
| 1306 | { | ||
| 1307 | struct video_picture *pic = arg; | ||
| 1308 | /* | ||
| 1309 | * Use temporary 'video_picture' structure to preserve our | ||
| 1310 | * own settings (such as color depth, palette) that we | ||
| 1311 | * aren't allowing everyone (V4L client) to change. | ||
| 1312 | */ | ||
| 1313 | uvd->vpic.brightness = pic->brightness; | ||
| 1314 | uvd->vpic.hue = pic->hue; | ||
| 1315 | uvd->vpic.colour = pic->colour; | ||
| 1316 | uvd->vpic.contrast = pic->contrast; | ||
| 1317 | uvd->settingsAdjusted = 0; /* Will force new settings */ | ||
| 1318 | return 0; | ||
| 1319 | } | ||
| 1320 | case VIDIOCSWIN: | ||
| 1321 | { | ||
| 1322 | struct video_window *vw = arg; | ||
| 1323 | |||
| 1324 | if(VALID_CALLBACK(uvd, setVideoMode)) { | ||
| 1325 | return GET_CALLBACK(uvd, setVideoMode)(uvd, vw); | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | if (vw->flags) | ||
| 1329 | return -EINVAL; | ||
| 1330 | if (vw->clipcount) | ||
| 1331 | return -EINVAL; | ||
| 1332 | if (vw->width != VIDEOSIZE_X(uvd->canvas)) | ||
| 1333 | return -EINVAL; | ||
| 1334 | if (vw->height != VIDEOSIZE_Y(uvd->canvas)) | ||
| 1335 | return -EINVAL; | ||
| 1336 | |||
| 1337 | return 0; | ||
| 1338 | } | ||
| 1339 | case VIDIOCGWIN: | ||
| 1340 | { | ||
| 1341 | struct video_window *vw = arg; | ||
| 1342 | |||
| 1343 | vw->x = 0; | ||
| 1344 | vw->y = 0; | ||
| 1345 | vw->width = VIDEOSIZE_X(uvd->videosize); | ||
| 1346 | vw->height = VIDEOSIZE_Y(uvd->videosize); | ||
| 1347 | vw->chromakey = 0; | ||
| 1348 | if (VALID_CALLBACK(uvd, getFPS)) | ||
| 1349 | vw->flags = GET_CALLBACK(uvd, getFPS)(uvd); | ||
| 1350 | else | ||
| 1351 | vw->flags = 10; /* FIXME: do better! */ | ||
| 1352 | return 0; | ||
| 1353 | } | ||
| 1354 | case VIDIOCGMBUF: | ||
| 1355 | { | ||
| 1356 | struct video_mbuf *vm = arg; | ||
| 1357 | int i; | ||
| 1358 | |||
| 1359 | memset(vm, 0, sizeof(*vm)); | ||
| 1360 | vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES; | ||
| 1361 | vm->frames = USBVIDEO_NUMFRAMES; | ||
| 1362 | for(i = 0; i < USBVIDEO_NUMFRAMES; i++) | ||
| 1363 | vm->offsets[i] = i * uvd->max_frame_size; | ||
| 1364 | |||
| 1365 | return 0; | ||
| 1366 | } | ||
| 1367 | case VIDIOCMCAPTURE: | ||
| 1368 | { | ||
| 1369 | struct video_mmap *vm = arg; | ||
| 1370 | |||
| 1371 | if (uvd->debug >= 1) { | ||
| 1372 | info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.", | ||
| 1373 | vm->frame, vm->width, vm->height, vm->format); | ||
| 1374 | } | ||
| 1375 | /* | ||
| 1376 | * Check if the requested size is supported. If the requestor | ||
| 1377 | * requests too big a frame then we may be tricked into accessing | ||
| 1378 | * outside of own preallocated frame buffer (in uvd->frame). | ||
| 1379 | * This will cause oops or a security hole. Theoretically, we | ||
| 1380 | * could only clamp the size down to acceptable bounds, but then | ||
| 1381 | * we'd need to figure out how to insert our smaller buffer into | ||
| 1382 | * larger caller's buffer... this is not an easy question. So we | ||
| 1383 | * here just flatly reject too large requests, assuming that the | ||
| 1384 | * caller will resubmit with smaller size. Callers should know | ||
| 1385 | * what size we support (returned by VIDIOCGCAP). However vidcat, | ||
| 1386 | * for one, does not care and allows to ask for any size. | ||
| 1387 | */ | ||
| 1388 | if ((vm->width > VIDEOSIZE_X(uvd->canvas)) || | ||
| 1389 | (vm->height > VIDEOSIZE_Y(uvd->canvas))) { | ||
| 1390 | if (uvd->debug > 0) { | ||
| 1391 | info("VIDIOCMCAPTURE: Size=%dx%d too large; " | ||
| 1392 | "allowed only up to %ldx%ld", vm->width, vm->height, | ||
| 1393 | VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas)); | ||
| 1394 | } | ||
| 1395 | return -EINVAL; | ||
| 1396 | } | ||
| 1397 | /* Check if the palette is supported */ | ||
| 1398 | if (((1L << vm->format) & uvd->paletteBits) == 0) { | ||
| 1399 | if (uvd->debug > 0) { | ||
| 1400 | info("VIDIOCMCAPTURE: format=%d. not supported" | ||
| 1401 | " (paletteBits=$%08lx)", | ||
| 1402 | vm->format, uvd->paletteBits); | ||
| 1403 | } | ||
| 1404 | return -EINVAL; | ||
| 1405 | } | ||
| 1406 | if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) { | ||
| 1407 | err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1); | ||
| 1408 | return -EINVAL; | ||
| 1409 | } | ||
| 1410 | if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) { | ||
| 1411 | /* Not an error - can happen */ | ||
| 1412 | } | ||
| 1413 | uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height); | ||
| 1414 | uvd->frame[vm->frame].palette = vm->format; | ||
| 1415 | |||
| 1416 | /* Mark it as ready */ | ||
| 1417 | uvd->frame[vm->frame].frameState = FrameState_Ready; | ||
| 1418 | |||
| 1419 | return usbvideo_NewFrame(uvd, vm->frame); | ||
| 1420 | } | ||
| 1421 | case VIDIOCSYNC: | ||
| 1422 | { | ||
| 1423 | int *frameNum = arg; | ||
| 1424 | int ret; | ||
| 1425 | |||
| 1426 | if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES) | ||
| 1427 | return -EINVAL; | ||
| 1428 | |||
| 1429 | if (uvd->debug >= 1) | ||
| 1430 | info("VIDIOCSYNC: syncing to frame %d.", *frameNum); | ||
| 1431 | if (uvd->flags & FLAGS_NO_DECODING) | ||
| 1432 | ret = usbvideo_GetFrame(uvd, *frameNum); | ||
| 1433 | else if (VALID_CALLBACK(uvd, getFrame)) { | ||
| 1434 | ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum); | ||
| 1435 | if ((ret < 0) && (uvd->debug >= 1)) { | ||
| 1436 | err("VIDIOCSYNC: getFrame() returned %d.", ret); | ||
| 1437 | } | ||
| 1438 | } else { | ||
| 1439 | err("VIDIOCSYNC: getFrame is not set"); | ||
| 1440 | ret = -EFAULT; | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | /* | ||
| 1444 | * The frame is in FrameState_Done_Hold state. Release it | ||
| 1445 | * right now because its data is already mapped into | ||
| 1446 | * the user space and it's up to the application to | ||
| 1447 | * make use of it until it asks for another frame. | ||
| 1448 | */ | ||
| 1449 | uvd->frame[*frameNum].frameState = FrameState_Unused; | ||
| 1450 | return ret; | ||
| 1451 | } | ||
| 1452 | case VIDIOCGFBUF: | ||
| 1453 | { | ||
| 1454 | struct video_buffer *vb = arg; | ||
| 1455 | |||
| 1456 | memset(vb, 0, sizeof(*vb)); | ||
| 1457 | return 0; | ||
| 1458 | } | ||
| 1459 | case VIDIOCKEY: | ||
| 1460 | return 0; | ||
| 1461 | |||
| 1462 | case VIDIOCCAPTURE: | ||
| 1463 | return -EINVAL; | ||
| 1464 | |||
| 1465 | case VIDIOCSFBUF: | ||
| 1466 | |||
| 1467 | case VIDIOCGTUNER: | ||
| 1468 | case VIDIOCSTUNER: | ||
| 1469 | |||
| 1470 | case VIDIOCGFREQ: | ||
| 1471 | case VIDIOCSFREQ: | ||
| 1472 | |||
| 1473 | case VIDIOCGAUDIO: | ||
| 1474 | case VIDIOCSAUDIO: | ||
| 1475 | return -EINVAL; | ||
| 1476 | |||
| 1477 | default: | ||
| 1478 | return -ENOIOCTLCMD; | ||
| 1479 | } | ||
| 1480 | return 0; | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file, | ||
| 1484 | unsigned int cmd, unsigned long arg) | ||
| 1485 | { | ||
| 1486 | return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl); | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | /* | ||
| 1490 | * usbvideo_v4l_read() | ||
| 1491 | * | ||
| 1492 | * This is mostly boring stuff. We simply ask for a frame and when it | ||
| 1493 | * arrives copy all the video data from it into user space. There is | ||
| 1494 | * no obvious need to override this method. | ||
| 1495 | * | ||
| 1496 | * History: | ||
| 1497 | * 20-Oct-2000 Created. | ||
| 1498 | * 01-Nov-2000 Added mutex (uvd->lock). | ||
| 1499 | */ | ||
| 1500 | static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, | ||
| 1501 | size_t count, loff_t *ppos) | ||
| 1502 | { | ||
| 1503 | struct uvd *uvd = file->private_data; | ||
| 1504 | int noblock = file->f_flags & O_NONBLOCK; | ||
| 1505 | int frmx = -1, i; | ||
| 1506 | struct usbvideo_frame *frame; | ||
| 1507 | |||
| 1508 | if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL)) | ||
| 1509 | return -EFAULT; | ||
| 1510 | |||
| 1511 | if (uvd->debug >= 1) | ||
| 1512 | info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock); | ||
| 1513 | |||
| 1514 | mutex_lock(&uvd->lock); | ||
| 1515 | |||
| 1516 | /* See if a frame is completed, then use it. */ | ||
| 1517 | for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { | ||
| 1518 | if ((uvd->frame[i].frameState == FrameState_Done) || | ||
| 1519 | (uvd->frame[i].frameState == FrameState_Done_Hold) || | ||
| 1520 | (uvd->frame[i].frameState == FrameState_Error)) { | ||
| 1521 | frmx = i; | ||
| 1522 | break; | ||
| 1523 | } | ||
| 1524 | } | ||
| 1525 | |||
| 1526 | /* FIXME: If we don't start a frame here then who ever does? */ | ||
| 1527 | if (noblock && (frmx == -1)) { | ||
| 1528 | count = -EAGAIN; | ||
| 1529 | goto read_done; | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | /* | ||
| 1533 | * If no FrameState_Done, look for a FrameState_Grabbing state. | ||
| 1534 | * See if a frame is in process (grabbing), then use it. | ||
| 1535 | * We will need to wait until it becomes cooked, of course. | ||
| 1536 | */ | ||
| 1537 | if (frmx == -1) { | ||
| 1538 | for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { | ||
| 1539 | if (uvd->frame[i].frameState == FrameState_Grabbing) { | ||
| 1540 | frmx = i; | ||
| 1541 | break; | ||
| 1542 | } | ||
| 1543 | } | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | /* | ||
| 1547 | * If no frame is active, start one. We don't care which one | ||
| 1548 | * it will be, so #0 is as good as any. | ||
| 1549 | * In read access mode we don't have convenience of VIDIOCMCAPTURE | ||
| 1550 | * to specify the requested palette (video format) on per-frame | ||
| 1551 | * basis. This means that we have to return data in -some- format | ||
| 1552 | * and just hope that the client knows what to do with it. | ||
| 1553 | * The default format is configured in uvd->defaultPalette field | ||
| 1554 | * as one of VIDEO_PALETTE_xxx values. We stuff it into the new | ||
| 1555 | * frame and initiate the frame filling process. | ||
| 1556 | */ | ||
| 1557 | if (frmx == -1) { | ||
| 1558 | if (uvd->defaultPalette == 0) { | ||
| 1559 | err("%s: No default palette; don't know what to do!", __FUNCTION__); | ||
| 1560 | count = -EFAULT; | ||
| 1561 | goto read_done; | ||
| 1562 | } | ||
| 1563 | frmx = 0; | ||
| 1564 | /* | ||
| 1565 | * We have no per-frame control over video size. | ||
| 1566 | * Therefore we only can use whatever size was | ||
| 1567 | * specified as default. | ||
| 1568 | */ | ||
| 1569 | uvd->frame[frmx].request = uvd->videosize; | ||
| 1570 | uvd->frame[frmx].palette = uvd->defaultPalette; | ||
| 1571 | uvd->frame[frmx].frameState = FrameState_Ready; | ||
| 1572 | usbvideo_NewFrame(uvd, frmx); | ||
| 1573 | /* Now frame 0 is supposed to start filling... */ | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | /* | ||
| 1577 | * Get a pointer to the active frame. It is either previously | ||
| 1578 | * completed frame or frame in progress but not completed yet. | ||
| 1579 | */ | ||
| 1580 | frame = &uvd->frame[frmx]; | ||
| 1581 | |||
| 1582 | /* | ||
| 1583 | * Sit back & wait until the frame gets filled and postprocessed. | ||
| 1584 | * If we fail to get the picture [in time] then return the error. | ||
| 1585 | * In this call we specify that we want the frame to be waited for, | ||
| 1586 | * postprocessed and switched into FrameState_Done_Hold state. This | ||
| 1587 | * state is used to hold the frame as "fully completed" between | ||
| 1588 | * subsequent partial reads of the same frame. | ||
| 1589 | */ | ||
| 1590 | if (frame->frameState != FrameState_Done_Hold) { | ||
| 1591 | long rv = -EFAULT; | ||
| 1592 | if (uvd->flags & FLAGS_NO_DECODING) | ||
| 1593 | rv = usbvideo_GetFrame(uvd, frmx); | ||
| 1594 | else if (VALID_CALLBACK(uvd, getFrame)) | ||
| 1595 | rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx); | ||
| 1596 | else | ||
| 1597 | err("getFrame is not set"); | ||
| 1598 | if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) { | ||
| 1599 | count = rv; | ||
| 1600 | goto read_done; | ||
| 1601 | } | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | /* | ||
| 1605 | * Copy bytes to user space. We allow for partial reads, which | ||
| 1606 | * means that the user application can request read less than | ||
| 1607 | * the full frame size. It is up to the application to issue | ||
| 1608 | * subsequent calls until entire frame is read. | ||
| 1609 | * | ||
| 1610 | * First things first, make sure we don't copy more than we | ||
| 1611 | * have - even if the application wants more. That would be | ||
| 1612 | * a big security embarassment! | ||
| 1613 | */ | ||
| 1614 | if ((count + frame->seqRead_Index) > frame->seqRead_Length) | ||
| 1615 | count = frame->seqRead_Length - frame->seqRead_Index; | ||
| 1616 | |||
| 1617 | /* | ||
| 1618 | * Copy requested amount of data to user space. We start | ||
| 1619 | * copying from the position where we last left it, which | ||
| 1620 | * will be zero for a new frame (not read before). | ||
| 1621 | */ | ||
| 1622 | if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) { | ||
| 1623 | count = -EFAULT; | ||
| 1624 | goto read_done; | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | /* Update last read position */ | ||
| 1628 | frame->seqRead_Index += count; | ||
| 1629 | if (uvd->debug >= 1) { | ||
| 1630 | err("%s: {copy} count used=%Zd, new seqRead_Index=%ld", | ||
| 1631 | __FUNCTION__, count, frame->seqRead_Index); | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | /* Finally check if the frame is done with and "release" it */ | ||
| 1635 | if (frame->seqRead_Index >= frame->seqRead_Length) { | ||
| 1636 | /* All data has been read */ | ||
| 1637 | frame->seqRead_Index = 0; | ||
| 1638 | |||
| 1639 | /* Mark it as available to be used again. */ | ||
| 1640 | uvd->frame[frmx].frameState = FrameState_Unused; | ||
| 1641 | if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) { | ||
| 1642 | err("%s: usbvideo_NewFrame failed.", __FUNCTION__); | ||
| 1643 | } | ||
| 1644 | } | ||
| 1645 | read_done: | ||
| 1646 | mutex_unlock(&uvd->lock); | ||
| 1647 | return count; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | /* | ||
| 1651 | * Make all of the blocks of data contiguous | ||
| 1652 | */ | ||
| 1653 | static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb) | ||
| 1654 | { | ||
| 1655 | char *cdata; | ||
| 1656 | int i, totlen = 0; | ||
| 1657 | |||
| 1658 | for (i = 0; i < urb->number_of_packets; i++) { | ||
| 1659 | int n = urb->iso_frame_desc[i].actual_length; | ||
| 1660 | int st = urb->iso_frame_desc[i].status; | ||
| 1661 | |||
| 1662 | cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
| 1663 | |||
| 1664 | /* Detect and ignore errored packets */ | ||
| 1665 | if (st < 0) { | ||
| 1666 | if (uvd->debug >= 1) | ||
| 1667 | err("Data error: packet=%d. len=%d. status=%d.", i, n, st); | ||
| 1668 | uvd->stats.iso_err_count++; | ||
| 1669 | continue; | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | /* Detect and ignore empty packets */ | ||
| 1673 | if (n <= 0) { | ||
| 1674 | uvd->stats.iso_skip_count++; | ||
| 1675 | continue; | ||
| 1676 | } | ||
| 1677 | totlen += n; /* Little local accounting */ | ||
| 1678 | RingQueue_Enqueue(&uvd->dp, cdata, n); | ||
| 1679 | } | ||
| 1680 | return totlen; | ||
| 1681 | } | ||
| 1682 | |||
| 1683 | static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs) | ||
| 1684 | { | ||
| 1685 | int i, ret, len; | ||
| 1686 | struct uvd *uvd = urb->context; | ||
| 1687 | |||
| 1688 | /* We don't want to do anything if we are about to be removed! */ | ||
| 1689 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
| 1690 | return; | ||
| 1691 | #if 0 | ||
| 1692 | if (urb->actual_length > 0) { | ||
| 1693 | info("urb=$%p status=%d. errcount=%d. length=%d.", | ||
| 1694 | urb, urb->status, urb->error_count, urb->actual_length); | ||
| 1695 | } else { | ||
| 1696 | static int c = 0; | ||
| 1697 | if (c++ % 100 == 0) | ||
| 1698 | info("No Isoc data"); | ||
| 1699 | } | ||
| 1700 | #endif | ||
| 1701 | |||
| 1702 | if (!uvd->streaming) { | ||
| 1703 | if (uvd->debug >= 1) | ||
| 1704 | info("Not streaming, but interrupt!"); | ||
| 1705 | return; | ||
| 1706 | } | ||
| 1707 | |||
| 1708 | uvd->stats.urb_count++; | ||
| 1709 | if (urb->actual_length <= 0) | ||
| 1710 | goto urb_done_with; | ||
| 1711 | |||
| 1712 | /* Copy the data received into ring queue */ | ||
| 1713 | len = usbvideo_CompressIsochronous(uvd, urb); | ||
| 1714 | uvd->stats.urb_length = len; | ||
| 1715 | if (len <= 0) | ||
| 1716 | goto urb_done_with; | ||
| 1717 | |||
| 1718 | /* Here we got some data */ | ||
| 1719 | uvd->stats.data_count += len; | ||
| 1720 | RingQueue_WakeUpInterruptible(&uvd->dp); | ||
| 1721 | |||
| 1722 | urb_done_with: | ||
| 1723 | for (i = 0; i < FRAMES_PER_DESC; i++) { | ||
| 1724 | urb->iso_frame_desc[i].status = 0; | ||
| 1725 | urb->iso_frame_desc[i].actual_length = 0; | ||
| 1726 | } | ||
| 1727 | urb->status = 0; | ||
| 1728 | urb->dev = uvd->dev; | ||
| 1729 | ret = usb_submit_urb (urb, GFP_KERNEL); | ||
| 1730 | if(ret) | ||
| 1731 | err("usb_submit_urb error (%d)", ret); | ||
| 1732 | return; | ||
| 1733 | } | ||
| 1734 | |||
| 1735 | /* | ||
| 1736 | * usbvideo_StartDataPump() | ||
| 1737 | * | ||
| 1738 | * History: | ||
| 1739 | * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead | ||
| 1740 | * of hardcoded values. Simplified by using for loop, | ||
| 1741 | * allowed any number of URBs. | ||
| 1742 | */ | ||
| 1743 | static int usbvideo_StartDataPump(struct uvd *uvd) | ||
| 1744 | { | ||
| 1745 | struct usb_device *dev = uvd->dev; | ||
| 1746 | int i, errFlag; | ||
| 1747 | |||
| 1748 | if (uvd->debug > 1) | ||
| 1749 | info("%s($%p)", __FUNCTION__, uvd); | ||
| 1750 | |||
| 1751 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
| 1752 | err("%s: Camera is not operational", __FUNCTION__); | ||
| 1753 | return -EFAULT; | ||
| 1754 | } | ||
| 1755 | uvd->curframe = -1; | ||
| 1756 | |||
| 1757 | /* Alternate interface 1 is is the biggest frame size */ | ||
| 1758 | i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); | ||
| 1759 | if (i < 0) { | ||
| 1760 | err("%s: usb_set_interface error", __FUNCTION__); | ||
| 1761 | uvd->last_error = i; | ||
| 1762 | return -EBUSY; | ||
| 1763 | } | ||
| 1764 | if (VALID_CALLBACK(uvd, videoStart)) | ||
| 1765 | GET_CALLBACK(uvd, videoStart)(uvd); | ||
| 1766 | else | ||
| 1767 | err("%s: videoStart not set", __FUNCTION__); | ||
| 1768 | |||
| 1769 | /* We double buffer the Iso lists */ | ||
| 1770 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 1771 | int j, k; | ||
| 1772 | struct urb *urb = uvd->sbuf[i].urb; | ||
| 1773 | urb->dev = dev; | ||
| 1774 | urb->context = uvd; | ||
| 1775 | urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); | ||
| 1776 | urb->interval = 1; | ||
| 1777 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 1778 | urb->transfer_buffer = uvd->sbuf[i].data; | ||
| 1779 | urb->complete = usbvideo_IsocIrq; | ||
| 1780 | urb->number_of_packets = FRAMES_PER_DESC; | ||
| 1781 | urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC; | ||
| 1782 | for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) { | ||
| 1783 | urb->iso_frame_desc[j].offset = k; | ||
| 1784 | urb->iso_frame_desc[j].length = uvd->iso_packet_len; | ||
| 1785 | } | ||
| 1786 | } | ||
| 1787 | |||
| 1788 | /* Submit all URBs */ | ||
| 1789 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 1790 | errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); | ||
| 1791 | if (errFlag) | ||
| 1792 | err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag); | ||
| 1793 | } | ||
| 1794 | |||
| 1795 | uvd->streaming = 1; | ||
| 1796 | if (uvd->debug > 1) | ||
| 1797 | info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp); | ||
| 1798 | return 0; | ||
| 1799 | } | ||
| 1800 | |||
| 1801 | /* | ||
| 1802 | * usbvideo_StopDataPump() | ||
| 1803 | * | ||
| 1804 | * This procedure stops streaming and deallocates URBs. Then it | ||
| 1805 | * activates zero-bandwidth alt. setting of the video interface. | ||
| 1806 | * | ||
| 1807 | * History: | ||
| 1808 | * 22-Jan-2000 Corrected order of actions to work after surprise removal. | ||
| 1809 | * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values. | ||
| 1810 | */ | ||
| 1811 | static void usbvideo_StopDataPump(struct uvd *uvd) | ||
| 1812 | { | ||
| 1813 | int i, j; | ||
| 1814 | |||
| 1815 | if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) | ||
| 1816 | return; | ||
| 1817 | |||
| 1818 | if (uvd->debug > 1) | ||
| 1819 | info("%s($%p)", __FUNCTION__, uvd); | ||
| 1820 | |||
| 1821 | /* Unschedule all of the iso td's */ | ||
| 1822 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
| 1823 | usb_kill_urb(uvd->sbuf[i].urb); | ||
| 1824 | } | ||
| 1825 | if (uvd->debug > 1) | ||
| 1826 | info("%s: streaming=0", __FUNCTION__); | ||
| 1827 | uvd->streaming = 0; | ||
| 1828 | |||
| 1829 | if (!uvd->remove_pending) { | ||
| 1830 | /* Invoke minidriver's magic to stop the camera */ | ||
| 1831 | if (VALID_CALLBACK(uvd, videoStop)) | ||
| 1832 | GET_CALLBACK(uvd, videoStop)(uvd); | ||
| 1833 | else | ||
| 1834 | err("%s: videoStop not set", __FUNCTION__); | ||
| 1835 | |||
| 1836 | /* Set packet size to 0 */ | ||
| 1837 | j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); | ||
| 1838 | if (j < 0) { | ||
| 1839 | err("%s: usb_set_interface() error %d.", __FUNCTION__, j); | ||
| 1840 | uvd->last_error = j; | ||
| 1841 | } | ||
| 1842 | } | ||
| 1843 | } | ||
| 1844 | |||
| 1845 | /* | ||
| 1846 | * usbvideo_NewFrame() | ||
| 1847 | * | ||
| 1848 | * History: | ||
| 1849 | * 29-Mar-00 Added copying of previous frame into the current one. | ||
| 1850 | * 6-Aug-00 Added model 3 video sizes, removed redundant width, height. | ||
| 1851 | */ | ||
| 1852 | static int usbvideo_NewFrame(struct uvd *uvd, int framenum) | ||
| 1853 | { | ||
| 1854 | struct usbvideo_frame *frame; | ||
| 1855 | int n; | ||
| 1856 | |||
| 1857 | if (uvd->debug > 1) | ||
| 1858 | info("usbvideo_NewFrame($%p,%d.)", uvd, framenum); | ||
| 1859 | |||
| 1860 | /* If we're not grabbing a frame right now and the other frame is */ | ||
| 1861 | /* ready to be grabbed into, then use it instead */ | ||
| 1862 | if (uvd->curframe != -1) | ||
| 1863 | return 0; | ||
| 1864 | |||
| 1865 | /* If necessary we adjust picture settings between frames */ | ||
| 1866 | if (!uvd->settingsAdjusted) { | ||
| 1867 | if (VALID_CALLBACK(uvd, adjustPicture)) | ||
| 1868 | GET_CALLBACK(uvd, adjustPicture)(uvd); | ||
| 1869 | uvd->settingsAdjusted = 1; | ||
| 1870 | } | ||
| 1871 | |||
| 1872 | n = (framenum + 1) % USBVIDEO_NUMFRAMES; | ||
| 1873 | if (uvd->frame[n].frameState == FrameState_Ready) | ||
| 1874 | framenum = n; | ||
| 1875 | |||
| 1876 | frame = &uvd->frame[framenum]; | ||
| 1877 | |||
| 1878 | frame->frameState = FrameState_Grabbing; | ||
| 1879 | frame->scanstate = ScanState_Scanning; | ||
| 1880 | frame->seqRead_Length = 0; /* Accumulated in xxx_parse_data() */ | ||
| 1881 | frame->deinterlace = Deinterlace_None; | ||
| 1882 | frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */ | ||
| 1883 | uvd->curframe = framenum; | ||
| 1884 | |||
| 1885 | /* | ||
| 1886 | * Normally we would want to copy previous frame into the current one | ||
| 1887 | * before we even start filling it with data; this allows us to stop | ||
| 1888 | * filling at any moment; top portion of the frame will be new and | ||
| 1889 | * bottom portion will stay as it was in previous frame. If we don't | ||
| 1890 | * do that then missing chunks of video stream will result in flickering | ||
| 1891 | * portions of old data whatever it was before. | ||
| 1892 | * | ||
| 1893 | * If we choose not to copy previous frame (to, for example, save few | ||
| 1894 | * bus cycles - the frame can be pretty large!) then we have an option | ||
| 1895 | * to clear the frame before using. If we experience losses in this | ||
| 1896 | * mode then missing picture will be black (no flickering). | ||
| 1897 | * | ||
| 1898 | * Finally, if user chooses not to clean the current frame before | ||
| 1899 | * filling it with data then the old data will be visible if we fail | ||
| 1900 | * to refill entire frame with new data. | ||
| 1901 | */ | ||
| 1902 | if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) { | ||
| 1903 | /* This copies previous frame into this one to mask losses */ | ||
| 1904 | int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES; | ||
| 1905 | memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size); | ||
| 1906 | } else { | ||
| 1907 | if (uvd->flags & FLAGS_CLEAN_FRAMES) { | ||
| 1908 | /* This provides a "clean" frame but slows things down */ | ||
| 1909 | memset(frame->data, 0, uvd->max_frame_size); | ||
| 1910 | } | ||
| 1911 | } | ||
| 1912 | return 0; | ||
| 1913 | } | ||
| 1914 | |||
| 1915 | /* | ||
| 1916 | * usbvideo_CollectRawData() | ||
| 1917 | * | ||
| 1918 | * This procedure can be used instead of 'processData' callback if you | ||
| 1919 | * only want to dump the raw data from the camera into the output | ||
| 1920 | * device (frame buffer). You can look at it with V4L client, but the | ||
| 1921 | * image will be unwatchable. The main purpose of this code and of the | ||
| 1922 | * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from | ||
| 1923 | * new, unknown cameras. This procedure will be automatically invoked | ||
| 1924 | * instead of the specified callback handler when uvd->flags has bit | ||
| 1925 | * FLAGS_NO_DECODING set. Therefore, any regular build of any driver | ||
| 1926 | * based on usbvideo can use this feature at any time. | ||
| 1927 | */ | ||
| 1928 | static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame) | ||
| 1929 | { | ||
| 1930 | int n; | ||
| 1931 | |||
| 1932 | assert(uvd != NULL); | ||
| 1933 | assert(frame != NULL); | ||
| 1934 | |||
| 1935 | /* Try to move data from queue into frame buffer */ | ||
| 1936 | n = RingQueue_GetLength(&uvd->dp); | ||
| 1937 | if (n > 0) { | ||
| 1938 | int m; | ||
| 1939 | /* See how much space we have left */ | ||
| 1940 | m = uvd->max_frame_size - frame->seqRead_Length; | ||
| 1941 | if (n > m) | ||
| 1942 | n = m; | ||
| 1943 | /* Now move that much data into frame buffer */ | ||
| 1944 | RingQueue_Dequeue( | ||
| 1945 | &uvd->dp, | ||
| 1946 | frame->data + frame->seqRead_Length, | ||
| 1947 | m); | ||
| 1948 | frame->seqRead_Length += m; | ||
| 1949 | } | ||
| 1950 | /* See if we filled the frame */ | ||
| 1951 | if (frame->seqRead_Length >= uvd->max_frame_size) { | ||
| 1952 | frame->frameState = FrameState_Done; | ||
| 1953 | uvd->curframe = -1; | ||
| 1954 | uvd->stats.frame_num++; | ||
| 1955 | } | ||
| 1956 | } | ||
| 1957 | |||
| 1958 | static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) | ||
| 1959 | { | ||
| 1960 | struct usbvideo_frame *frame = &uvd->frame[frameNum]; | ||
| 1961 | |||
| 1962 | if (uvd->debug >= 2) | ||
| 1963 | info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum); | ||
| 1964 | |||
| 1965 | switch (frame->frameState) { | ||
| 1966 | case FrameState_Unused: | ||
| 1967 | if (uvd->debug >= 2) | ||
| 1968 | info("%s: FrameState_Unused", __FUNCTION__); | ||
| 1969 | return -EINVAL; | ||
| 1970 | case FrameState_Ready: | ||
| 1971 | case FrameState_Grabbing: | ||
| 1972 | case FrameState_Error: | ||
| 1973 | { | ||
| 1974 | int ntries, signalPending; | ||
| 1975 | redo: | ||
| 1976 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
| 1977 | if (uvd->debug >= 2) | ||
| 1978 | info("%s: Camera is not operational (1)", __FUNCTION__); | ||
| 1979 | return -EIO; | ||
| 1980 | } | ||
| 1981 | ntries = 0; | ||
| 1982 | do { | ||
| 1983 | RingQueue_InterruptibleSleepOn(&uvd->dp); | ||
| 1984 | signalPending = signal_pending(current); | ||
| 1985 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
| 1986 | if (uvd->debug >= 2) | ||
| 1987 | info("%s: Camera is not operational (2)", __FUNCTION__); | ||
| 1988 | return -EIO; | ||
| 1989 | } | ||
| 1990 | assert(uvd->fbuf != NULL); | ||
| 1991 | if (signalPending) { | ||
| 1992 | if (uvd->debug >= 2) | ||
| 1993 | info("%s: Signal=$%08x", __FUNCTION__, signalPending); | ||
| 1994 | if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) { | ||
| 1995 | usbvideo_TestPattern(uvd, 1, 0); | ||
| 1996 | uvd->curframe = -1; | ||
| 1997 | uvd->stats.frame_num++; | ||
| 1998 | if (uvd->debug >= 2) | ||
| 1999 | info("%s: Forced test pattern screen", __FUNCTION__); | ||
| 2000 | return 0; | ||
| 2001 | } else { | ||
| 2002 | /* Standard answer: Interrupted! */ | ||
| 2003 | if (uvd->debug >= 2) | ||
| 2004 | info("%s: Interrupted!", __FUNCTION__); | ||
| 2005 | return -EINTR; | ||
| 2006 | } | ||
| 2007 | } else { | ||
| 2008 | /* No signals - we just got new data in dp queue */ | ||
| 2009 | if (uvd->flags & FLAGS_NO_DECODING) | ||
| 2010 | usbvideo_CollectRawData(uvd, frame); | ||
| 2011 | else if (VALID_CALLBACK(uvd, processData)) | ||
| 2012 | GET_CALLBACK(uvd, processData)(uvd, frame); | ||
| 2013 | else | ||
| 2014 | err("%s: processData not set", __FUNCTION__); | ||
| 2015 | } | ||
| 2016 | } while (frame->frameState == FrameState_Grabbing); | ||
| 2017 | if (uvd->debug >= 2) { | ||
| 2018 | info("%s: Grabbing done; state=%d. (%lu. bytes)", | ||
| 2019 | __FUNCTION__, frame->frameState, frame->seqRead_Length); | ||
| 2020 | } | ||
| 2021 | if (frame->frameState == FrameState_Error) { | ||
| 2022 | int ret = usbvideo_NewFrame(uvd, frameNum); | ||
| 2023 | if (ret < 0) { | ||
| 2024 | err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret); | ||
| 2025 | return ret; | ||
| 2026 | } | ||
| 2027 | goto redo; | ||
| 2028 | } | ||
| 2029 | /* Note that we fall through to meet our destiny below */ | ||
| 2030 | } | ||
| 2031 | case FrameState_Done: | ||
| 2032 | /* | ||
| 2033 | * Do all necessary postprocessing of data prepared in | ||
| 2034 | * "interrupt" code and the collecting code above. The | ||
| 2035 | * frame gets marked as FrameState_Done by queue parsing code. | ||
| 2036 | * This status means that we collected enough data and | ||
| 2037 | * most likely processed it as we went through. However | ||
| 2038 | * the data may need postprocessing, such as deinterlacing | ||
| 2039 | * or picture adjustments implemented in software (horror!) | ||
| 2040 | * | ||
| 2041 | * As soon as the frame becomes "final" it gets promoted to | ||
| 2042 | * FrameState_Done_Hold status where it will remain until the | ||
| 2043 | * caller consumed all the video data from the frame. Then | ||
| 2044 | * the empty shell of ex-frame is thrown out for dogs to eat. | ||
| 2045 | * But we, worried about pets, will recycle the frame! | ||
| 2046 | */ | ||
| 2047 | uvd->stats.frame_num++; | ||
| 2048 | if ((uvd->flags & FLAGS_NO_DECODING) == 0) { | ||
| 2049 | if (VALID_CALLBACK(uvd, postProcess)) | ||
| 2050 | GET_CALLBACK(uvd, postProcess)(uvd, frame); | ||
| 2051 | if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST) | ||
| 2052 | usbvideo_SoftwareContrastAdjustment(uvd, frame); | ||
| 2053 | } | ||
| 2054 | frame->frameState = FrameState_Done_Hold; | ||
| 2055 | if (uvd->debug >= 2) | ||
| 2056 | info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__); | ||
| 2057 | return 0; | ||
| 2058 | |||
| 2059 | case FrameState_Done_Hold: | ||
| 2060 | /* | ||
| 2061 | * We stay in this state indefinitely until someone external, | ||
| 2062 | * like ioctl() or read() call finishes digesting the frame | ||
| 2063 | * data. Then it will mark the frame as FrameState_Unused and | ||
| 2064 | * it will be released back into the wild to roam freely. | ||
| 2065 | */ | ||
| 2066 | if (uvd->debug >= 2) | ||
| 2067 | info("%s: FrameState_Done_Hold state.", __FUNCTION__); | ||
| 2068 | return 0; | ||
| 2069 | } | ||
| 2070 | |||
| 2071 | /* Catch-all for other cases. We shall not be here. */ | ||
| 2072 | err("%s: Invalid state %d.", __FUNCTION__, frame->frameState); | ||
| 2073 | frame->frameState = FrameState_Unused; | ||
| 2074 | return 0; | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | /* | ||
| 2078 | * usbvideo_DeinterlaceFrame() | ||
| 2079 | * | ||
| 2080 | * This procedure deinterlaces the given frame. Some cameras produce | ||
| 2081 | * only half of scanlines - sometimes only even lines, sometimes only | ||
| 2082 | * odd lines. The deinterlacing method is stored in frame->deinterlace | ||
| 2083 | * variable. | ||
| 2084 | * | ||
| 2085 | * Here we scan the frame vertically and replace missing scanlines with | ||
| 2086 | * average between surrounding ones - before and after. If we have no | ||
| 2087 | * line above then we just copy next line. Similarly, if we need to | ||
| 2088 | * create a last line then preceding line is used. | ||
| 2089 | */ | ||
| 2090 | void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame) | ||
| 2091 | { | ||
| 2092 | if ((uvd == NULL) || (frame == NULL)) | ||
| 2093 | return; | ||
| 2094 | |||
| 2095 | if ((frame->deinterlace == Deinterlace_FillEvenLines) || | ||
| 2096 | (frame->deinterlace == Deinterlace_FillOddLines)) | ||
| 2097 | { | ||
| 2098 | const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
| 2099 | int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1; | ||
| 2100 | |||
| 2101 | for (; i < VIDEOSIZE_Y(frame->request); i += 2) { | ||
| 2102 | const unsigned char *fs1, *fs2; | ||
| 2103 | unsigned char *fd; | ||
| 2104 | int ip, in, j; /* Previous and next lines */ | ||
| 2105 | |||
| 2106 | /* | ||
| 2107 | * Need to average lines before and after 'i'. | ||
| 2108 | * If we go out of bounds seeking those lines then | ||
| 2109 | * we point back to existing line. | ||
| 2110 | */ | ||
| 2111 | ip = i - 1; /* First, get rough numbers */ | ||
| 2112 | in = i + 1; | ||
| 2113 | |||
| 2114 | /* Now validate */ | ||
| 2115 | if (ip < 0) | ||
| 2116 | ip = in; | ||
| 2117 | if (in >= VIDEOSIZE_Y(frame->request)) | ||
| 2118 | in = ip; | ||
| 2119 | |||
| 2120 | /* Sanity check */ | ||
| 2121 | if ((ip < 0) || (in < 0) || | ||
| 2122 | (ip >= VIDEOSIZE_Y(frame->request)) || | ||
| 2123 | (in >= VIDEOSIZE_Y(frame->request))) | ||
| 2124 | { | ||
| 2125 | err("Error: ip=%d. in=%d. req.height=%ld.", | ||
| 2126 | ip, in, VIDEOSIZE_Y(frame->request)); | ||
| 2127 | break; | ||
| 2128 | } | ||
| 2129 | |||
| 2130 | /* Now we need to average lines 'ip' and 'in' to produce line 'i' */ | ||
| 2131 | fs1 = frame->data + (v4l_linesize * ip); | ||
| 2132 | fs2 = frame->data + (v4l_linesize * in); | ||
| 2133 | fd = frame->data + (v4l_linesize * i); | ||
| 2134 | |||
| 2135 | /* Average lines around destination */ | ||
| 2136 | for (j=0; j < v4l_linesize; j++) { | ||
| 2137 | fd[j] = (unsigned char)((((unsigned) fs1[j]) + | ||
| 2138 | ((unsigned)fs2[j])) >> 1); | ||
| 2139 | } | ||
| 2140 | } | ||
| 2141 | } | ||
| 2142 | |||
| 2143 | /* Optionally display statistics on the screen */ | ||
| 2144 | if (uvd->flags & FLAGS_OVERLAY_STATS) | ||
| 2145 | usbvideo_OverlayStats(uvd, frame); | ||
| 2146 | } | ||
| 2147 | |||
| 2148 | EXPORT_SYMBOL(usbvideo_DeinterlaceFrame); | ||
| 2149 | |||
| 2150 | /* | ||
| 2151 | * usbvideo_SoftwareContrastAdjustment() | ||
| 2152 | * | ||
| 2153 | * This code adjusts the contrast of the frame, assuming RGB24 format. | ||
| 2154 | * As most software image processing, this job is CPU-intensive. | ||
| 2155 | * Get a camera that supports hardware adjustment! | ||
| 2156 | * | ||
| 2157 | * History: | ||
| 2158 | * 09-Feb-2001 Created. | ||
| 2159 | */ | ||
| 2160 | static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, | ||
| 2161 | struct usbvideo_frame *frame) | ||
| 2162 | { | ||
| 2163 | int i, j, v4l_linesize; | ||
| 2164 | signed long adj; | ||
| 2165 | const int ccm = 128; /* Color correction median - see below */ | ||
| 2166 | |||
| 2167 | if ((uvd == NULL) || (frame == NULL)) { | ||
| 2168 | err("%s: Illegal call.", __FUNCTION__); | ||
| 2169 | return; | ||
| 2170 | } | ||
| 2171 | adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ | ||
| 2172 | RESTRICT_TO_RANGE(adj, -ccm, ccm+1); | ||
| 2173 | if (adj == 0) { | ||
| 2174 | /* In rare case of no adjustment */ | ||
| 2175 | return; | ||
| 2176 | } | ||
| 2177 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
| 2178 | for (i=0; i < VIDEOSIZE_Y(frame->request); i++) { | ||
| 2179 | unsigned char *fd = frame->data + (v4l_linesize * i); | ||
| 2180 | for (j=0; j < v4l_linesize; j++) { | ||
| 2181 | signed long v = (signed long) fd[j]; | ||
| 2182 | /* Magnify up to 2 times, reduce down to zero */ | ||
| 2183 | v = 128 + ((ccm + adj) * (v - 128)) / ccm; | ||
| 2184 | RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */ | ||
| 2185 | fd[j] = (unsigned char) v; | ||
| 2186 | } | ||
| 2187 | } | ||
| 2188 | } | ||
| 2189 | |||
| 2190 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h deleted file mode 100644 index 135433c2680a..000000000000 --- a/drivers/usb/media/usbvideo.h +++ /dev/null | |||
| @@ -1,394 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * This program is free software; you can redistribute it and/or modify | ||
| 3 | * it under the terms of the GNU General Public License as published by | ||
| 4 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 5 | * any later version. | ||
| 6 | * | ||
| 7 | * This program is distributed in the hope that it will be useful, | ||
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | * GNU General Public License for more details. | ||
| 11 | * | ||
| 12 | * You should have received a copy of the GNU General Public License | ||
| 13 | * along with this program; if not, write to the Free Software | ||
| 14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 15 | */ | ||
| 16 | #ifndef usbvideo_h | ||
| 17 | #define usbvideo_h | ||
| 18 | |||
| 19 | #include <linux/config.h> | ||
| 20 | #include <linux/videodev.h> | ||
| 21 | #include <linux/usb.h> | ||
| 22 | #include <linux/mutex.h> | ||
| 23 | |||
| 24 | /* Most helpful debugging aid */ | ||
| 25 | #define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__)))) | ||
| 26 | |||
| 27 | #define USBVIDEO_REPORT_STATS 1 /* Set to 0 to block statistics on close */ | ||
| 28 | |||
| 29 | /* Bit flags (options) */ | ||
| 30 | #define FLAGS_RETRY_VIDIOCSYNC (1 << 0) | ||
| 31 | #define FLAGS_MONOCHROME (1 << 1) | ||
| 32 | #define FLAGS_DISPLAY_HINTS (1 << 2) | ||
| 33 | #define FLAGS_OVERLAY_STATS (1 << 3) | ||
| 34 | #define FLAGS_FORCE_TESTPATTERN (1 << 4) | ||
| 35 | #define FLAGS_SEPARATE_FRAMES (1 << 5) | ||
| 36 | #define FLAGS_CLEAN_FRAMES (1 << 6) | ||
| 37 | #define FLAGS_NO_DECODING (1 << 7) | ||
| 38 | |||
| 39 | /* Bit flags for frames (apply to the frame where they are specified) */ | ||
| 40 | #define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST (1 << 0) | ||
| 41 | |||
| 42 | /* Camera capabilities (maximum) */ | ||
| 43 | #define CAMERA_URB_FRAMES 32 | ||
| 44 | #define CAMERA_MAX_ISO_PACKET 1023 /* 1022 actually sent by camera */ | ||
| 45 | #define FRAMES_PER_DESC (CAMERA_URB_FRAMES) | ||
| 46 | #define FRAME_SIZE_PER_DESC (CAMERA_MAX_ISO_PACKET) | ||
| 47 | |||
| 48 | /* This macro restricts an int variable to an inclusive range */ | ||
| 49 | #define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } | ||
| 50 | |||
| 51 | #define V4L_BYTES_PER_PIXEL 3 /* Because we produce RGB24 */ | ||
| 52 | |||
| 53 | /* | ||
| 54 | * Use this macro to construct constants for different video sizes. | ||
| 55 | * We have to deal with different video sizes that have to be | ||
| 56 | * configured in the device or compared against when we receive | ||
| 57 | * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y | ||
| 58 | * #defines and that's the end of story. However this solution | ||
| 59 | * does not allow to convert between real pixel sizes and the | ||
| 60 | * constant (integer) value that may be used to tag a frame or | ||
| 61 | * whatever. The set of macros below constructs videosize constants | ||
| 62 | * from the pixel size and allows to reconstruct the pixel size | ||
| 63 | * from the combined value later. | ||
| 64 | */ | ||
| 65 | #define VIDEOSIZE(x,y) (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16)) | ||
| 66 | #define VIDEOSIZE_X(vs) ((vs) & 0xFFFFL) | ||
| 67 | #define VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL) | ||
| 68 | typedef unsigned long videosize_t; | ||
| 69 | |||
| 70 | /* | ||
| 71 | * This macro checks if the camera is still operational. The 'uvd' | ||
| 72 | * pointer must be valid, uvd->dev must be valid, we are not | ||
| 73 | * removing the device and the device has not erred on us. | ||
| 74 | */ | ||
| 75 | #define CAMERA_IS_OPERATIONAL(uvd) (\ | ||
| 76 | (uvd != NULL) && \ | ||
| 77 | ((uvd)->dev != NULL) && \ | ||
| 78 | ((uvd)->last_error == 0) && \ | ||
| 79 | (!(uvd)->remove_pending)) | ||
| 80 | |||
| 81 | /* | ||
| 82 | * We use macros to do YUV -> RGB conversion because this is | ||
| 83 | * very important for speed and totally unimportant for size. | ||
| 84 | * | ||
| 85 | * YUV -> RGB Conversion | ||
| 86 | * --------------------- | ||
| 87 | * | ||
| 88 | * B = 1.164*(Y-16) + 2.018*(V-128) | ||
| 89 | * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) | ||
| 90 | * R = 1.164*(Y-16) + 1.596*(U-128) | ||
| 91 | * | ||
| 92 | * If you fancy integer arithmetics (as you should), hear this: | ||
| 93 | * | ||
| 94 | * 65536*B = 76284*(Y-16) + 132252*(V-128) | ||
| 95 | * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) | ||
| 96 | * 65536*R = 76284*(Y-16) + 104595*(U-128) | ||
| 97 | * | ||
| 98 | * Make sure the output values are within [0..255] range. | ||
| 99 | */ | ||
| 100 | #define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x))) | ||
| 101 | #define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \ | ||
| 102 | int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \ | ||
| 103 | mm_y = (my) - 16; \ | ||
| 104 | mm_u = (mu) - 128; \ | ||
| 105 | mm_v = (mv) - 128; \ | ||
| 106 | mm_yc= mm_y * 76284; \ | ||
| 107 | mm_b = (mm_yc + 132252*mm_v ) >> 16; \ | ||
| 108 | mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \ | ||
| 109 | mm_r = (mm_yc + 104595*mm_u ) >> 16; \ | ||
| 110 | mb = LIMIT_RGB(mm_b); \ | ||
| 111 | mg = LIMIT_RGB(mm_g); \ | ||
| 112 | mr = LIMIT_RGB(mm_r); \ | ||
| 113 | } | ||
| 114 | |||
| 115 | #define RING_QUEUE_SIZE (128*1024) /* Must be a power of 2 */ | ||
| 116 | #define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1) | ||
| 117 | #define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n) | ||
| 118 | #define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)]) | ||
| 119 | |||
| 120 | struct RingQueue { | ||
| 121 | unsigned char *queue; /* Data from the Isoc data pump */ | ||
| 122 | int length; /* How many bytes allocated for the queue */ | ||
| 123 | int wi; /* That's where we write */ | ||
| 124 | int ri; /* Read from here until you hit write index */ | ||
| 125 | wait_queue_head_t wqh; /* Processes waiting */ | ||
| 126 | }; | ||
| 127 | |||
| 128 | enum ScanState { | ||
| 129 | ScanState_Scanning, /* Scanning for header */ | ||
| 130 | ScanState_Lines /* Parsing lines */ | ||
| 131 | }; | ||
| 132 | |||
| 133 | /* Completion states of the data parser */ | ||
| 134 | enum ParseState { | ||
| 135 | scan_Continue, /* Just parse next item */ | ||
| 136 | scan_NextFrame, /* Frame done, send it to V4L */ | ||
| 137 | scan_Out, /* Not enough data for frame */ | ||
| 138 | scan_EndParse /* End parsing */ | ||
| 139 | }; | ||
| 140 | |||
| 141 | enum FrameState { | ||
| 142 | FrameState_Unused, /* Unused (no MCAPTURE) */ | ||
| 143 | FrameState_Ready, /* Ready to start grabbing */ | ||
| 144 | FrameState_Grabbing, /* In the process of being grabbed into */ | ||
| 145 | FrameState_Done, /* Finished grabbing, but not been synced yet */ | ||
| 146 | FrameState_Done_Hold, /* Are syncing or reading */ | ||
| 147 | FrameState_Error, /* Something bad happened while processing */ | ||
| 148 | }; | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Some frames may contain only even or odd lines. This type | ||
| 152 | * specifies what type of deinterlacing is required. | ||
| 153 | */ | ||
| 154 | enum Deinterlace { | ||
| 155 | Deinterlace_None=0, | ||
| 156 | Deinterlace_FillOddLines, | ||
| 157 | Deinterlace_FillEvenLines | ||
| 158 | }; | ||
| 159 | |||
| 160 | #define USBVIDEO_NUMFRAMES 2 /* How many frames we work with */ | ||
| 161 | #define USBVIDEO_NUMSBUF 2 /* How many URBs linked in a ring */ | ||
| 162 | |||
| 163 | /* This structure represents one Isoc request - URB and buffer */ | ||
| 164 | struct usbvideo_sbuf { | ||
| 165 | char *data; | ||
| 166 | struct urb *urb; | ||
| 167 | }; | ||
| 168 | |||
| 169 | struct usbvideo_frame { | ||
| 170 | char *data; /* Frame buffer */ | ||
| 171 | unsigned long header; /* Significant bits from the header */ | ||
| 172 | |||
| 173 | videosize_t canvas; /* The canvas (max. image) allocated */ | ||
| 174 | videosize_t request; /* That's what the application asked for */ | ||
| 175 | unsigned short palette; /* The desired format */ | ||
| 176 | |||
| 177 | enum FrameState frameState;/* State of grabbing */ | ||
| 178 | enum ScanState scanstate; /* State of scanning */ | ||
| 179 | enum Deinterlace deinterlace; | ||
| 180 | int flags; /* USBVIDEO_FRAME_FLAG_xxx bit flags */ | ||
| 181 | |||
| 182 | int curline; /* Line of frame we're working on */ | ||
| 183 | |||
| 184 | long seqRead_Length; /* Raw data length of frame */ | ||
| 185 | long seqRead_Index; /* Amount of data that has been already read */ | ||
| 186 | |||
| 187 | void *user; /* Additional data that user may need */ | ||
| 188 | }; | ||
| 189 | |||
| 190 | /* Statistics that can be overlaid on screen */ | ||
| 191 | struct usbvideo_statistics { | ||
| 192 | unsigned long frame_num; /* Sequential number of the frame */ | ||
| 193 | unsigned long urb_count; /* How many URBs we received so far */ | ||
| 194 | unsigned long urb_length; /* Length of last URB */ | ||
| 195 | unsigned long data_count; /* How many bytes we received */ | ||
| 196 | unsigned long header_count; /* How many frame headers we found */ | ||
| 197 | unsigned long iso_skip_count; /* How many empty ISO packets received */ | ||
| 198 | unsigned long iso_err_count; /* How many bad ISO packets received */ | ||
| 199 | }; | ||
| 200 | |||
| 201 | struct usbvideo; | ||
| 202 | |||
| 203 | struct uvd { | ||
| 204 | struct video_device vdev; /* Must be the first field! */ | ||
| 205 | struct usb_device *dev; | ||
| 206 | struct usbvideo *handle; /* Points back to the struct usbvideo */ | ||
| 207 | void *user_data; /* Camera-dependent data */ | ||
| 208 | int user_size; /* Size of that camera-dependent data */ | ||
| 209 | int debug; /* Debug level for usbvideo */ | ||
| 210 | unsigned char iface; /* Video interface number */ | ||
| 211 | unsigned char video_endp; | ||
| 212 | unsigned char ifaceAltActive; | ||
| 213 | unsigned char ifaceAltInactive; /* Alt settings */ | ||
| 214 | unsigned long flags; /* FLAGS_USBVIDEO_xxx */ | ||
| 215 | unsigned long paletteBits; /* Which palettes we accept? */ | ||
| 216 | unsigned short defaultPalette; /* What palette to use for read() */ | ||
| 217 | struct mutex lock; | ||
| 218 | int user; /* user count for exclusive use */ | ||
| 219 | |||
| 220 | videosize_t videosize; /* Current setting */ | ||
| 221 | videosize_t canvas; /* This is the width,height of the V4L canvas */ | ||
| 222 | int max_frame_size; /* Bytes in one video frame */ | ||
| 223 | |||
| 224 | int uvd_used; /* Is this structure in use? */ | ||
| 225 | int streaming; /* Are we streaming Isochronous? */ | ||
| 226 | int grabbing; /* Are we grabbing? */ | ||
| 227 | int settingsAdjusted; /* Have we adjusted contrast etc.? */ | ||
| 228 | int last_error; /* What calamity struck us? */ | ||
| 229 | |||
| 230 | char *fbuf; /* Videodev buffer area */ | ||
| 231 | int fbuf_size; /* Videodev buffer size */ | ||
| 232 | |||
| 233 | int curframe; | ||
| 234 | int iso_packet_len; /* Videomode-dependent, saves bus bandwidth */ | ||
| 235 | |||
| 236 | struct RingQueue dp; /* Isoc data pump */ | ||
| 237 | struct usbvideo_frame frame[USBVIDEO_NUMFRAMES]; | ||
| 238 | struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF]; | ||
| 239 | |||
| 240 | volatile int remove_pending; /* If set then about to exit */ | ||
| 241 | |||
| 242 | struct video_picture vpic, vpic_old; /* Picture settings */ | ||
| 243 | struct video_capability vcap; /* Video capabilities */ | ||
| 244 | struct video_channel vchan; /* May be used for tuner support */ | ||
| 245 | struct usbvideo_statistics stats; | ||
| 246 | char videoName[32]; /* Holds name like "video7" */ | ||
| 247 | }; | ||
| 248 | |||
| 249 | /* | ||
| 250 | * usbvideo callbacks (virtual methods). They are set when usbvideo | ||
| 251 | * services are registered. All of these default to NULL, except those | ||
| 252 | * that default to usbvideo-provided methods. | ||
| 253 | */ | ||
| 254 | struct usbvideo_cb { | ||
| 255 | int (*probe)(struct usb_interface *, const struct usb_device_id *); | ||
| 256 | void (*userFree)(struct uvd *); | ||
| 257 | void (*disconnect)(struct usb_interface *); | ||
| 258 | int (*setupOnOpen)(struct uvd *); | ||
| 259 | void (*videoStart)(struct uvd *); | ||
| 260 | void (*videoStop)(struct uvd *); | ||
| 261 | void (*processData)(struct uvd *, struct usbvideo_frame *); | ||
| 262 | void (*postProcess)(struct uvd *, struct usbvideo_frame *); | ||
| 263 | void (*adjustPicture)(struct uvd *); | ||
| 264 | int (*getFPS)(struct uvd *); | ||
| 265 | int (*overlayHook)(struct uvd *, struct usbvideo_frame *); | ||
| 266 | int (*getFrame)(struct uvd *, int); | ||
| 267 | int (*startDataPump)(struct uvd *uvd); | ||
| 268 | void (*stopDataPump)(struct uvd *uvd); | ||
| 269 | int (*setVideoMode)(struct uvd *uvd, struct video_window *vw); | ||
| 270 | }; | ||
| 271 | |||
| 272 | struct usbvideo { | ||
| 273 | int num_cameras; /* As allocated */ | ||
| 274 | struct usb_driver usbdrv; /* Interface to the USB stack */ | ||
| 275 | char drvName[80]; /* Driver name */ | ||
| 276 | struct mutex lock; /* Mutex protecting camera structures */ | ||
| 277 | struct usbvideo_cb cb; /* Table of callbacks (virtual methods) */ | ||
| 278 | struct video_device vdt; /* Video device template */ | ||
| 279 | struct uvd *cam; /* Array of camera structures */ | ||
| 280 | struct module *md_module; /* Minidriver module */ | ||
| 281 | }; | ||
| 282 | |||
| 283 | |||
| 284 | /* | ||
| 285 | * This macro retrieves callback address from the struct uvd object. | ||
| 286 | * No validity checks are done here, so be sure to check the | ||
| 287 | * callback beforehand with VALID_CALLBACK. | ||
| 288 | */ | ||
| 289 | #define GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName) | ||
| 290 | |||
| 291 | /* | ||
| 292 | * This macro returns either callback pointer or NULL. This is safe | ||
| 293 | * macro, meaning that most of components of data structures involved | ||
| 294 | * may be NULL - this only results in NULL being returned. You may | ||
| 295 | * wish to use this macro to make sure that the callback is callable. | ||
| 296 | * However keep in mind that those checks take time. | ||
| 297 | */ | ||
| 298 | #define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \ | ||
| 299 | ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL) | ||
| 300 | |||
| 301 | int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len); | ||
| 302 | int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n); | ||
| 303 | void RingQueue_WakeUpInterruptible(struct RingQueue *rq); | ||
| 304 | void RingQueue_Flush(struct RingQueue *rq); | ||
| 305 | |||
| 306 | static inline int RingQueue_GetLength(const struct RingQueue *rq) | ||
| 307 | { | ||
| 308 | return (rq->wi - rq->ri + rq->length) & (rq->length-1); | ||
| 309 | } | ||
| 310 | |||
| 311 | static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq) | ||
| 312 | { | ||
| 313 | return rq->length - RingQueue_GetLength(rq); | ||
| 314 | } | ||
| 315 | |||
| 316 | void usbvideo_DrawLine( | ||
| 317 | struct usbvideo_frame *frame, | ||
| 318 | int x1, int y1, | ||
| 319 | int x2, int y2, | ||
| 320 | unsigned char cr, unsigned char cg, unsigned char cb); | ||
| 321 | void usbvideo_HexDump(const unsigned char *data, int len); | ||
| 322 | void usbvideo_SayAndWait(const char *what); | ||
| 323 | void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode); | ||
| 324 | |||
| 325 | /* Memory allocation routines */ | ||
| 326 | unsigned long usbvideo_kvirt_to_pa(unsigned long adr); | ||
| 327 | |||
| 328 | int usbvideo_register( | ||
| 329 | struct usbvideo **pCams, | ||
| 330 | const int num_cams, | ||
| 331 | const int num_extra, | ||
| 332 | const char *driverName, | ||
| 333 | const struct usbvideo_cb *cbTable, | ||
| 334 | struct module *md, | ||
| 335 | const struct usb_device_id *id_table); | ||
| 336 | struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams); | ||
| 337 | int usbvideo_RegisterVideoDevice(struct uvd *uvd); | ||
| 338 | void usbvideo_Deregister(struct usbvideo **uvt); | ||
| 339 | |||
| 340 | int usbvideo_v4l_initialize(struct video_device *dev); | ||
| 341 | |||
| 342 | void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame); | ||
| 343 | |||
| 344 | /* | ||
| 345 | * This code performs bounds checking - use it when working with | ||
| 346 | * new formats, or else you may get oopses all over the place. | ||
| 347 | * If pixel falls out of bounds then it gets shoved back (as close | ||
| 348 | * to place of offence as possible) and is painted bright red. | ||
| 349 | * | ||
| 350 | * There are two important concepts: frame width, height and | ||
| 351 | * V4L canvas width, height. The former is the area requested by | ||
| 352 | * the application -for this very frame-. The latter is the largest | ||
| 353 | * possible frame that we can serve (we advertise that via V4L ioctl). | ||
| 354 | * The frame data is expected to be formatted as lines of length | ||
| 355 | * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines. | ||
| 356 | */ | ||
| 357 | static inline void RGB24_PUTPIXEL( | ||
| 358 | struct usbvideo_frame *fr, | ||
| 359 | int ix, int iy, | ||
| 360 | unsigned char vr, | ||
| 361 | unsigned char vg, | ||
| 362 | unsigned char vb) | ||
| 363 | { | ||
| 364 | register unsigned char *pf; | ||
| 365 | int limiter = 0, mx, my; | ||
| 366 | mx = ix; | ||
| 367 | my = iy; | ||
| 368 | if (mx < 0) { | ||
| 369 | mx=0; | ||
| 370 | limiter++; | ||
| 371 | } else if (mx >= VIDEOSIZE_X((fr)->request)) { | ||
| 372 | mx= VIDEOSIZE_X((fr)->request) - 1; | ||
| 373 | limiter++; | ||
| 374 | } | ||
| 375 | if (my < 0) { | ||
| 376 | my = 0; | ||
| 377 | limiter++; | ||
| 378 | } else if (my >= VIDEOSIZE_Y((fr)->request)) { | ||
| 379 | my = VIDEOSIZE_Y((fr)->request) - 1; | ||
| 380 | limiter++; | ||
| 381 | } | ||
| 382 | pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix)); | ||
| 383 | if (limiter) { | ||
| 384 | *pf++ = 0; | ||
| 385 | *pf++ = 0; | ||
| 386 | *pf++ = 0xFF; | ||
| 387 | } else { | ||
| 388 | *pf++ = (vb); | ||
| 389 | *pf++ = (vg); | ||
| 390 | *pf++ = (vr); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 394 | #endif /* usbvideo_h */ | ||
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c deleted file mode 100644 index 1d06e53ec7c5..000000000000 --- a/drivers/usb/media/vicam.c +++ /dev/null | |||
| @@ -1,1411 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * USB ViCam WebCam driver | ||
| 3 | * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), | ||
| 4 | * Christopher L Cheney (ccheney@cheney.cx), | ||
| 5 | * Pavel Machek (pavel@suse.cz), | ||
| 6 | * John Tyner (jtyner@cs.ucr.edu), | ||
| 7 | * Monroe Williams (monroe@pobox.com) | ||
| 8 | * | ||
| 9 | * Supports 3COM HomeConnect PC Digital WebCam | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License as published by | ||
| 13 | * the Free Software Foundation; either version 2 of the License, or | ||
| 14 | * (at your option) any later version. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | * GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License | ||
| 22 | * along with this program; if not, write to the Free Software | ||
| 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 24 | * | ||
| 25 | * This source code is based heavily on the CPiA webcam driver which was | ||
| 26 | * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt | ||
| 27 | * | ||
| 28 | * Portions of this code were also copied from usbvideo.c | ||
| 29 | * | ||
| 30 | * Special thanks to the the whole team at Sourceforge for help making | ||
| 31 | * this driver become a reality. Notably: | ||
| 32 | * Andy Armstrong who reverse engineered the color encoding and | ||
| 33 | * Pavel Machek and Chris Cheney who worked on reverse engineering the | ||
| 34 | * camera controls and wrote the first generation driver. | ||
| 35 | */ | ||
| 36 | |||
| 37 | #include <linux/kernel.h> | ||
| 38 | #include <linux/module.h> | ||
| 39 | #include <linux/init.h> | ||
| 40 | #include <linux/videodev.h> | ||
| 41 | #include <linux/usb.h> | ||
| 42 | #include <linux/vmalloc.h> | ||
| 43 | #include <linux/slab.h> | ||
| 44 | #include <linux/proc_fs.h> | ||
| 45 | #include <linux/mutex.h> | ||
| 46 | #include "usbvideo.h" | ||
| 47 | |||
| 48 | // #define VICAM_DEBUG | ||
| 49 | |||
| 50 | #ifdef VICAM_DEBUG | ||
| 51 | #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args) | ||
| 52 | #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) | ||
| 53 | #else | ||
| 54 | #define DBG(fmn,args...) do {} while(0) | ||
| 55 | #endif | ||
| 56 | |||
| 57 | #define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" | ||
| 58 | #define DRIVER_DESC "ViCam WebCam Driver" | ||
| 59 | |||
| 60 | /* Define these values to match your device */ | ||
| 61 | #define USB_VICAM_VENDOR_ID 0x04c1 | ||
| 62 | #define USB_VICAM_PRODUCT_ID 0x009d | ||
| 63 | |||
| 64 | #define VICAM_BYTES_PER_PIXEL 3 | ||
| 65 | #define VICAM_MAX_READ_SIZE (512*242+128) | ||
| 66 | #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) | ||
| 67 | #define VICAM_FRAMES 2 | ||
| 68 | |||
| 69 | #define VICAM_HEADER_SIZE 64 | ||
| 70 | |||
| 71 | #define clamp( x, l, h ) max_t( __typeof__( x ), \ | ||
| 72 | ( l ), \ | ||
| 73 | min_t( __typeof__( x ), \ | ||
| 74 | ( h ), \ | ||
| 75 | ( x ) ) ) | ||
| 76 | |||
| 77 | /* Not sure what all the bytes in these char | ||
| 78 | * arrays do, but they're necessary to make | ||
| 79 | * the camera work. | ||
| 80 | */ | ||
| 81 | |||
| 82 | static unsigned char setup1[] = { | ||
| 83 | 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67, | ||
| 84 | 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00, | ||
| 85 | 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17, | ||
| 86 | 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00, | ||
| 87 | 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 | ||
| 88 | }; | ||
| 89 | |||
| 90 | static unsigned char setup2[] = { | ||
| 91 | 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00, | ||
| 92 | 0x00, 0x00 | ||
| 93 | }; | ||
| 94 | |||
| 95 | static unsigned char setup3[] = { | ||
| 96 | 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00 | ||
| 97 | }; | ||
| 98 | |||
| 99 | static unsigned char setup4[] = { | ||
| 100 | 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07, | ||
| 101 | 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00, | ||
| 102 | 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00, | ||
| 103 | 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07, | ||
| 104 | 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00, | ||
| 105 | 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00, | ||
| 106 | 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07, | ||
| 107 | 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, | ||
| 108 | 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0, | ||
| 109 | 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07, | ||
| 110 | 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00, | ||
| 111 | 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0, | ||
| 112 | 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1, | ||
| 113 | 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09, | ||
| 114 | 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, | ||
| 115 | 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF, | ||
| 116 | 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02, | ||
| 117 | 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, | ||
| 118 | 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF, | ||
| 119 | 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00, | ||
| 120 | 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00, | ||
| 121 | 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05, | ||
| 122 | 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA, | ||
| 123 | 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06, | ||
| 124 | 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF, | ||
| 125 | 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05, | ||
| 126 | 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01, | ||
| 127 | 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09, | ||
| 128 | 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06, | ||
| 129 | 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05, | ||
| 130 | 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA, | ||
| 131 | 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05, | ||
| 132 | 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, | ||
| 133 | 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00, | ||
| 134 | 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF, | ||
| 135 | 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00, | ||
| 136 | 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0, | ||
| 137 | 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06, | ||
| 138 | 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00, | ||
| 139 | 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07, | ||
| 140 | 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF, | ||
| 141 | 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00, | ||
| 142 | 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, | ||
| 143 | 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57, | ||
| 144 | 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57, | ||
| 145 | 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00, | ||
| 146 | 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0, | ||
| 147 | 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B, | ||
| 148 | 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06, | ||
| 149 | 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, | ||
| 150 | 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E, | ||
| 151 | 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, | ||
| 152 | 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, | ||
| 153 | 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00, | ||
| 154 | 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, | ||
| 155 | 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF, | ||
| 156 | 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0, | ||
| 157 | 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, | ||
| 158 | 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05, | ||
| 159 | 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF, | ||
| 160 | 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0, | ||
| 161 | 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07, | ||
| 162 | 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07, | ||
| 163 | 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF, | ||
| 164 | 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF, | ||
| 165 | 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, | ||
| 166 | 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, | ||
| 167 | 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1, | ||
| 168 | 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67, | ||
| 169 | 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00, | ||
| 170 | 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07, | ||
| 171 | 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07, | ||
| 172 | 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07, | ||
| 173 | 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00, | ||
| 174 | 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06, | ||
| 175 | 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67, | ||
| 176 | 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8, | ||
| 177 | 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, | ||
| 178 | 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF, | ||
| 179 | 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02, | ||
| 180 | 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, | ||
| 181 | 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06, | ||
| 182 | 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05, | ||
| 183 | 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, | ||
| 184 | 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00, | ||
| 185 | 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06, | ||
| 186 | 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, | ||
| 187 | 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05, | ||
| 188 | 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05, | ||
| 189 | 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, | ||
| 190 | 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04, | ||
| 191 | 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF, | ||
| 192 | 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06, | ||
| 193 | 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, | ||
| 194 | 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00, | ||
| 195 | 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05, | ||
| 196 | 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07, | ||
| 197 | 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07, | ||
| 198 | 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07, | ||
| 199 | 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF, | ||
| 200 | 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07, | ||
| 201 | 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06, | ||
| 202 | 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05, | ||
| 203 | 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07, | ||
| 204 | 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00, | ||
| 205 | 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00, | ||
| 206 | 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77, | ||
| 207 | 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04, | ||
| 208 | 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0, | ||
| 209 | 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1, | ||
| 210 | 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07, | ||
| 211 | 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF, | ||
| 212 | 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, | ||
| 213 | 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, | ||
| 214 | 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, | ||
| 215 | 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77, | ||
| 216 | 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1, | ||
| 217 | 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07, | ||
| 218 | 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, | ||
| 219 | 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06, | ||
| 220 | 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, | ||
| 221 | 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, | ||
| 222 | 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07, | ||
| 223 | 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00, | ||
| 224 | 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00, | ||
| 225 | 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, | ||
| 226 | 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, | ||
| 227 | 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F, | ||
| 228 | 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00, | ||
| 229 | 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00, | ||
| 230 | 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA, | ||
| 231 | 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, | ||
| 232 | 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06, | ||
| 233 | 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF, | ||
| 234 | 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B, | ||
| 235 | 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, | ||
| 236 | 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09, | ||
| 237 | 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05, | ||
| 238 | 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07, | ||
| 239 | 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00, | ||
| 240 | 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF, | ||
| 241 | 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05, | ||
| 242 | 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00, | ||
| 243 | 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00, | ||
| 244 | 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05, | ||
| 245 | 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05, | ||
| 246 | 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00, | ||
| 247 | 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF, | ||
| 248 | 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09, | ||
| 249 | 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, | ||
| 250 | 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1, | ||
| 251 | 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00, | ||
| 252 | 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05, | ||
| 253 | 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00, | ||
| 254 | 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00, | ||
| 255 | 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05, | ||
| 256 | 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0, | ||
| 257 | 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67, | ||
| 258 | 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87, | ||
| 259 | 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9, | ||
| 260 | 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1, | ||
| 261 | 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF, | ||
| 262 | 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00, | ||
| 263 | 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0, | ||
| 264 | 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87, | ||
| 265 | 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, | ||
| 266 | 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67, | ||
| 267 | 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, | ||
| 268 | 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, | ||
| 269 | 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67, | ||
| 270 | 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, | ||
| 271 | 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, | ||
| 272 | 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, | ||
| 273 | 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00, | ||
| 274 | 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF, | ||
| 275 | 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, | ||
| 276 | 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67, | ||
| 277 | 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09, | ||
| 278 | 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, | ||
| 279 | 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA, | ||
| 280 | 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87, | ||
| 281 | 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07, | ||
| 282 | 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, | ||
| 283 | 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07, | ||
| 284 | 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, | ||
| 285 | 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02, | ||
| 286 | 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, | ||
| 287 | 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
| 288 | 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00, | ||
| 289 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 290 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 291 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 292 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 293 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 294 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 295 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 296 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 297 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 298 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 299 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 300 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 301 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 302 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 303 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 304 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 305 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 306 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 307 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 308 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 309 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 310 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 311 | }; | ||
| 312 | |||
| 313 | static unsigned char setup5[] = { | ||
| 314 | 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00, | ||
| 315 | 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, | ||
| 316 | 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00, | ||
| 317 | 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00, | ||
| 318 | 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, | ||
| 319 | 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00, | ||
| 320 | 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00, | ||
| 321 | 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01, | ||
| 322 | 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01, | ||
| 323 | 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01, | ||
| 324 | 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01, | ||
| 325 | 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01, | ||
| 326 | 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01, | ||
| 327 | 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01, | ||
| 328 | 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01, | ||
| 329 | 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02, | ||
| 330 | 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02, | ||
| 331 | 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02, | ||
| 332 | 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02, | ||
| 333 | 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02, | ||
| 334 | 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02, | ||
| 335 | 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02, | ||
| 336 | 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02, | ||
| 337 | 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03, | ||
| 338 | 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03, | ||
| 339 | 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03, | ||
| 340 | 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03, | ||
| 341 | 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03, | ||
| 342 | 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03, | ||
| 343 | 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03, | ||
| 344 | 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04, | ||
| 345 | 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04, | ||
| 346 | 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04, | ||
| 347 | 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04, | ||
| 348 | 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04, | ||
| 349 | 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04, | ||
| 350 | 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04, | ||
| 351 | 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05, | ||
| 352 | 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 | ||
| 353 | }; | ||
| 354 | |||
| 355 | /* rvmalloc / rvfree copied from usbvideo.c | ||
| 356 | * | ||
| 357 | * Not sure why these are not yet non-statics which I can reference through | ||
| 358 | * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime | ||
| 359 | * in the future. | ||
| 360 | * | ||
| 361 | */ | ||
| 362 | static void *rvmalloc(unsigned long size) | ||
| 363 | { | ||
| 364 | void *mem; | ||
| 365 | unsigned long adr; | ||
| 366 | |||
| 367 | size = PAGE_ALIGN(size); | ||
| 368 | mem = vmalloc_32(size); | ||
| 369 | if (!mem) | ||
| 370 | return NULL; | ||
| 371 | |||
| 372 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
| 373 | adr = (unsigned long) mem; | ||
| 374 | while (size > 0) { | ||
| 375 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
| 376 | adr += PAGE_SIZE; | ||
| 377 | size -= PAGE_SIZE; | ||
| 378 | } | ||
| 379 | |||
| 380 | return mem; | ||
| 381 | } | ||
| 382 | |||
| 383 | static void rvfree(void *mem, unsigned long size) | ||
| 384 | { | ||
| 385 | unsigned long adr; | ||
| 386 | |||
| 387 | if (!mem) | ||
| 388 | return; | ||
| 389 | |||
| 390 | adr = (unsigned long) mem; | ||
| 391 | while ((long) size > 0) { | ||
| 392 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
| 393 | adr += PAGE_SIZE; | ||
| 394 | size -= PAGE_SIZE; | ||
| 395 | } | ||
| 396 | vfree(mem); | ||
| 397 | } | ||
| 398 | |||
| 399 | struct vicam_camera { | ||
| 400 | u16 shutter_speed; // capture shutter speed | ||
| 401 | u16 gain; // capture gain | ||
| 402 | |||
| 403 | u8 *raw_image; // raw data captured from the camera | ||
| 404 | u8 *framebuf; // processed data in RGB24 format | ||
| 405 | u8 *cntrlbuf; // area used to send control msgs | ||
| 406 | |||
| 407 | struct video_device vdev; // v4l video device | ||
| 408 | struct usb_device *udev; // usb device | ||
| 409 | |||
| 410 | /* guard against simultaneous accesses to the camera */ | ||
| 411 | struct mutex cam_lock; | ||
| 412 | |||
| 413 | int is_initialized; | ||
| 414 | u8 open_count; | ||
| 415 | u8 bulkEndpoint; | ||
| 416 | int needsDummyRead; | ||
| 417 | |||
| 418 | #if defined(CONFIG_VIDEO_PROC_FS) | ||
| 419 | struct proc_dir_entry *proc_dir; | ||
| 420 | #endif | ||
| 421 | |||
| 422 | }; | ||
| 423 | |||
| 424 | static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); | ||
| 425 | static void vicam_disconnect(struct usb_interface *intf); | ||
| 426 | static void read_frame(struct vicam_camera *cam, int framenum); | ||
| 427 | static void vicam_decode_color(const u8 *, u8 *); | ||
| 428 | |||
| 429 | static int __send_control_msg(struct vicam_camera *cam, | ||
| 430 | u8 request, | ||
| 431 | u16 value, | ||
| 432 | u16 index, | ||
| 433 | unsigned char *cp, | ||
| 434 | u16 size) | ||
| 435 | { | ||
| 436 | int status; | ||
| 437 | |||
| 438 | /* cp must be memory that has been allocated by kmalloc */ | ||
| 439 | |||
| 440 | status = usb_control_msg(cam->udev, | ||
| 441 | usb_sndctrlpipe(cam->udev, 0), | ||
| 442 | request, | ||
| 443 | USB_DIR_OUT | USB_TYPE_VENDOR | | ||
| 444 | USB_RECIP_DEVICE, value, index, | ||
| 445 | cp, size, 1000); | ||
| 446 | |||
| 447 | status = min(status, 0); | ||
| 448 | |||
| 449 | if (status < 0) { | ||
| 450 | printk(KERN_INFO "Failed sending control message, error %d.\n", | ||
| 451 | status); | ||
| 452 | } | ||
| 453 | |||
| 454 | return status; | ||
| 455 | } | ||
| 456 | |||
| 457 | static int send_control_msg(struct vicam_camera *cam, | ||
| 458 | u8 request, | ||
| 459 | u16 value, | ||
| 460 | u16 index, | ||
| 461 | unsigned char *cp, | ||
| 462 | u16 size) | ||
| 463 | { | ||
| 464 | int status = -ENODEV; | ||
| 465 | mutex_lock(&cam->cam_lock); | ||
| 466 | if (cam->udev) { | ||
| 467 | status = __send_control_msg(cam, request, value, | ||
| 468 | index, cp, size); | ||
| 469 | } | ||
| 470 | mutex_unlock(&cam->cam_lock); | ||
| 471 | return status; | ||
| 472 | } | ||
| 473 | static int | ||
| 474 | initialize_camera(struct vicam_camera *cam) | ||
| 475 | { | ||
| 476 | const struct { | ||
| 477 | u8 *data; | ||
| 478 | u32 size; | ||
| 479 | } firmware[] = { | ||
| 480 | { .data = setup1, .size = sizeof(setup1) }, | ||
| 481 | { .data = setup2, .size = sizeof(setup2) }, | ||
| 482 | { .data = setup3, .size = sizeof(setup3) }, | ||
| 483 | { .data = setup4, .size = sizeof(setup4) }, | ||
| 484 | { .data = setup5, .size = sizeof(setup5) }, | ||
| 485 | { .data = setup3, .size = sizeof(setup3) }, | ||
| 486 | { .data = NULL, .size = 0 } | ||
| 487 | }; | ||
| 488 | |||
| 489 | int err, i; | ||
| 490 | |||
| 491 | for (i = 0, err = 0; firmware[i].data && !err; i++) { | ||
| 492 | memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size); | ||
| 493 | |||
| 494 | err = send_control_msg(cam, 0xff, 0, 0, | ||
| 495 | cam->cntrlbuf, firmware[i].size); | ||
| 496 | } | ||
| 497 | |||
| 498 | return err; | ||
| 499 | } | ||
| 500 | |||
| 501 | static int | ||
| 502 | set_camera_power(struct vicam_camera *cam, int state) | ||
| 503 | { | ||
| 504 | int status; | ||
| 505 | |||
| 506 | if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0) | ||
| 507 | return status; | ||
| 508 | |||
| 509 | if (state) { | ||
| 510 | send_control_msg(cam, 0x55, 1, 0, NULL, 0); | ||
| 511 | } | ||
| 512 | |||
| 513 | return 0; | ||
| 514 | } | ||
| 515 | |||
| 516 | static int | ||
| 517 | vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg) | ||
| 518 | { | ||
| 519 | void __user *user_arg = (void __user *)arg; | ||
| 520 | struct vicam_camera *cam = file->private_data; | ||
| 521 | int retval = 0; | ||
| 522 | |||
| 523 | if (!cam) | ||
| 524 | return -ENODEV; | ||
| 525 | |||
| 526 | switch (ioctlnr) { | ||
| 527 | /* query capabilities */ | ||
| 528 | case VIDIOCGCAP: | ||
| 529 | { | ||
| 530 | struct video_capability b; | ||
| 531 | |||
| 532 | DBG("VIDIOCGCAP\n"); | ||
| 533 | memset(&b, 0, sizeof(b)); | ||
| 534 | strcpy(b.name, "ViCam-based Camera"); | ||
| 535 | b.type = VID_TYPE_CAPTURE; | ||
| 536 | b.channels = 1; | ||
| 537 | b.audios = 0; | ||
| 538 | b.maxwidth = 320; /* VIDEOSIZE_CIF */ | ||
| 539 | b.maxheight = 240; | ||
| 540 | b.minwidth = 320; /* VIDEOSIZE_48_48 */ | ||
| 541 | b.minheight = 240; | ||
| 542 | |||
| 543 | if (copy_to_user(user_arg, &b, sizeof(b))) | ||
| 544 | retval = -EFAULT; | ||
| 545 | |||
| 546 | break; | ||
| 547 | } | ||
| 548 | /* get/set video source - we are a camera and nothing else */ | ||
| 549 | case VIDIOCGCHAN: | ||
| 550 | { | ||
| 551 | struct video_channel v; | ||
| 552 | |||
| 553 | DBG("VIDIOCGCHAN\n"); | ||
| 554 | if (copy_from_user(&v, user_arg, sizeof(v))) { | ||
| 555 | retval = -EFAULT; | ||
| 556 | break; | ||
| 557 | } | ||
| 558 | if (v.channel != 0) { | ||
| 559 | retval = -EINVAL; | ||
| 560 | break; | ||
| 561 | } | ||
| 562 | |||
| 563 | v.channel = 0; | ||
| 564 | strcpy(v.name, "Camera"); | ||
| 565 | v.tuners = 0; | ||
| 566 | v.flags = 0; | ||
| 567 | v.type = VIDEO_TYPE_CAMERA; | ||
| 568 | v.norm = 0; | ||
| 569 | |||
| 570 | if (copy_to_user(user_arg, &v, sizeof(v))) | ||
| 571 | retval = -EFAULT; | ||
| 572 | break; | ||
| 573 | } | ||
| 574 | |||
| 575 | case VIDIOCSCHAN: | ||
| 576 | { | ||
| 577 | int v; | ||
| 578 | |||
| 579 | if (copy_from_user(&v, user_arg, sizeof(v))) | ||
| 580 | retval = -EFAULT; | ||
| 581 | DBG("VIDIOCSCHAN %d\n", v); | ||
| 582 | |||
| 583 | if (retval == 0 && v != 0) | ||
| 584 | retval = -EINVAL; | ||
| 585 | |||
| 586 | break; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* image properties */ | ||
| 590 | case VIDIOCGPICT: | ||
| 591 | { | ||
| 592 | struct video_picture vp; | ||
| 593 | DBG("VIDIOCGPICT\n"); | ||
| 594 | memset(&vp, 0, sizeof (struct video_picture)); | ||
| 595 | vp.brightness = cam->gain << 8; | ||
| 596 | vp.depth = 24; | ||
| 597 | vp.palette = VIDEO_PALETTE_RGB24; | ||
| 598 | if (copy_to_user(user_arg, &vp, sizeof (struct video_picture))) | ||
| 599 | retval = -EFAULT; | ||
| 600 | break; | ||
| 601 | } | ||
| 602 | |||
| 603 | case VIDIOCSPICT: | ||
| 604 | { | ||
| 605 | struct video_picture vp; | ||
| 606 | |||
| 607 | if (copy_from_user(&vp, user_arg, sizeof(vp))) { | ||
| 608 | retval = -EFAULT; | ||
| 609 | break; | ||
| 610 | } | ||
| 611 | |||
| 612 | DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth, | ||
| 613 | vp.palette); | ||
| 614 | |||
| 615 | cam->gain = vp.brightness >> 8; | ||
| 616 | |||
| 617 | if (vp.depth != 24 | ||
| 618 | || vp.palette != VIDEO_PALETTE_RGB24) | ||
| 619 | retval = -EINVAL; | ||
| 620 | |||
| 621 | break; | ||
| 622 | } | ||
| 623 | |||
| 624 | /* get/set capture window */ | ||
| 625 | case VIDIOCGWIN: | ||
| 626 | { | ||
| 627 | struct video_window vw; | ||
| 628 | vw.x = 0; | ||
| 629 | vw.y = 0; | ||
| 630 | vw.width = 320; | ||
| 631 | vw.height = 240; | ||
| 632 | vw.chromakey = 0; | ||
| 633 | vw.flags = 0; | ||
| 634 | vw.clips = NULL; | ||
| 635 | vw.clipcount = 0; | ||
| 636 | |||
| 637 | DBG("VIDIOCGWIN\n"); | ||
| 638 | |||
| 639 | if (copy_to_user(user_arg, (void *)&vw, sizeof(vw))) | ||
| 640 | retval = -EFAULT; | ||
| 641 | |||
| 642 | // I'm not sure what the deal with a capture window is, it is very poorly described | ||
| 643 | // in the doc. So I won't support it now. | ||
| 644 | break; | ||
| 645 | } | ||
| 646 | |||
| 647 | case VIDIOCSWIN: | ||
| 648 | { | ||
| 649 | |||
| 650 | struct video_window vw; | ||
| 651 | |||
| 652 | if (copy_from_user(&vw, user_arg, sizeof(vw))) { | ||
| 653 | retval = -EFAULT; | ||
| 654 | break; | ||
| 655 | } | ||
| 656 | |||
| 657 | DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height); | ||
| 658 | |||
| 659 | if ( vw.width != 320 || vw.height != 240 ) | ||
| 660 | retval = -EFAULT; | ||
| 661 | |||
| 662 | break; | ||
| 663 | } | ||
| 664 | |||
| 665 | /* mmap interface */ | ||
| 666 | case VIDIOCGMBUF: | ||
| 667 | { | ||
| 668 | struct video_mbuf vm; | ||
| 669 | int i; | ||
| 670 | |||
| 671 | DBG("VIDIOCGMBUF\n"); | ||
| 672 | memset(&vm, 0, sizeof (vm)); | ||
| 673 | vm.size = | ||
| 674 | VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; | ||
| 675 | vm.frames = VICAM_FRAMES; | ||
| 676 | for (i = 0; i < VICAM_FRAMES; i++) | ||
| 677 | vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; | ||
| 678 | |||
| 679 | if (copy_to_user(user_arg, (void *)&vm, sizeof(vm))) | ||
| 680 | retval = -EFAULT; | ||
| 681 | |||
| 682 | break; | ||
| 683 | } | ||
| 684 | |||
| 685 | case VIDIOCMCAPTURE: | ||
| 686 | { | ||
| 687 | struct video_mmap vm; | ||
| 688 | // int video_size; | ||
| 689 | |||
| 690 | if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) { | ||
| 691 | retval = -EFAULT; | ||
| 692 | break; | ||
| 693 | } | ||
| 694 | |||
| 695 | DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); | ||
| 696 | |||
| 697 | if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) | ||
| 698 | retval = -EINVAL; | ||
| 699 | |||
| 700 | // in theory right here we'd start the image capturing | ||
| 701 | // (fill in a bulk urb and submit it asynchronously) | ||
| 702 | // | ||
| 703 | // Instead we're going to do a total hack job for now and | ||
| 704 | // retrieve the frame in VIDIOCSYNC | ||
| 705 | |||
| 706 | break; | ||
| 707 | } | ||
| 708 | |||
| 709 | case VIDIOCSYNC: | ||
| 710 | { | ||
| 711 | int frame; | ||
| 712 | |||
| 713 | if (copy_from_user((void *)&frame, user_arg, sizeof(int))) { | ||
| 714 | retval = -EFAULT; | ||
| 715 | break; | ||
| 716 | } | ||
| 717 | DBG("VIDIOCSYNC: %d\n", frame); | ||
| 718 | |||
| 719 | read_frame(cam, frame); | ||
| 720 | vicam_decode_color(cam->raw_image, | ||
| 721 | cam->framebuf + | ||
| 722 | frame * VICAM_MAX_FRAME_SIZE ); | ||
| 723 | |||
| 724 | break; | ||
| 725 | } | ||
| 726 | |||
| 727 | /* pointless to implement overlay with this camera */ | ||
| 728 | case VIDIOCCAPTURE: | ||
| 729 | case VIDIOCGFBUF: | ||
| 730 | case VIDIOCSFBUF: | ||
| 731 | case VIDIOCKEY: | ||
| 732 | retval = -EINVAL; | ||
| 733 | break; | ||
| 734 | |||
| 735 | /* tuner interface - we have none */ | ||
| 736 | case VIDIOCGTUNER: | ||
| 737 | case VIDIOCSTUNER: | ||
| 738 | case VIDIOCGFREQ: | ||
| 739 | case VIDIOCSFREQ: | ||
| 740 | retval = -EINVAL; | ||
| 741 | break; | ||
| 742 | |||
| 743 | /* audio interface - we have none */ | ||
| 744 | case VIDIOCGAUDIO: | ||
| 745 | case VIDIOCSAUDIO: | ||
| 746 | retval = -EINVAL; | ||
| 747 | break; | ||
| 748 | default: | ||
| 749 | retval = -ENOIOCTLCMD; | ||
| 750 | break; | ||
| 751 | } | ||
| 752 | |||
| 753 | return retval; | ||
| 754 | } | ||
| 755 | |||
| 756 | static int | ||
| 757 | vicam_open(struct inode *inode, struct file *file) | ||
| 758 | { | ||
| 759 | struct video_device *dev = video_devdata(file); | ||
| 760 | struct vicam_camera *cam = | ||
| 761 | (struct vicam_camera *) dev->priv; | ||
| 762 | DBG("open\n"); | ||
| 763 | |||
| 764 | if (!cam) { | ||
| 765 | printk(KERN_ERR | ||
| 766 | "vicam video_device improperly initialized"); | ||
| 767 | return -EINVAL; | ||
| 768 | } | ||
| 769 | |||
| 770 | /* the videodev_lock held above us protects us from | ||
| 771 | * simultaneous opens...for now. we probably shouldn't | ||
| 772 | * rely on this fact forever. | ||
| 773 | */ | ||
| 774 | |||
| 775 | if (cam->open_count > 0) { | ||
| 776 | printk(KERN_INFO | ||
| 777 | "vicam_open called on already opened camera"); | ||
| 778 | return -EBUSY; | ||
| 779 | } | ||
| 780 | |||
| 781 | cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); | ||
| 782 | if (!cam->raw_image) { | ||
| 783 | return -ENOMEM; | ||
| 784 | } | ||
| 785 | |||
| 786 | cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); | ||
| 787 | if (!cam->framebuf) { | ||
| 788 | kfree(cam->raw_image); | ||
| 789 | return -ENOMEM; | ||
| 790 | } | ||
| 791 | |||
| 792 | cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 793 | if (!cam->cntrlbuf) { | ||
| 794 | kfree(cam->raw_image); | ||
| 795 | rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); | ||
| 796 | return -ENOMEM; | ||
| 797 | } | ||
| 798 | |||
| 799 | // First upload firmware, then turn the camera on | ||
| 800 | |||
| 801 | if (!cam->is_initialized) { | ||
| 802 | initialize_camera(cam); | ||
| 803 | |||
| 804 | cam->is_initialized = 1; | ||
| 805 | } | ||
| 806 | |||
| 807 | set_camera_power(cam, 1); | ||
| 808 | |||
| 809 | cam->needsDummyRead = 1; | ||
| 810 | cam->open_count++; | ||
| 811 | |||
| 812 | file->private_data = cam; | ||
| 813 | |||
| 814 | return 0; | ||
| 815 | } | ||
| 816 | |||
| 817 | static int | ||
| 818 | vicam_close(struct inode *inode, struct file *file) | ||
| 819 | { | ||
| 820 | struct vicam_camera *cam = file->private_data; | ||
| 821 | int open_count; | ||
| 822 | struct usb_device *udev; | ||
| 823 | |||
| 824 | DBG("close\n"); | ||
| 825 | |||
| 826 | /* it's not the end of the world if | ||
| 827 | * we fail to turn the camera off. | ||
| 828 | */ | ||
| 829 | |||
| 830 | set_camera_power(cam, 0); | ||
| 831 | |||
| 832 | kfree(cam->raw_image); | ||
| 833 | rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); | ||
| 834 | kfree(cam->cntrlbuf); | ||
| 835 | |||
| 836 | mutex_lock(&cam->cam_lock); | ||
| 837 | |||
| 838 | cam->open_count--; | ||
| 839 | open_count = cam->open_count; | ||
| 840 | udev = cam->udev; | ||
| 841 | |||
| 842 | mutex_unlock(&cam->cam_lock); | ||
| 843 | |||
| 844 | if (!open_count && !udev) { | ||
| 845 | kfree(cam); | ||
| 846 | } | ||
| 847 | |||
| 848 | return 0; | ||
| 849 | } | ||
| 850 | |||
| 851 | static void vicam_decode_color(const u8 *data, u8 *rgb) | ||
| 852 | { | ||
| 853 | /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB | ||
| 854 | * Copyright (C) 2002 Monroe Williams (monroe@pobox.com) | ||
| 855 | */ | ||
| 856 | |||
| 857 | int i, prevY, nextY; | ||
| 858 | |||
| 859 | prevY = 512; | ||
| 860 | nextY = 512; | ||
| 861 | |||
| 862 | data += VICAM_HEADER_SIZE; | ||
| 863 | |||
| 864 | for( i = 0; i < 240; i++, data += 512 ) { | ||
| 865 | const int y = ( i * 242 ) / 240; | ||
| 866 | |||
| 867 | int j, prevX, nextX; | ||
| 868 | int Y, Cr, Cb; | ||
| 869 | |||
| 870 | if ( y == 242 - 1 ) { | ||
| 871 | nextY = -512; | ||
| 872 | } | ||
| 873 | |||
| 874 | prevX = 1; | ||
| 875 | nextX = 1; | ||
| 876 | |||
| 877 | for ( j = 0; j < 320; j++, rgb += 3 ) { | ||
| 878 | const int x = ( j * 512 ) / 320; | ||
| 879 | const u8 * const src = &data[x]; | ||
| 880 | |||
| 881 | if ( x == 512 - 1 ) { | ||
| 882 | nextX = -1; | ||
| 883 | } | ||
| 884 | |||
| 885 | Cr = ( src[prevX] - src[0] ) + | ||
| 886 | ( src[nextX] - src[0] ); | ||
| 887 | Cr /= 2; | ||
| 888 | |||
| 889 | Cb = ( src[prevY] - src[prevX + prevY] ) + | ||
| 890 | ( src[prevY] - src[nextX + prevY] ) + | ||
| 891 | ( src[nextY] - src[prevX + nextY] ) + | ||
| 892 | ( src[nextY] - src[nextX + nextY] ); | ||
| 893 | Cb /= 4; | ||
| 894 | |||
| 895 | Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 ); | ||
| 896 | |||
| 897 | if ( i & 1 ) { | ||
| 898 | int Ct = Cr; | ||
| 899 | Cr = Cb; | ||
| 900 | Cb = Ct; | ||
| 901 | } | ||
| 902 | |||
| 903 | if ( ( x ^ i ) & 1 ) { | ||
| 904 | Cr = -Cr; | ||
| 905 | Cb = -Cb; | ||
| 906 | } | ||
| 907 | |||
| 908 | rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) + | ||
| 909 | 500 ) / 900, 0, 255 ); | ||
| 910 | rgb[1] = clamp( ( ( Y - ( 392 * Cb ) - | ||
| 911 | ( 813 * Cr ) ) + | ||
| 912 | 500 ) / 1000, 0, 255 ); | ||
| 913 | rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) + | ||
| 914 | 500 ) / 1300, 0, 255 ); | ||
| 915 | |||
| 916 | prevX = -1; | ||
| 917 | } | ||
| 918 | |||
| 919 | prevY = -512; | ||
| 920 | } | ||
| 921 | } | ||
| 922 | |||
| 923 | static void | ||
| 924 | read_frame(struct vicam_camera *cam, int framenum) | ||
| 925 | { | ||
| 926 | unsigned char *request = cam->cntrlbuf; | ||
| 927 | int realShutter; | ||
| 928 | int n; | ||
| 929 | int actual_length; | ||
| 930 | |||
| 931 | if (cam->needsDummyRead) { | ||
| 932 | cam->needsDummyRead = 0; | ||
| 933 | read_frame(cam, framenum); | ||
| 934 | } | ||
| 935 | |||
| 936 | memset(request, 0, 16); | ||
| 937 | request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain | ||
| 938 | |||
| 939 | request[1] = 0; // 512x242 capture | ||
| 940 | |||
| 941 | request[2] = 0x90; // the function of these two bytes | ||
| 942 | request[3] = 0x07; // is not yet understood | ||
| 943 | |||
| 944 | if (cam->shutter_speed > 60) { | ||
| 945 | // Short exposure | ||
| 946 | realShutter = | ||
| 947 | ((-15631900 / cam->shutter_speed) + 260533) / 1000; | ||
| 948 | request[4] = realShutter & 0xFF; | ||
| 949 | request[5] = (realShutter >> 8) & 0xFF; | ||
| 950 | request[6] = 0x03; | ||
| 951 | request[7] = 0x01; | ||
| 952 | } else { | ||
| 953 | // Long exposure | ||
| 954 | realShutter = 15600 / cam->shutter_speed - 1; | ||
| 955 | request[4] = 0; | ||
| 956 | request[5] = 0; | ||
| 957 | request[6] = realShutter & 0xFF; | ||
| 958 | request[7] = realShutter >> 8; | ||
| 959 | } | ||
| 960 | |||
| 961 | // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0 | ||
| 962 | request[8] = 0; | ||
| 963 | // bytes 9-15 do not seem to affect exposure or image quality | ||
| 964 | |||
| 965 | mutex_lock(&cam->cam_lock); | ||
| 966 | |||
| 967 | if (!cam->udev) { | ||
| 968 | goto done; | ||
| 969 | } | ||
| 970 | |||
| 971 | n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16); | ||
| 972 | |||
| 973 | if (n < 0) { | ||
| 974 | printk(KERN_ERR | ||
| 975 | " Problem sending frame capture control message"); | ||
| 976 | goto done; | ||
| 977 | } | ||
| 978 | |||
| 979 | n = usb_bulk_msg(cam->udev, | ||
| 980 | usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), | ||
| 981 | cam->raw_image, | ||
| 982 | 512 * 242 + 128, &actual_length, 10000); | ||
| 983 | |||
| 984 | if (n < 0) { | ||
| 985 | printk(KERN_ERR "Problem during bulk read of frame data: %d\n", | ||
| 986 | n); | ||
| 987 | } | ||
| 988 | |||
| 989 | done: | ||
| 990 | mutex_unlock(&cam->cam_lock); | ||
| 991 | } | ||
| 992 | |||
| 993 | static ssize_t | ||
| 994 | vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos ) | ||
| 995 | { | ||
| 996 | struct vicam_camera *cam = file->private_data; | ||
| 997 | |||
| 998 | DBG("read %d bytes.\n", (int) count); | ||
| 999 | |||
| 1000 | if (*ppos >= VICAM_MAX_FRAME_SIZE) { | ||
| 1001 | *ppos = 0; | ||
| 1002 | return 0; | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | if (*ppos == 0) { | ||
| 1006 | read_frame(cam, 0); | ||
| 1007 | vicam_decode_color(cam->raw_image, | ||
| 1008 | cam->framebuf + | ||
| 1009 | 0 * VICAM_MAX_FRAME_SIZE); | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos); | ||
| 1013 | |||
| 1014 | if (copy_to_user(buf, &cam->framebuf[*ppos], count)) { | ||
| 1015 | count = -EFAULT; | ||
| 1016 | } else { | ||
| 1017 | *ppos += count; | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | if (count == VICAM_MAX_FRAME_SIZE) { | ||
| 1021 | *ppos = 0; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | return count; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | |||
| 1028 | static int | ||
| 1029 | vicam_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 1030 | { | ||
| 1031 | // TODO: allocate the raw frame buffer if necessary | ||
| 1032 | unsigned long page, pos; | ||
| 1033 | unsigned long start = vma->vm_start; | ||
| 1034 | unsigned long size = vma->vm_end-vma->vm_start; | ||
| 1035 | struct vicam_camera *cam = file->private_data; | ||
| 1036 | |||
| 1037 | if (!cam) | ||
| 1038 | return -ENODEV; | ||
| 1039 | |||
| 1040 | DBG("vicam_mmap: %ld\n", size); | ||
| 1041 | |||
| 1042 | /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes | ||
| 1043 | * to the size the application requested for mmap and it was screwing apps up. | ||
| 1044 | if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) | ||
| 1045 | return -EINVAL; | ||
| 1046 | */ | ||
| 1047 | |||
| 1048 | pos = (unsigned long)cam->framebuf; | ||
| 1049 | while (size > 0) { | ||
| 1050 | page = vmalloc_to_pfn((void *)pos); | ||
| 1051 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) | ||
| 1052 | return -EAGAIN; | ||
| 1053 | |||
| 1054 | start += PAGE_SIZE; | ||
| 1055 | pos += PAGE_SIZE; | ||
| 1056 | if (size > PAGE_SIZE) | ||
| 1057 | size -= PAGE_SIZE; | ||
| 1058 | else | ||
| 1059 | size = 0; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | return 0; | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | #if defined(CONFIG_VIDEO_PROC_FS) | ||
| 1066 | |||
| 1067 | static struct proc_dir_entry *vicam_proc_root = NULL; | ||
| 1068 | |||
| 1069 | static int vicam_read_helper(char *page, char **start, off_t off, | ||
| 1070 | int count, int *eof, int value) | ||
| 1071 | { | ||
| 1072 | char *out = page; | ||
| 1073 | int len; | ||
| 1074 | |||
| 1075 | out += sprintf(out, "%d",value); | ||
| 1076 | |||
| 1077 | len = out - page; | ||
| 1078 | len -= off; | ||
| 1079 | if (len < count) { | ||
| 1080 | *eof = 1; | ||
| 1081 | if (len <= 0) | ||
| 1082 | return 0; | ||
| 1083 | } else | ||
| 1084 | len = count; | ||
| 1085 | |||
| 1086 | *start = page + off; | ||
| 1087 | return len; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | static int vicam_read_proc_shutter(char *page, char **start, off_t off, | ||
| 1091 | int count, int *eof, void *data) | ||
| 1092 | { | ||
| 1093 | return vicam_read_helper(page,start,off,count,eof, | ||
| 1094 | ((struct vicam_camera *)data)->shutter_speed); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | static int vicam_read_proc_gain(char *page, char **start, off_t off, | ||
| 1098 | int count, int *eof, void *data) | ||
| 1099 | { | ||
| 1100 | return vicam_read_helper(page,start,off,count,eof, | ||
| 1101 | ((struct vicam_camera *)data)->gain); | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | static int | ||
| 1105 | vicam_write_proc_shutter(struct file *file, const char *buffer, | ||
| 1106 | unsigned long count, void *data) | ||
| 1107 | { | ||
| 1108 | u16 stmp; | ||
| 1109 | char kbuf[8]; | ||
| 1110 | struct vicam_camera *cam = (struct vicam_camera *) data; | ||
| 1111 | |||
| 1112 | if (count > 6) | ||
| 1113 | return -EINVAL; | ||
| 1114 | |||
| 1115 | if (copy_from_user(kbuf, buffer, count)) | ||
| 1116 | return -EFAULT; | ||
| 1117 | |||
| 1118 | stmp = (u16) simple_strtoul(kbuf, NULL, 10); | ||
| 1119 | if (stmp < 4 || stmp > 32000) | ||
| 1120 | return -EINVAL; | ||
| 1121 | |||
| 1122 | cam->shutter_speed = stmp; | ||
| 1123 | |||
| 1124 | return count; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | static int | ||
| 1128 | vicam_write_proc_gain(struct file *file, const char *buffer, | ||
| 1129 | unsigned long count, void *data) | ||
| 1130 | { | ||
| 1131 | u16 gtmp; | ||
| 1132 | char kbuf[8]; | ||
| 1133 | |||
| 1134 | struct vicam_camera *cam = (struct vicam_camera *) data; | ||
| 1135 | |||
| 1136 | if (count > 4) | ||
| 1137 | return -EINVAL; | ||
| 1138 | |||
| 1139 | if (copy_from_user(kbuf, buffer, count)) | ||
| 1140 | return -EFAULT; | ||
| 1141 | |||
| 1142 | gtmp = (u16) simple_strtoul(kbuf, NULL, 10); | ||
| 1143 | if (gtmp > 255) | ||
| 1144 | return -EINVAL; | ||
| 1145 | cam->gain = gtmp; | ||
| 1146 | |||
| 1147 | return count; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | static void | ||
| 1151 | vicam_create_proc_root(void) | ||
| 1152 | { | ||
| 1153 | vicam_proc_root = proc_mkdir("video/vicam", NULL); | ||
| 1154 | |||
| 1155 | if (vicam_proc_root) | ||
| 1156 | vicam_proc_root->owner = THIS_MODULE; | ||
| 1157 | else | ||
| 1158 | printk(KERN_ERR | ||
| 1159 | "could not create /proc entry for vicam!"); | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | static void | ||
| 1163 | vicam_destroy_proc_root(void) | ||
| 1164 | { | ||
| 1165 | if (vicam_proc_root) | ||
| 1166 | remove_proc_entry("video/vicam", 0); | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | static void | ||
| 1170 | vicam_create_proc_entry(struct vicam_camera *cam) | ||
| 1171 | { | ||
| 1172 | char name[64]; | ||
| 1173 | struct proc_dir_entry *ent; | ||
| 1174 | |||
| 1175 | DBG(KERN_INFO "vicam: creating proc entry\n"); | ||
| 1176 | |||
| 1177 | if (!vicam_proc_root || !cam) { | ||
| 1178 | printk(KERN_INFO | ||
| 1179 | "vicam: could not create proc entry, %s pointer is null.\n", | ||
| 1180 | (!cam ? "camera" : "root")); | ||
| 1181 | return; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | sprintf(name, "video%d", cam->vdev.minor); | ||
| 1185 | |||
| 1186 | cam->proc_dir = proc_mkdir(name, vicam_proc_root); | ||
| 1187 | |||
| 1188 | if ( !cam->proc_dir ) | ||
| 1189 | return; // FIXME: We should probably return an error here | ||
| 1190 | |||
| 1191 | ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR, | ||
| 1192 | cam->proc_dir); | ||
| 1193 | if (ent) { | ||
| 1194 | ent->data = cam; | ||
| 1195 | ent->read_proc = vicam_read_proc_shutter; | ||
| 1196 | ent->write_proc = vicam_write_proc_shutter; | ||
| 1197 | ent->size = 64; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR, | ||
| 1201 | cam->proc_dir); | ||
| 1202 | if (ent) { | ||
| 1203 | ent->data = cam; | ||
| 1204 | ent->read_proc = vicam_read_proc_gain; | ||
| 1205 | ent->write_proc = vicam_write_proc_gain; | ||
| 1206 | ent->size = 64; | ||
| 1207 | } | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | static void | ||
| 1211 | vicam_destroy_proc_entry(void *ptr) | ||
| 1212 | { | ||
| 1213 | struct vicam_camera *cam = (struct vicam_camera *) ptr; | ||
| 1214 | char name[16]; | ||
| 1215 | |||
| 1216 | if ( !cam->proc_dir ) | ||
| 1217 | return; | ||
| 1218 | |||
| 1219 | sprintf(name, "video%d", cam->vdev.minor); | ||
| 1220 | remove_proc_entry("shutter", cam->proc_dir); | ||
| 1221 | remove_proc_entry("gain", cam->proc_dir); | ||
| 1222 | remove_proc_entry(name,vicam_proc_root); | ||
| 1223 | cam->proc_dir = NULL; | ||
| 1224 | |||
| 1225 | } | ||
| 1226 | |||
| 1227 | #else | ||
| 1228 | static inline void vicam_create_proc_root(void) { } | ||
| 1229 | static inline void vicam_destroy_proc_root(void) { } | ||
| 1230 | static inline void vicam_create_proc_entry(struct vicam_camera *cam) { } | ||
| 1231 | static inline void vicam_destroy_proc_entry(void *ptr) { } | ||
| 1232 | #endif | ||
| 1233 | |||
| 1234 | static struct file_operations vicam_fops = { | ||
| 1235 | .owner = THIS_MODULE, | ||
| 1236 | .open = vicam_open, | ||
| 1237 | .release = vicam_close, | ||
| 1238 | .read = vicam_read, | ||
| 1239 | .mmap = vicam_mmap, | ||
| 1240 | .ioctl = vicam_ioctl, | ||
| 1241 | .compat_ioctl = v4l_compat_ioctl32, | ||
| 1242 | .llseek = no_llseek, | ||
| 1243 | }; | ||
| 1244 | |||
| 1245 | static struct video_device vicam_template = { | ||
| 1246 | .owner = THIS_MODULE, | ||
| 1247 | .name = "ViCam-based USB Camera", | ||
| 1248 | .type = VID_TYPE_CAPTURE, | ||
| 1249 | .hardware = VID_HARDWARE_VICAM, | ||
| 1250 | .fops = &vicam_fops, | ||
| 1251 | .minor = -1, | ||
| 1252 | }; | ||
| 1253 | |||
| 1254 | /* table of devices that work with this driver */ | ||
| 1255 | static struct usb_device_id vicam_table[] = { | ||
| 1256 | {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, | ||
| 1257 | {} /* Terminating entry */ | ||
| 1258 | }; | ||
| 1259 | |||
| 1260 | MODULE_DEVICE_TABLE(usb, vicam_table); | ||
| 1261 | |||
| 1262 | static struct usb_driver vicam_driver = { | ||
| 1263 | .name = "vicam", | ||
| 1264 | .probe = vicam_probe, | ||
| 1265 | .disconnect = vicam_disconnect, | ||
| 1266 | .id_table = vicam_table | ||
| 1267 | }; | ||
| 1268 | |||
| 1269 | /** | ||
| 1270 | * vicam_probe | ||
| 1271 | * @intf: the interface | ||
| 1272 | * @id: the device id | ||
| 1273 | * | ||
| 1274 | * Called by the usb core when a new device is connected that it thinks | ||
| 1275 | * this driver might be interested in. | ||
| 1276 | */ | ||
| 1277 | static int | ||
| 1278 | vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) | ||
| 1279 | { | ||
| 1280 | struct usb_device *dev = interface_to_usbdev(intf); | ||
| 1281 | int bulkEndpoint = 0; | ||
| 1282 | const struct usb_host_interface *interface; | ||
| 1283 | const struct usb_endpoint_descriptor *endpoint; | ||
| 1284 | struct vicam_camera *cam; | ||
| 1285 | |||
| 1286 | printk(KERN_INFO "ViCam based webcam connected\n"); | ||
| 1287 | |||
| 1288 | interface = intf->cur_altsetting; | ||
| 1289 | |||
| 1290 | DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", | ||
| 1291 | interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints)); | ||
| 1292 | endpoint = &interface->endpoint[0].desc; | ||
| 1293 | |||
| 1294 | if ((endpoint->bEndpointAddress & 0x80) && | ||
| 1295 | ((endpoint->bmAttributes & 3) == 0x02)) { | ||
| 1296 | /* we found a bulk in endpoint */ | ||
| 1297 | bulkEndpoint = endpoint->bEndpointAddress; | ||
| 1298 | } else { | ||
| 1299 | printk(KERN_ERR | ||
| 1300 | "No bulk in endpoint was found ?! (this is bad)\n"); | ||
| 1301 | } | ||
| 1302 | |||
| 1303 | if ((cam = | ||
| 1304 | kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { | ||
| 1305 | printk(KERN_WARNING | ||
| 1306 | "could not allocate kernel memory for vicam_camera struct\n"); | ||
| 1307 | return -ENOMEM; | ||
| 1308 | } | ||
| 1309 | |||
| 1310 | memset(cam, 0, sizeof (struct vicam_camera)); | ||
| 1311 | |||
| 1312 | cam->shutter_speed = 15; | ||
| 1313 | |||
| 1314 | mutex_init(&cam->cam_lock); | ||
| 1315 | |||
| 1316 | memcpy(&cam->vdev, &vicam_template, | ||
| 1317 | sizeof (vicam_template)); | ||
| 1318 | cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only | ||
| 1319 | |||
| 1320 | cam->udev = dev; | ||
| 1321 | cam->bulkEndpoint = bulkEndpoint; | ||
| 1322 | |||
| 1323 | if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { | ||
| 1324 | kfree(cam); | ||
| 1325 | printk(KERN_WARNING "video_register_device failed\n"); | ||
| 1326 | return -EIO; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | vicam_create_proc_entry(cam); | ||
| 1330 | |||
| 1331 | printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); | ||
| 1332 | |||
| 1333 | usb_set_intfdata (intf, cam); | ||
| 1334 | |||
| 1335 | return 0; | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | static void | ||
| 1339 | vicam_disconnect(struct usb_interface *intf) | ||
| 1340 | { | ||
| 1341 | int open_count; | ||
| 1342 | struct vicam_camera *cam = usb_get_intfdata (intf); | ||
| 1343 | usb_set_intfdata (intf, NULL); | ||
| 1344 | |||
| 1345 | /* we must unregister the device before taking its | ||
| 1346 | * cam_lock. This is because the video open call | ||
| 1347 | * holds the same lock as video unregister. if we | ||
| 1348 | * unregister inside of the cam_lock and open also | ||
| 1349 | * uses the cam_lock, we get deadlock. | ||
| 1350 | */ | ||
| 1351 | |||
| 1352 | video_unregister_device(&cam->vdev); | ||
| 1353 | |||
| 1354 | /* stop the camera from being used */ | ||
| 1355 | |||
| 1356 | mutex_lock(&cam->cam_lock); | ||
| 1357 | |||
| 1358 | /* mark the camera as gone */ | ||
| 1359 | |||
| 1360 | cam->udev = NULL; | ||
| 1361 | |||
| 1362 | vicam_destroy_proc_entry(cam); | ||
| 1363 | |||
| 1364 | /* the only thing left to do is synchronize with | ||
| 1365 | * our close/release function on who should release | ||
| 1366 | * the camera memory. if there are any users using the | ||
| 1367 | * camera, it's their job. if there are no users, | ||
| 1368 | * it's ours. | ||
| 1369 | */ | ||
| 1370 | |||
| 1371 | open_count = cam->open_count; | ||
| 1372 | |||
| 1373 | mutex_unlock(&cam->cam_lock); | ||
| 1374 | |||
| 1375 | if (!open_count) { | ||
| 1376 | kfree(cam); | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | /* | ||
| 1383 | */ | ||
| 1384 | static int __init | ||
| 1385 | usb_vicam_init(void) | ||
| 1386 | { | ||
| 1387 | int retval; | ||
| 1388 | DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); | ||
| 1389 | vicam_create_proc_root(); | ||
| 1390 | retval = usb_register(&vicam_driver); | ||
| 1391 | if (retval) | ||
| 1392 | printk(KERN_WARNING "usb_register failed!\n"); | ||
| 1393 | return retval; | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | static void __exit | ||
| 1397 | usb_vicam_exit(void) | ||
| 1398 | { | ||
| 1399 | DBG(KERN_INFO | ||
| 1400 | "ViCam-based WebCam driver shutdown\n"); | ||
| 1401 | |||
| 1402 | usb_deregister(&vicam_driver); | ||
| 1403 | vicam_destroy_proc_root(); | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | module_init(usb_vicam_init); | ||
| 1407 | module_exit(usb_vicam_exit); | ||
| 1408 | |||
| 1409 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 1410 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 1411 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c deleted file mode 100644 index b57dec3782e0..000000000000 --- a/drivers/usb/media/w9968cf.c +++ /dev/null | |||
| @@ -1,3691 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
| 5 | * * | ||
| 6 | * - Memory management code from bttv driver by Ralph Metzler, * | ||
| 7 | * Marcus Metzler and Gerd Knorr. * | ||
| 8 | * - I2C interface to kernel, high-level image sensor control routines and * | ||
| 9 | * some symbolic names from OV511 driver by Mark W. McClelland. * | ||
| 10 | * - Low-level I2C fast write function by Piotr Czerczak. * | ||
| 11 | * - Low-level I2C read function by Frederic Jouault. * | ||
| 12 | * * | ||
| 13 | * This program is free software; you can redistribute it and/or modify * | ||
| 14 | * it under the terms of the GNU General Public License as published by * | ||
| 15 | * the Free Software Foundation; either version 2 of the License, or * | ||
| 16 | * (at your option) any later version. * | ||
| 17 | * * | ||
| 18 | * This program is distributed in the hope that it will be useful, * | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 21 | * GNU General Public License for more details. * | ||
| 22 | * * | ||
| 23 | * You should have received a copy of the GNU General Public License * | ||
| 24 | * along with this program; if not, write to the Free Software * | ||
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
| 26 | ***************************************************************************/ | ||
| 27 | |||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/kernel.h> | ||
| 30 | #include <linux/kmod.h> | ||
| 31 | #include <linux/init.h> | ||
| 32 | #include <linux/fs.h> | ||
| 33 | #include <linux/vmalloc.h> | ||
| 34 | #include <linux/slab.h> | ||
| 35 | #include <linux/mm.h> | ||
| 36 | #include <linux/string.h> | ||
| 37 | #include <linux/errno.h> | ||
| 38 | #include <linux/sched.h> | ||
| 39 | #include <linux/ioctl.h> | ||
| 40 | #include <linux/delay.h> | ||
| 41 | #include <linux/stddef.h> | ||
| 42 | #include <asm/page.h> | ||
| 43 | #include <asm/uaccess.h> | ||
| 44 | #include <linux/page-flags.h> | ||
| 45 | #include <linux/moduleparam.h> | ||
| 46 | |||
| 47 | #include "w9968cf.h" | ||
| 48 | #include "w9968cf_decoder.h" | ||
| 49 | |||
| 50 | static struct w9968cf_vpp_t* w9968cf_vpp; | ||
| 51 | static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); | ||
| 52 | |||
| 53 | static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ | ||
| 54 | static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */ | ||
| 55 | |||
| 56 | static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ | ||
| 57 | |||
| 58 | |||
| 59 | /**************************************************************************** | ||
| 60 | * Module macros and parameters * | ||
| 61 | ****************************************************************************/ | ||
| 62 | |||
| 63 | MODULE_DEVICE_TABLE(usb, winbond_id_table); | ||
| 64 | |||
| 65 | MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL); | ||
| 66 | MODULE_DESCRIPTION(W9968CF_MODULE_NAME); | ||
| 67 | MODULE_VERSION(W9968CF_MODULE_VERSION); | ||
| 68 | MODULE_LICENSE(W9968CF_MODULE_LICENSE); | ||
| 69 | MODULE_SUPPORTED_DEVICE("Video"); | ||
| 70 | |||
| 71 | static int ovmod_load = W9968CF_OVMOD_LOAD; | ||
| 72 | static unsigned short simcams = W9968CF_SIMCAMS; | ||
| 73 | static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/ | ||
| 74 | static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
| 75 | W9968CF_PACKET_SIZE}; | ||
| 76 | static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
| 77 | W9968CF_BUFFERS}; | ||
| 78 | static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
| 79 | W9968CF_DOUBLE_BUFFER}; | ||
| 80 | static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING}; | ||
| 81 | static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = | ||
| 82 | W9968CF_FILTER_TYPE}; | ||
| 83 | static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW}; | ||
| 84 | static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
| 85 | W9968CF_DECOMPRESSION}; | ||
| 86 | static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING}; | ||
| 87 | static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0}; | ||
| 88 | static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB}; | ||
| 89 | static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT}; | ||
| 90 | static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP}; | ||
| 91 | static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
| 92 | W9968CF_LIGHTFREQ}; | ||
| 93 | static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]= | ||
| 94 | W9968CF_BANDINGFILTER}; | ||
| 95 | static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV}; | ||
| 96 | static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT}; | ||
| 97 | static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR}; | ||
| 98 | static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME}; | ||
| 99 | static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
| 100 | W9968CF_BRIGHTNESS}; | ||
| 101 | static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE}; | ||
| 102 | static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR}; | ||
| 103 | static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
| 104 | W9968CF_CONTRAST}; | ||
| 105 | static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
| 106 | W9968CF_WHITENESS}; | ||
| 107 | #ifdef W9968CF_DEBUG | ||
| 108 | static unsigned short debug = W9968CF_DEBUG_LEVEL; | ||
| 109 | static int specific_debug = W9968CF_SPECIFIC_DEBUG; | ||
| 110 | #endif | ||
| 111 | |||
| 112 | static unsigned int param_nv[24]; /* number of values per parameter */ | ||
| 113 | |||
| 114 | #ifdef CONFIG_KMOD | ||
| 115 | module_param(ovmod_load, bool, 0644); | ||
| 116 | #endif | ||
| 117 | module_param(simcams, ushort, 0644); | ||
| 118 | module_param_array(video_nr, short, ¶m_nv[0], 0444); | ||
| 119 | module_param_array(packet_size, uint, ¶m_nv[1], 0444); | ||
| 120 | module_param_array(max_buffers, ushort, ¶m_nv[2], 0444); | ||
| 121 | module_param_array(double_buffer, bool, ¶m_nv[3], 0444); | ||
| 122 | module_param_array(clamping, bool, ¶m_nv[4], 0444); | ||
| 123 | module_param_array(filter_type, ushort, ¶m_nv[5], 0444); | ||
| 124 | module_param_array(largeview, bool, ¶m_nv[6], 0444); | ||
| 125 | module_param_array(decompression, ushort, ¶m_nv[7], 0444); | ||
| 126 | module_param_array(upscaling, bool, ¶m_nv[8], 0444); | ||
| 127 | module_param_array(force_palette, ushort, ¶m_nv[9], 0444); | ||
| 128 | module_param_array(force_rgb, ushort, ¶m_nv[10], 0444); | ||
| 129 | module_param_array(autobright, bool, ¶m_nv[11], 0444); | ||
| 130 | module_param_array(autoexp, bool, ¶m_nv[12], 0444); | ||
| 131 | module_param_array(lightfreq, ushort, ¶m_nv[13], 0444); | ||
| 132 | module_param_array(bandingfilter, bool, ¶m_nv[14], 0444); | ||
| 133 | module_param_array(clockdiv, short, ¶m_nv[15], 0444); | ||
| 134 | module_param_array(backlight, bool, ¶m_nv[16], 0444); | ||
| 135 | module_param_array(mirror, bool, ¶m_nv[17], 0444); | ||
| 136 | module_param_array(monochrome, bool, ¶m_nv[18], 0444); | ||
| 137 | module_param_array(brightness, uint, ¶m_nv[19], 0444); | ||
| 138 | module_param_array(hue, uint, ¶m_nv[20], 0444); | ||
| 139 | module_param_array(colour, uint, ¶m_nv[21], 0444); | ||
| 140 | module_param_array(contrast, uint, ¶m_nv[22], 0444); | ||
| 141 | module_param_array(whiteness, uint, ¶m_nv[23], 0444); | ||
| 142 | #ifdef W9968CF_DEBUG | ||
| 143 | module_param(debug, ushort, 0644); | ||
| 144 | module_param(specific_debug, bool, 0644); | ||
| 145 | #endif | ||
| 146 | |||
| 147 | #ifdef CONFIG_KMOD | ||
| 148 | MODULE_PARM_DESC(ovmod_load, | ||
| 149 | "\n<0|1> Automatic 'ovcamchip' module loading." | ||
| 150 | "\n0 disabled, 1 enabled." | ||
| 151 | "\nIf enabled,'insmod' searches for the required 'ovcamchip'" | ||
| 152 | "\nmodule in the system, according to its configuration, and" | ||
| 153 | "\nattempts to load that module automatically. This action is" | ||
| 154 | "\nperformed once as soon as the 'w9968cf' module is loaded" | ||
| 155 | "\ninto memory." | ||
| 156 | "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"." | ||
| 157 | "\n"); | ||
| 158 | #endif | ||
| 159 | MODULE_PARM_DESC(simcams, | ||
| 160 | "\n<n> Number of cameras allowed to stream simultaneously." | ||
| 161 | "\nn may vary from 0 to " | ||
| 162 | __MODULE_STRING(W9968CF_MAX_DEVICES)"." | ||
| 163 | "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"." | ||
| 164 | "\n"); | ||
| 165 | MODULE_PARM_DESC(video_nr, | ||
| 166 | "\n<-1|n[,...]> Specify V4L minor mode number." | ||
| 167 | "\n -1 = use next available (default)" | ||
| 168 | "\n n = use minor number n (integer >= 0)" | ||
| 169 | "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES) | ||
| 170 | " cameras this way." | ||
| 171 | "\nFor example:" | ||
| 172 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
| 173 | "\nthe second camera and use auto for the first" | ||
| 174 | "\none and for every other camera." | ||
| 175 | "\n"); | ||
| 176 | MODULE_PARM_DESC(packet_size, | ||
| 177 | "\n<n[,...]> Specify the maximum data payload" | ||
| 178 | "\nsize in bytes for alternate settings, for each device." | ||
| 179 | "\nn is scaled between 63 and 1023 " | ||
| 180 | "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")." | ||
| 181 | "\n"); | ||
| 182 | MODULE_PARM_DESC(max_buffers, | ||
| 183 | "\n<n[,...]> For advanced users." | ||
| 184 | "\nSpecify the maximum number of video frame buffers" | ||
| 185 | "\nto allocate for each device, from 2 to " | ||
| 186 | __MODULE_STRING(W9968CF_MAX_BUFFERS) | ||
| 187 | ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")." | ||
| 188 | "\n"); | ||
| 189 | MODULE_PARM_DESC(double_buffer, | ||
| 190 | "\n<0|1[,...]> " | ||
| 191 | "Hardware double buffering: 0 disabled, 1 enabled." | ||
| 192 | "\nIt should be enabled if you want smooth video output: if" | ||
| 193 | "\nyou obtain out of sync. video, disable it, or try to" | ||
| 194 | "\ndecrease the 'clockdiv' module parameter value." | ||
| 195 | "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER) | ||
| 196 | " for every device." | ||
| 197 | "\n"); | ||
| 198 | MODULE_PARM_DESC(clamping, | ||
| 199 | "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled." | ||
| 200 | "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING) | ||
| 201 | " for every device." | ||
| 202 | "\n"); | ||
| 203 | MODULE_PARM_DESC(filter_type, | ||
| 204 | "\n<0|1|2[,...]> Video filter type." | ||
| 205 | "\n0 none, 1 (1-2-1) 3-tap filter, " | ||
| 206 | "2 (2-3-6-3-2) 5-tap filter." | ||
| 207 | "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE) | ||
| 208 | " for every device." | ||
| 209 | "\nThe filter is used to reduce noise and aliasing artifacts" | ||
| 210 | "\nproduced by the CCD or CMOS image sensor, and the scaling" | ||
| 211 | " process." | ||
| 212 | "\n"); | ||
| 213 | MODULE_PARM_DESC(largeview, | ||
| 214 | "\n<0|1[,...]> Large view: 0 disabled, 1 enabled." | ||
| 215 | "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW) | ||
| 216 | " for every device." | ||
| 217 | "\n"); | ||
| 218 | MODULE_PARM_DESC(upscaling, | ||
| 219 | "\n<0|1[,...]> Software scaling (for non-compressed video):" | ||
| 220 | "\n0 disabled, 1 enabled." | ||
| 221 | "\nDisable it if you have a slow CPU or you don't have" | ||
| 222 | " enough memory." | ||
| 223 | "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING) | ||
| 224 | " for every device." | ||
| 225 | "\nIf 'w9968cf-vpp' is not present, this parameter is" | ||
| 226 | " set to 0." | ||
| 227 | "\n"); | ||
| 228 | MODULE_PARM_DESC(decompression, | ||
| 229 | "\n<0|1|2[,...]> Software video decompression:" | ||
| 230 | "\n- 0 disables decompression (doesn't allow formats needing" | ||
| 231 | " decompression)" | ||
| 232 | "\n- 1 forces decompression (allows formats needing" | ||
| 233 | " decompression only);" | ||
| 234 | "\n- 2 allows any permitted formats." | ||
| 235 | "\nFormats supporting compressed video are YUV422P and" | ||
| 236 | " YUV420P/YUV420 " | ||
| 237 | "\nin any resolutions where both width and height are " | ||
| 238 | "a multiple of 16." | ||
| 239 | "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION) | ||
| 240 | " for every device." | ||
| 241 | "\nIf 'w9968cf-vpp' is not present, forcing decompression is " | ||
| 242 | "\nnot allowed; in this case this parameter is set to 2." | ||
| 243 | "\n"); | ||
| 244 | MODULE_PARM_DESC(force_palette, | ||
| 245 | "\n<0" | ||
| 246 | "|" __MODULE_STRING(VIDEO_PALETTE_UYVY) | ||
| 247 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420) | ||
| 248 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P) | ||
| 249 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P) | ||
| 250 | "|" __MODULE_STRING(VIDEO_PALETTE_YUYV) | ||
| 251 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422) | ||
| 252 | "|" __MODULE_STRING(VIDEO_PALETTE_GREY) | ||
| 253 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB555) | ||
| 254 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB565) | ||
| 255 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB24) | ||
| 256 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB32) | ||
| 257 | "[,...]>" | ||
| 258 | " Force picture palette." | ||
| 259 | "\nIn order:" | ||
| 260 | "\n- 0 allows any of the following formats:" | ||
| 261 | "\n- UYVY 16 bpp - Original video, compression disabled" | ||
| 262 | "\n- YUV420 12 bpp - Original video, compression enabled" | ||
| 263 | "\n- YUV422P 16 bpp - Original video, compression enabled" | ||
| 264 | "\n- YUV420P 12 bpp - Original video, compression enabled" | ||
| 265 | "\n- YUVY 16 bpp - Software conversion from UYVY" | ||
| 266 | "\n- YUV422 16 bpp - Software conversion from UYVY" | ||
| 267 | "\n- GREY 8 bpp - Software conversion from UYVY" | ||
| 268 | "\n- RGB555 16 bpp - Software conversion from UYVY" | ||
| 269 | "\n- RGB565 16 bpp - Software conversion from UYVY" | ||
| 270 | "\n- RGB24 24 bpp - Software conversion from UYVY" | ||
| 271 | "\n- RGB32 32 bpp - Software conversion from UYVY" | ||
| 272 | "\nWhen not 0, this parameter will override 'decompression'." | ||
| 273 | "\nDefault value is 0 for every device." | ||
| 274 | "\nInitial palette is " | ||
| 275 | __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"." | ||
| 276 | "\nIf 'w9968cf-vpp' is not present, this parameter is" | ||
| 277 | " set to 9 (UYVY)." | ||
| 278 | "\n"); | ||
| 279 | MODULE_PARM_DESC(force_rgb, | ||
| 280 | "\n<0|1[,...]> Read RGB video data instead of BGR:" | ||
| 281 | "\n 1 = use RGB component ordering." | ||
| 282 | "\n 0 = use BGR component ordering." | ||
| 283 | "\nThis parameter has effect when using RGBX palettes only." | ||
| 284 | "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB) | ||
| 285 | " for every device." | ||
| 286 | "\n"); | ||
| 287 | MODULE_PARM_DESC(autobright, | ||
| 288 | "\n<0|1[,...]> Image sensor automatically changes brightness:" | ||
| 289 | "\n 0 = no, 1 = yes" | ||
| 290 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT) | ||
| 291 | " for every device." | ||
| 292 | "\n"); | ||
| 293 | MODULE_PARM_DESC(autoexp, | ||
| 294 | "\n<0|1[,...]> Image sensor automatically changes exposure:" | ||
| 295 | "\n 0 = no, 1 = yes" | ||
| 296 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP) | ||
| 297 | " for every device." | ||
| 298 | "\n"); | ||
| 299 | MODULE_PARM_DESC(lightfreq, | ||
| 300 | "\n<50|60[,...]> Light frequency in Hz:" | ||
| 301 | "\n 50 for European and Asian lighting," | ||
| 302 | " 60 for American lighting." | ||
| 303 | "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ) | ||
| 304 | " for every device." | ||
| 305 | "\n"); | ||
| 306 | MODULE_PARM_DESC(bandingfilter, | ||
| 307 | "\n<0|1[,...]> Banding filter to reduce effects of" | ||
| 308 | " fluorescent lighting:" | ||
| 309 | "\n 0 disabled, 1 enabled." | ||
| 310 | "\nThis filter tries to reduce the pattern of horizontal" | ||
| 311 | "\nlight/dark bands caused by some (usually fluorescent)" | ||
| 312 | " lighting." | ||
| 313 | "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER) | ||
| 314 | " for every device." | ||
| 315 | "\n"); | ||
| 316 | MODULE_PARM_DESC(clockdiv, | ||
| 317 | "\n<-1|n[,...]> " | ||
| 318 | "Force pixel clock divisor to a specific value (for experts):" | ||
| 319 | "\n n may vary from 0 to 127." | ||
| 320 | "\n -1 for automatic value." | ||
| 321 | "\nSee also the 'double_buffer' module parameter." | ||
| 322 | "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV) | ||
| 323 | " for every device." | ||
| 324 | "\n"); | ||
| 325 | MODULE_PARM_DESC(backlight, | ||
| 326 | "\n<0|1[,...]> Objects are lit from behind:" | ||
| 327 | "\n 0 = no, 1 = yes" | ||
| 328 | "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT) | ||
| 329 | " for every device." | ||
| 330 | "\n"); | ||
| 331 | MODULE_PARM_DESC(mirror, | ||
| 332 | "\n<0|1[,...]> Reverse image horizontally:" | ||
| 333 | "\n 0 = no, 1 = yes" | ||
| 334 | "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR) | ||
| 335 | " for every device." | ||
| 336 | "\n"); | ||
| 337 | MODULE_PARM_DESC(monochrome, | ||
| 338 | "\n<0|1[,...]> Use image sensor as monochrome sensor:" | ||
| 339 | "\n 0 = no, 1 = yes" | ||
| 340 | "\nNot all the sensors support monochrome color." | ||
| 341 | "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME) | ||
| 342 | " for every device." | ||
| 343 | "\n"); | ||
| 344 | MODULE_PARM_DESC(brightness, | ||
| 345 | "\n<n[,...]> Set picture brightness (0-65535)." | ||
| 346 | "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS) | ||
| 347 | " for every device." | ||
| 348 | "\nThis parameter has no effect if 'autobright' is enabled." | ||
| 349 | "\n"); | ||
| 350 | MODULE_PARM_DESC(hue, | ||
| 351 | "\n<n[,...]> Set picture hue (0-65535)." | ||
| 352 | "\nDefault value is "__MODULE_STRING(W9968CF_HUE) | ||
| 353 | " for every device." | ||
| 354 | "\n"); | ||
| 355 | MODULE_PARM_DESC(colour, | ||
| 356 | "\n<n[,...]> Set picture saturation (0-65535)." | ||
| 357 | "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR) | ||
| 358 | " for every device." | ||
| 359 | "\n"); | ||
| 360 | MODULE_PARM_DESC(contrast, | ||
| 361 | "\n<n[,...]> Set picture contrast (0-65535)." | ||
| 362 | "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST) | ||
| 363 | " for every device." | ||
| 364 | "\n"); | ||
| 365 | MODULE_PARM_DESC(whiteness, | ||
| 366 | "\n<n[,...]> Set picture whiteness (0-65535)." | ||
| 367 | "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS) | ||
| 368 | " for every device." | ||
| 369 | "\n"); | ||
| 370 | #ifdef W9968CF_DEBUG | ||
| 371 | MODULE_PARM_DESC(debug, | ||
| 372 | "\n<n> Debugging information level, from 0 to 6:" | ||
| 373 | "\n0 = none (use carefully)" | ||
| 374 | "\n1 = critical errors" | ||
| 375 | "\n2 = significant informations" | ||
| 376 | "\n3 = configuration or general messages" | ||
| 377 | "\n4 = warnings" | ||
| 378 | "\n5 = called functions" | ||
| 379 | "\n6 = function internals" | ||
| 380 | "\nLevel 5 and 6 are useful for testing only, when only " | ||
| 381 | "one device is used." | ||
| 382 | "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"." | ||
| 383 | "\n"); | ||
| 384 | MODULE_PARM_DESC(specific_debug, | ||
| 385 | "\n<0|1> Enable or disable specific debugging messages:" | ||
| 386 | "\n0 = print messages concerning every level" | ||
| 387 | " <= 'debug' level." | ||
| 388 | "\n1 = print messages concerning the level" | ||
| 389 | " indicated by 'debug'." | ||
| 390 | "\nDefault value is " | ||
| 391 | __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"." | ||
| 392 | "\n"); | ||
| 393 | #endif /* W9968CF_DEBUG */ | ||
| 394 | |||
| 395 | |||
| 396 | |||
| 397 | /**************************************************************************** | ||
| 398 | * Some prototypes * | ||
| 399 | ****************************************************************************/ | ||
| 400 | |||
| 401 | /* Video4linux interface */ | ||
| 402 | static struct file_operations w9968cf_fops; | ||
| 403 | static int w9968cf_open(struct inode*, struct file*); | ||
| 404 | static int w9968cf_release(struct inode*, struct file*); | ||
| 405 | static int w9968cf_mmap(struct file*, struct vm_area_struct*); | ||
| 406 | static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long); | ||
| 407 | static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*); | ||
| 408 | static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, | ||
| 409 | void __user *); | ||
| 410 | |||
| 411 | /* USB-specific */ | ||
| 412 | static int w9968cf_start_transfer(struct w9968cf_device*); | ||
| 413 | static int w9968cf_stop_transfer(struct w9968cf_device*); | ||
| 414 | static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index); | ||
| 415 | static int w9968cf_read_reg(struct w9968cf_device*, u16 index); | ||
| 416 | static int w9968cf_write_fsb(struct w9968cf_device*, u16* data); | ||
| 417 | static int w9968cf_write_sb(struct w9968cf_device*, u16 value); | ||
| 418 | static int w9968cf_read_sb(struct w9968cf_device*); | ||
| 419 | static int w9968cf_upload_quantizationtables(struct w9968cf_device*); | ||
| 420 | static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs); | ||
| 421 | |||
| 422 | /* Low-level I2C (SMBus) I/O */ | ||
| 423 | static int w9968cf_smbus_start(struct w9968cf_device*); | ||
| 424 | static int w9968cf_smbus_stop(struct w9968cf_device*); | ||
| 425 | static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v); | ||
| 426 | static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v); | ||
| 427 | static int w9968cf_smbus_write_ack(struct w9968cf_device*); | ||
| 428 | static int w9968cf_smbus_read_ack(struct w9968cf_device*); | ||
| 429 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device*); | ||
| 430 | static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, | ||
| 431 | u16 address, u8* value); | ||
| 432 | static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, | ||
| 433 | u8 subaddress, u8* value); | ||
| 434 | static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*, | ||
| 435 | u16 address, u8 subaddress); | ||
| 436 | static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*, | ||
| 437 | u16 address, u8 subaddress, | ||
| 438 | u8 value); | ||
| 439 | |||
| 440 | /* I2C interface to kernel */ | ||
| 441 | static int w9968cf_i2c_init(struct w9968cf_device*); | ||
| 442 | static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, | ||
| 443 | unsigned short flags, char read_write, | ||
| 444 | u8 command, int size, union i2c_smbus_data*); | ||
| 445 | static u32 w9968cf_i2c_func(struct i2c_adapter*); | ||
| 446 | static int w9968cf_i2c_attach_inform(struct i2c_client*); | ||
| 447 | static int w9968cf_i2c_detach_inform(struct i2c_client*); | ||
| 448 | static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd, | ||
| 449 | unsigned long arg); | ||
| 450 | |||
| 451 | /* Memory management */ | ||
| 452 | static void* rvmalloc(unsigned long size); | ||
| 453 | static void rvfree(void *mem, unsigned long size); | ||
| 454 | static void w9968cf_deallocate_memory(struct w9968cf_device*); | ||
| 455 | static int w9968cf_allocate_memory(struct w9968cf_device*); | ||
| 456 | |||
| 457 | /* High-level image sensor control functions */ | ||
| 458 | static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val); | ||
| 459 | static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val); | ||
| 460 | static int w9968cf_sensor_cmd(struct w9968cf_device*, | ||
| 461 | unsigned int cmd, void *arg); | ||
| 462 | static int w9968cf_sensor_init(struct w9968cf_device*); | ||
| 463 | static int w9968cf_sensor_update_settings(struct w9968cf_device*); | ||
| 464 | static int w9968cf_sensor_get_picture(struct w9968cf_device*); | ||
| 465 | static int w9968cf_sensor_update_picture(struct w9968cf_device*, | ||
| 466 | struct video_picture pict); | ||
| 467 | |||
| 468 | /* Other helper functions */ | ||
| 469 | static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*, | ||
| 470 | enum w9968cf_model_id, | ||
| 471 | const unsigned short dev_nr); | ||
| 472 | static void w9968cf_adjust_configuration(struct w9968cf_device*); | ||
| 473 | static int w9968cf_turn_on_led(struct w9968cf_device*); | ||
| 474 | static int w9968cf_init_chip(struct w9968cf_device*); | ||
| 475 | static inline u16 w9968cf_valid_palette(u16 palette); | ||
| 476 | static inline u16 w9968cf_valid_depth(u16 palette); | ||
| 477 | static inline u8 w9968cf_need_decompression(u16 palette); | ||
| 478 | static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture); | ||
| 479 | static int w9968cf_set_window(struct w9968cf_device*, struct video_window); | ||
| 480 | static int w9968cf_postprocess_frame(struct w9968cf_device*, | ||
| 481 | struct w9968cf_frame_t*); | ||
| 482 | static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h); | ||
| 483 | static void w9968cf_init_framelist(struct w9968cf_device*); | ||
| 484 | static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num); | ||
| 485 | static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**); | ||
| 486 | static void w9968cf_release_resources(struct w9968cf_device*); | ||
| 487 | |||
| 488 | |||
| 489 | |||
| 490 | /**************************************************************************** | ||
| 491 | * Symbolic names * | ||
| 492 | ****************************************************************************/ | ||
| 493 | |||
| 494 | /* Used to represent a list of values and their respective symbolic names */ | ||
| 495 | struct w9968cf_symbolic_list { | ||
| 496 | const int num; | ||
| 497 | const char *name; | ||
| 498 | }; | ||
| 499 | |||
| 500 | /*-------------------------------------------------------------------------- | ||
| 501 | Returns the name of the matching element in the symbolic_list array. The | ||
| 502 | end of the list must be marked with an element that has a NULL name. | ||
| 503 | --------------------------------------------------------------------------*/ | ||
| 504 | static inline const char * | ||
| 505 | symbolic(struct w9968cf_symbolic_list list[], const int num) | ||
| 506 | { | ||
| 507 | int i; | ||
| 508 | |||
| 509 | for (i = 0; list[i].name != NULL; i++) | ||
| 510 | if (list[i].num == num) | ||
| 511 | return (list[i].name); | ||
| 512 | |||
| 513 | return "Unknown"; | ||
| 514 | } | ||
| 515 | |||
| 516 | static struct w9968cf_symbolic_list camlist[] = { | ||
| 517 | { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" }, | ||
| 518 | { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" }, | ||
| 519 | |||
| 520 | /* Other cameras (having the same descriptors as Generic W996[87]CF) */ | ||
| 521 | { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" }, | ||
| 522 | { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" }, | ||
| 523 | { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" }, | ||
| 524 | { W9968CF_MOD_LL, "Lebon LDC-035A" }, | ||
| 525 | { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" }, | ||
| 526 | { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" }, | ||
| 527 | { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" }, | ||
| 528 | { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" }, | ||
| 529 | { W9968CF_MOD_PDP480, "Pretec DigiPen-480" }, | ||
| 530 | |||
| 531 | { -1, NULL } | ||
| 532 | }; | ||
| 533 | |||
| 534 | static struct w9968cf_symbolic_list senlist[] = { | ||
| 535 | { CC_OV76BE, "OV76BE" }, | ||
| 536 | { CC_OV7610, "OV7610" }, | ||
| 537 | { CC_OV7620, "OV7620" }, | ||
| 538 | { CC_OV7620AE, "OV7620AE" }, | ||
| 539 | { CC_OV6620, "OV6620" }, | ||
| 540 | { CC_OV6630, "OV6630" }, | ||
| 541 | { CC_OV6630AE, "OV6630AE" }, | ||
| 542 | { CC_OV6630AF, "OV6630AF" }, | ||
| 543 | { -1, NULL } | ||
| 544 | }; | ||
| 545 | |||
| 546 | /* Video4Linux1 palettes */ | ||
| 547 | static struct w9968cf_symbolic_list v4l1_plist[] = { | ||
| 548 | { VIDEO_PALETTE_GREY, "GREY" }, | ||
| 549 | { VIDEO_PALETTE_HI240, "HI240" }, | ||
| 550 | { VIDEO_PALETTE_RGB565, "RGB565" }, | ||
| 551 | { VIDEO_PALETTE_RGB24, "RGB24" }, | ||
| 552 | { VIDEO_PALETTE_RGB32, "RGB32" }, | ||
| 553 | { VIDEO_PALETTE_RGB555, "RGB555" }, | ||
| 554 | { VIDEO_PALETTE_YUV422, "YUV422" }, | ||
| 555 | { VIDEO_PALETTE_YUYV, "YUYV" }, | ||
| 556 | { VIDEO_PALETTE_UYVY, "UYVY" }, | ||
| 557 | { VIDEO_PALETTE_YUV420, "YUV420" }, | ||
| 558 | { VIDEO_PALETTE_YUV411, "YUV411" }, | ||
| 559 | { VIDEO_PALETTE_RAW, "RAW" }, | ||
| 560 | { VIDEO_PALETTE_YUV422P, "YUV422P" }, | ||
| 561 | { VIDEO_PALETTE_YUV411P, "YUV411P" }, | ||
| 562 | { VIDEO_PALETTE_YUV420P, "YUV420P" }, | ||
| 563 | { VIDEO_PALETTE_YUV410P, "YUV410P" }, | ||
| 564 | { -1, NULL } | ||
| 565 | }; | ||
| 566 | |||
| 567 | /* Decoder error codes: */ | ||
| 568 | static struct w9968cf_symbolic_list decoder_errlist[] = { | ||
| 569 | { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" }, | ||
| 570 | { W9968CF_DEC_ERR_BUF_OVERFLOW, "Buffer overflow" }, | ||
| 571 | { W9968CF_DEC_ERR_NO_SOI, "SOI marker not found" }, | ||
| 572 | { W9968CF_DEC_ERR_NO_SOF0, "SOF0 marker not found" }, | ||
| 573 | { W9968CF_DEC_ERR_NO_SOS, "SOS marker not found" }, | ||
| 574 | { W9968CF_DEC_ERR_NO_EOI, "EOI marker not found" }, | ||
| 575 | { -1, NULL } | ||
| 576 | }; | ||
| 577 | |||
| 578 | /* URB error codes: */ | ||
| 579 | static struct w9968cf_symbolic_list urb_errlist[] = { | ||
| 580 | { -ENOMEM, "No memory for allocation of internal structures" }, | ||
| 581 | { -ENOSPC, "The host controller's bandwidth is already consumed" }, | ||
| 582 | { -ENOENT, "URB was canceled by unlink_urb" }, | ||
| 583 | { -EXDEV, "ISO transfer only partially completed" }, | ||
| 584 | { -EAGAIN, "Too match scheduled for the future" }, | ||
| 585 | { -ENXIO, "URB already queued" }, | ||
| 586 | { -EFBIG, "Too much ISO frames requested" }, | ||
| 587 | { -ENOSR, "Buffer error (overrun)" }, | ||
| 588 | { -EPIPE, "Specified endpoint is stalled (device not responding)"}, | ||
| 589 | { -EOVERFLOW, "Babble (bad cable?)" }, | ||
| 590 | { -EPROTO, "Bit-stuff error (bad cable?)" }, | ||
| 591 | { -EILSEQ, "CRC/Timeout" }, | ||
| 592 | { -ETIMEDOUT, "NAK (device does not respond)" }, | ||
| 593 | { -1, NULL } | ||
| 594 | }; | ||
| 595 | |||
| 596 | |||
| 597 | |||
| 598 | /**************************************************************************** | ||
| 599 | * Memory management functions * | ||
| 600 | ****************************************************************************/ | ||
| 601 | static void* rvmalloc(unsigned long size) | ||
| 602 | { | ||
| 603 | void* mem; | ||
| 604 | unsigned long adr; | ||
| 605 | |||
| 606 | size = PAGE_ALIGN(size); | ||
| 607 | mem = vmalloc_32(size); | ||
| 608 | if (!mem) | ||
| 609 | return NULL; | ||
| 610 | |||
| 611 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
| 612 | adr = (unsigned long) mem; | ||
| 613 | while (size > 0) { | ||
| 614 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
| 615 | adr += PAGE_SIZE; | ||
| 616 | size -= PAGE_SIZE; | ||
| 617 | } | ||
| 618 | |||
| 619 | return mem; | ||
| 620 | } | ||
| 621 | |||
| 622 | |||
| 623 | static void rvfree(void* mem, unsigned long size) | ||
| 624 | { | ||
| 625 | unsigned long adr; | ||
| 626 | |||
| 627 | if (!mem) | ||
| 628 | return; | ||
| 629 | |||
| 630 | adr = (unsigned long) mem; | ||
| 631 | while ((long) size > 0) { | ||
| 632 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
| 633 | adr += PAGE_SIZE; | ||
| 634 | size -= PAGE_SIZE; | ||
| 635 | } | ||
| 636 | vfree(mem); | ||
| 637 | } | ||
| 638 | |||
| 639 | |||
| 640 | /*-------------------------------------------------------------------------- | ||
| 641 | Deallocate previously allocated memory. | ||
| 642 | --------------------------------------------------------------------------*/ | ||
| 643 | static void w9968cf_deallocate_memory(struct w9968cf_device* cam) | ||
| 644 | { | ||
| 645 | u8 i; | ||
| 646 | |||
| 647 | /* Free the isochronous transfer buffers */ | ||
| 648 | for (i = 0; i < W9968CF_URBS; i++) { | ||
| 649 | kfree(cam->transfer_buffer[i]); | ||
| 650 | cam->transfer_buffer[i] = NULL; | ||
| 651 | } | ||
| 652 | |||
| 653 | /* Free temporary frame buffer */ | ||
| 654 | if (cam->frame_tmp.buffer) { | ||
| 655 | rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size); | ||
| 656 | cam->frame_tmp.buffer = NULL; | ||
| 657 | } | ||
| 658 | |||
| 659 | /* Free helper buffer */ | ||
| 660 | if (cam->frame_vpp.buffer) { | ||
| 661 | rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size); | ||
| 662 | cam->frame_vpp.buffer = NULL; | ||
| 663 | } | ||
| 664 | |||
| 665 | /* Free video frame buffers */ | ||
| 666 | if (cam->frame[0].buffer) { | ||
| 667 | rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size); | ||
| 668 | cam->frame[0].buffer = NULL; | ||
| 669 | } | ||
| 670 | |||
| 671 | cam->nbuffers = 0; | ||
| 672 | |||
| 673 | DBG(5, "Memory successfully deallocated") | ||
| 674 | } | ||
| 675 | |||
| 676 | |||
| 677 | /*-------------------------------------------------------------------------- | ||
| 678 | Allocate memory buffers for USB transfers and video frames. | ||
| 679 | This function is called by open() only. | ||
| 680 | Return 0 on success, a negative number otherwise. | ||
| 681 | --------------------------------------------------------------------------*/ | ||
| 682 | static int w9968cf_allocate_memory(struct w9968cf_device* cam) | ||
| 683 | { | ||
| 684 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; | ||
| 685 | void* buff = NULL; | ||
| 686 | unsigned long hw_bufsize, vpp_bufsize; | ||
| 687 | u8 i, bpp; | ||
| 688 | |||
| 689 | /* NOTE: Deallocation is done elsewhere in case of error */ | ||
| 690 | |||
| 691 | /* Calculate the max amount of raw data per frame from the device */ | ||
| 692 | hw_bufsize = cam->maxwidth*cam->maxheight*2; | ||
| 693 | |||
| 694 | /* Calculate the max buf. size needed for post-processing routines */ | ||
| 695 | bpp = (w9968cf_vpp) ? 4 : 2; | ||
| 696 | if (cam->upscaling) | ||
| 697 | vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp, | ||
| 698 | cam->maxwidth*cam->maxheight*bpp); | ||
| 699 | else | ||
| 700 | vpp_bufsize = cam->maxwidth*cam->maxheight*bpp; | ||
| 701 | |||
| 702 | /* Allocate memory for the isochronous transfer buffers */ | ||
| 703 | for (i = 0; i < W9968CF_URBS; i++) { | ||
| 704 | if (!(cam->transfer_buffer[i] = | ||
| 705 | kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { | ||
| 706 | DBG(1, "Couldn't allocate memory for the isochronous " | ||
| 707 | "transfer buffers (%u bytes)", | ||
| 708 | p_size * W9968CF_ISO_PACKETS) | ||
| 709 | return -ENOMEM; | ||
| 710 | } | ||
| 711 | } | ||
| 712 | |||
| 713 | /* Allocate memory for the temporary frame buffer */ | ||
| 714 | if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) { | ||
| 715 | DBG(1, "Couldn't allocate memory for the temporary " | ||
| 716 | "video frame buffer (%lu bytes)", hw_bufsize) | ||
| 717 | return -ENOMEM; | ||
| 718 | } | ||
| 719 | cam->frame_tmp.size = hw_bufsize; | ||
| 720 | cam->frame_tmp.number = -1; | ||
| 721 | |||
| 722 | /* Allocate memory for the helper buffer */ | ||
| 723 | if (w9968cf_vpp) { | ||
| 724 | if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) { | ||
| 725 | DBG(1, "Couldn't allocate memory for the helper buffer" | ||
| 726 | " (%lu bytes)", vpp_bufsize) | ||
| 727 | return -ENOMEM; | ||
| 728 | } | ||
| 729 | cam->frame_vpp.size = vpp_bufsize; | ||
| 730 | } else | ||
| 731 | cam->frame_vpp.buffer = NULL; | ||
| 732 | |||
| 733 | /* Allocate memory for video frame buffers */ | ||
| 734 | cam->nbuffers = cam->max_buffers; | ||
| 735 | while (cam->nbuffers >= 2) { | ||
| 736 | if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize))) | ||
| 737 | break; | ||
| 738 | else | ||
| 739 | cam->nbuffers--; | ||
| 740 | } | ||
| 741 | |||
| 742 | if (!buff) { | ||
| 743 | DBG(1, "Couldn't allocate memory for the video frame buffers") | ||
| 744 | cam->nbuffers = 0; | ||
| 745 | return -ENOMEM; | ||
| 746 | } | ||
| 747 | |||
| 748 | if (cam->nbuffers != cam->max_buffers) | ||
| 749 | DBG(2, "Couldn't allocate memory for %u video frame buffers. " | ||
| 750 | "Only memory for %u buffers has been allocated", | ||
| 751 | cam->max_buffers, cam->nbuffers) | ||
| 752 | |||
| 753 | for (i = 0; i < cam->nbuffers; i++) { | ||
| 754 | cam->frame[i].buffer = buff + i*vpp_bufsize; | ||
| 755 | cam->frame[i].size = vpp_bufsize; | ||
| 756 | cam->frame[i].number = i; | ||
| 757 | /* Circular list */ | ||
| 758 | if (i != cam->nbuffers-1) | ||
| 759 | cam->frame[i].next = &cam->frame[i+1]; | ||
| 760 | else | ||
| 761 | cam->frame[i].next = &cam->frame[0]; | ||
| 762 | cam->frame[i].status = F_UNUSED; | ||
| 763 | } | ||
| 764 | |||
| 765 | DBG(5, "Memory successfully allocated") | ||
| 766 | return 0; | ||
| 767 | } | ||
| 768 | |||
| 769 | |||
| 770 | |||
| 771 | /**************************************************************************** | ||
| 772 | * USB-specific functions * | ||
| 773 | ****************************************************************************/ | ||
| 774 | |||
| 775 | /*-------------------------------------------------------------------------- | ||
| 776 | This is an handler function which is called after the URBs are completed. | ||
| 777 | It collects multiple data packets coming from the camera by putting them | ||
| 778 | into frame buffers: one or more zero data length data packets are used to | ||
| 779 | mark the end of a video frame; the first non-zero data packet is the start | ||
| 780 | of the next video frame; if an error is encountered in a packet, the entire | ||
| 781 | video frame is discarded and grabbed again. | ||
| 782 | If there are no requested frames in the FIFO list, packets are collected into | ||
| 783 | a temporary buffer. | ||
| 784 | --------------------------------------------------------------------------*/ | ||
| 785 | static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs) | ||
| 786 | { | ||
| 787 | struct w9968cf_device* cam = (struct w9968cf_device*)urb->context; | ||
| 788 | struct w9968cf_frame_t** f; | ||
| 789 | unsigned int len, status; | ||
| 790 | void* pos; | ||
| 791 | u8 i; | ||
| 792 | int err = 0; | ||
| 793 | |||
| 794 | if ((!cam->streaming) || cam->disconnected) { | ||
| 795 | DBG(4, "Got interrupt, but not streaming") | ||
| 796 | return; | ||
| 797 | } | ||
| 798 | |||
| 799 | /* "(*f)" will be used instead of "cam->frame_current" */ | ||
| 800 | f = &cam->frame_current; | ||
| 801 | |||
| 802 | /* If a frame has been requested and we are grabbing into | ||
| 803 | the temporary frame, we'll switch to that requested frame */ | ||
| 804 | if ((*f) == &cam->frame_tmp && *cam->requested_frame) { | ||
| 805 | if (cam->frame_tmp.status == F_GRABBING) { | ||
| 806 | w9968cf_pop_frame(cam, &cam->frame_current); | ||
| 807 | (*f)->status = F_GRABBING; | ||
| 808 | (*f)->length = cam->frame_tmp.length; | ||
| 809 | memcpy((*f)->buffer, cam->frame_tmp.buffer, | ||
| 810 | (*f)->length); | ||
| 811 | DBG(6, "Switched from temp. frame to frame #%d", | ||
| 812 | (*f)->number) | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | for (i = 0; i < urb->number_of_packets; i++) { | ||
| 817 | len = urb->iso_frame_desc[i].actual_length; | ||
| 818 | status = urb->iso_frame_desc[i].status; | ||
| 819 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
| 820 | |||
| 821 | if (status && len != 0) { | ||
| 822 | DBG(4, "URB failed, error in data packet " | ||
| 823 | "(error #%u, %s)", | ||
| 824 | status, symbolic(urb_errlist, status)) | ||
| 825 | (*f)->status = F_ERROR; | ||
| 826 | continue; | ||
| 827 | } | ||
| 828 | |||
| 829 | if (len) { /* start of frame */ | ||
| 830 | |||
| 831 | if ((*f)->status == F_UNUSED) { | ||
| 832 | (*f)->status = F_GRABBING; | ||
| 833 | (*f)->length = 0; | ||
| 834 | } | ||
| 835 | |||
| 836 | /* Buffer overflows shouldn't happen, however...*/ | ||
| 837 | if ((*f)->length + len > (*f)->size) { | ||
| 838 | DBG(4, "Buffer overflow: bad data packets") | ||
| 839 | (*f)->status = F_ERROR; | ||
| 840 | } | ||
| 841 | |||
| 842 | if ((*f)->status == F_GRABBING) { | ||
| 843 | memcpy((*f)->buffer + (*f)->length, pos, len); | ||
| 844 | (*f)->length += len; | ||
| 845 | } | ||
| 846 | |||
| 847 | } else if ((*f)->status == F_GRABBING) { /* end of frame */ | ||
| 848 | |||
| 849 | DBG(6, "Frame #%d successfully grabbed", (*f)->number) | ||
| 850 | |||
| 851 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
| 852 | err = w9968cf_vpp->check_headers((*f)->buffer, | ||
| 853 | (*f)->length); | ||
| 854 | if (err) { | ||
| 855 | DBG(4, "Skip corrupted frame: %s", | ||
| 856 | symbolic(decoder_errlist, err)) | ||
| 857 | (*f)->status = F_UNUSED; | ||
| 858 | continue; /* grab this frame again */ | ||
| 859 | } | ||
| 860 | } | ||
| 861 | |||
| 862 | (*f)->status = F_READY; | ||
| 863 | (*f)->queued = 0; | ||
| 864 | |||
| 865 | /* Take a pointer to the new frame from the FIFO list. | ||
| 866 | If the list is empty,we'll use the temporary frame*/ | ||
| 867 | if (*cam->requested_frame) | ||
| 868 | w9968cf_pop_frame(cam, &cam->frame_current); | ||
| 869 | else { | ||
| 870 | cam->frame_current = &cam->frame_tmp; | ||
| 871 | (*f)->status = F_UNUSED; | ||
| 872 | } | ||
| 873 | |||
| 874 | } else if ((*f)->status == F_ERROR) | ||
| 875 | (*f)->status = F_UNUSED; /* grab it again */ | ||
| 876 | |||
| 877 | PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d", | ||
| 878 | (unsigned long)(*f)->length, i, len, (*f)->status) | ||
| 879 | |||
| 880 | } /* end for */ | ||
| 881 | |||
| 882 | /* Resubmit this URB */ | ||
| 883 | urb->dev = cam->usbdev; | ||
| 884 | urb->status = 0; | ||
| 885 | spin_lock(&cam->urb_lock); | ||
| 886 | if (cam->streaming) | ||
| 887 | if ((err = usb_submit_urb(urb, GFP_ATOMIC))) { | ||
| 888 | cam->misconfigured = 1; | ||
| 889 | DBG(1, "Couldn't resubmit the URB: error %d, %s", | ||
| 890 | err, symbolic(urb_errlist, err)) | ||
| 891 | } | ||
| 892 | spin_unlock(&cam->urb_lock); | ||
| 893 | |||
| 894 | /* Wake up the user process */ | ||
| 895 | wake_up_interruptible(&cam->wait_queue); | ||
| 896 | } | ||
| 897 | |||
| 898 | |||
| 899 | /*--------------------------------------------------------------------------- | ||
| 900 | Setup the URB structures for the isochronous transfer. | ||
| 901 | Submit the URBs so that the data transfer begins. | ||
| 902 | Return 0 on success, a negative number otherwise. | ||
| 903 | ---------------------------------------------------------------------------*/ | ||
| 904 | static int w9968cf_start_transfer(struct w9968cf_device* cam) | ||
| 905 | { | ||
| 906 | struct usb_device *udev = cam->usbdev; | ||
| 907 | struct urb* urb; | ||
| 908 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; | ||
| 909 | u16 w, h, d; | ||
| 910 | int vidcapt; | ||
| 911 | u32 t_size; | ||
| 912 | int err = 0; | ||
| 913 | s8 i, j; | ||
| 914 | |||
| 915 | for (i = 0; i < W9968CF_URBS; i++) { | ||
| 916 | urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL); | ||
| 917 | cam->urb[i] = urb; | ||
| 918 | if (!urb) { | ||
| 919 | for (j = 0; j < i; j++) | ||
| 920 | usb_free_urb(cam->urb[j]); | ||
| 921 | DBG(1, "Couldn't allocate the URB structures") | ||
| 922 | return -ENOMEM; | ||
| 923 | } | ||
| 924 | |||
| 925 | urb->dev = udev; | ||
| 926 | urb->context = (void*)cam; | ||
| 927 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
| 928 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 929 | urb->number_of_packets = W9968CF_ISO_PACKETS; | ||
| 930 | urb->complete = w9968cf_urb_complete; | ||
| 931 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
| 932 | urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS; | ||
| 933 | urb->interval = 1; | ||
| 934 | for (j = 0; j < W9968CF_ISO_PACKETS; j++) { | ||
| 935 | urb->iso_frame_desc[j].offset = p_size*j; | ||
| 936 | urb->iso_frame_desc[j].length = p_size; | ||
| 937 | } | ||
| 938 | } | ||
| 939 | |||
| 940 | /* Transfer size per frame, in WORD ! */ | ||
| 941 | d = cam->hw_depth; | ||
| 942 | w = cam->hw_width; | ||
| 943 | h = cam->hw_height; | ||
| 944 | |||
| 945 | t_size = (w*h*d)/16; | ||
| 946 | |||
| 947 | err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ | ||
| 948 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ | ||
| 949 | |||
| 950 | /* Transfer size */ | ||
| 951 | err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */ | ||
| 952 | err += w9968cf_write_reg(cam, t_size >> 16, 0x3e); /* high bits */ | ||
| 953 | |||
| 954 | if (cam->vpp_flag & VPP_DECOMPRESSION) | ||
| 955 | err += w9968cf_upload_quantizationtables(cam); | ||
| 956 | |||
| 957 | vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */ | ||
| 958 | err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */ | ||
| 959 | |||
| 960 | err += usb_set_interface(udev, 0, cam->altsetting); | ||
| 961 | err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */ | ||
| 962 | |||
| 963 | if (err || (vidcapt < 0)) { | ||
| 964 | for (i = 0; i < W9968CF_URBS; i++) | ||
| 965 | usb_free_urb(cam->urb[i]); | ||
| 966 | DBG(1, "Couldn't tell the camera to start the data transfer") | ||
| 967 | return err; | ||
| 968 | } | ||
| 969 | |||
| 970 | w9968cf_init_framelist(cam); | ||
| 971 | |||
| 972 | /* Begin to grab into the temporary buffer */ | ||
| 973 | cam->frame_tmp.status = F_UNUSED; | ||
| 974 | cam->frame_tmp.queued = 0; | ||
| 975 | cam->frame_current = &cam->frame_tmp; | ||
| 976 | |||
| 977 | if (!(cam->vpp_flag & VPP_DECOMPRESSION)) | ||
| 978 | DBG(5, "Isochronous transfer size: %lu bytes/frame", | ||
| 979 | (unsigned long)t_size*2) | ||
| 980 | |||
| 981 | DBG(5, "Starting the isochronous transfer...") | ||
| 982 | |||
| 983 | cam->streaming = 1; | ||
| 984 | |||
| 985 | /* Submit the URBs */ | ||
| 986 | for (i = 0; i < W9968CF_URBS; i++) { | ||
| 987 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
| 988 | if (err) { | ||
| 989 | cam->streaming = 0; | ||
| 990 | for (j = i-1; j >= 0; j--) { | ||
| 991 | usb_kill_urb(cam->urb[j]); | ||
| 992 | usb_free_urb(cam->urb[j]); | ||
| 993 | } | ||
| 994 | DBG(1, "Couldn't send a transfer request to the " | ||
| 995 | "USB core (error #%d, %s)", err, | ||
| 996 | symbolic(urb_errlist, err)) | ||
| 997 | return err; | ||
| 998 | } | ||
| 999 | } | ||
| 1000 | |||
| 1001 | return 0; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | |||
| 1005 | /*-------------------------------------------------------------------------- | ||
| 1006 | Stop the isochronous transfer and set alternate setting to 0 (0Mb/s). | ||
| 1007 | Return 0 on success, a negative number otherwise. | ||
| 1008 | --------------------------------------------------------------------------*/ | ||
| 1009 | static int w9968cf_stop_transfer(struct w9968cf_device* cam) | ||
| 1010 | { | ||
| 1011 | struct usb_device *udev = cam->usbdev; | ||
| 1012 | unsigned long lock_flags; | ||
| 1013 | int err = 0; | ||
| 1014 | s8 i; | ||
| 1015 | |||
| 1016 | if (!cam->streaming) | ||
| 1017 | return 0; | ||
| 1018 | |||
| 1019 | /* This avoids race conditions with usb_submit_urb() | ||
| 1020 | in the URB completition handler */ | ||
| 1021 | spin_lock_irqsave(&cam->urb_lock, lock_flags); | ||
| 1022 | cam->streaming = 0; | ||
| 1023 | spin_unlock_irqrestore(&cam->urb_lock, lock_flags); | ||
| 1024 | |||
| 1025 | for (i = W9968CF_URBS-1; i >= 0; i--) | ||
| 1026 | if (cam->urb[i]) { | ||
| 1027 | usb_kill_urb(cam->urb[i]); | ||
| 1028 | usb_free_urb(cam->urb[i]); | ||
| 1029 | cam->urb[i] = NULL; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | if (cam->disconnected) | ||
| 1033 | goto exit; | ||
| 1034 | |||
| 1035 | err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */ | ||
| 1036 | err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
| 1037 | err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */ | ||
| 1038 | err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */ | ||
| 1039 | |||
| 1040 | if (err) { | ||
| 1041 | DBG(2, "Failed to tell the camera to stop the isochronous " | ||
| 1042 | "transfer. However this is not a critical error.") | ||
| 1043 | return -EIO; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | exit: | ||
| 1047 | DBG(5, "Isochronous transfer stopped") | ||
| 1048 | return 0; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | |||
| 1052 | /*-------------------------------------------------------------------------- | ||
| 1053 | Write a W9968CF register. | ||
| 1054 | Return 0 on success, -1 otherwise. | ||
| 1055 | --------------------------------------------------------------------------*/ | ||
| 1056 | static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index) | ||
| 1057 | { | ||
| 1058 | struct usb_device* udev = cam->usbdev; | ||
| 1059 | int res; | ||
| 1060 | |||
| 1061 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, | ||
| 1062 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
| 1063 | value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT); | ||
| 1064 | |||
| 1065 | if (res < 0) | ||
| 1066 | DBG(4, "Failed to write a register " | ||
| 1067 | "(value 0x%04X, index 0x%02X, error #%d, %s)", | ||
| 1068 | value, index, res, symbolic(urb_errlist, res)) | ||
| 1069 | |||
| 1070 | return (res >= 0) ? 0 : -1; | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | |||
| 1074 | /*-------------------------------------------------------------------------- | ||
| 1075 | Read a W9968CF register. | ||
| 1076 | Return the register value on success, -1 otherwise. | ||
| 1077 | --------------------------------------------------------------------------*/ | ||
| 1078 | static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index) | ||
| 1079 | { | ||
| 1080 | struct usb_device* udev = cam->usbdev; | ||
| 1081 | u16* buff = cam->control_buffer; | ||
| 1082 | int res; | ||
| 1083 | |||
| 1084 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1, | ||
| 1085 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 1086 | 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT); | ||
| 1087 | |||
| 1088 | if (res < 0) | ||
| 1089 | DBG(4, "Failed to read a register " | ||
| 1090 | "(index 0x%02X, error #%d, %s)", | ||
| 1091 | index, res, symbolic(urb_errlist, res)) | ||
| 1092 | |||
| 1093 | return (res >= 0) ? (int)(*buff) : -1; | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | |||
| 1097 | /*-------------------------------------------------------------------------- | ||
| 1098 | Write 64-bit data to the fast serial bus registers. | ||
| 1099 | Return 0 on success, -1 otherwise. | ||
| 1100 | --------------------------------------------------------------------------*/ | ||
| 1101 | static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data) | ||
| 1102 | { | ||
| 1103 | struct usb_device* udev = cam->usbdev; | ||
| 1104 | u16 value; | ||
| 1105 | int res; | ||
| 1106 | |||
| 1107 | value = *data++; | ||
| 1108 | |||
| 1109 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, | ||
| 1110 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
| 1111 | value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT); | ||
| 1112 | |||
| 1113 | if (res < 0) | ||
| 1114 | DBG(4, "Failed to write the FSB registers " | ||
| 1115 | "(error #%d, %s)", res, symbolic(urb_errlist, res)) | ||
| 1116 | |||
| 1117 | return (res >= 0) ? 0 : -1; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | |||
| 1121 | /*-------------------------------------------------------------------------- | ||
| 1122 | Write data to the serial bus control register. | ||
| 1123 | Return 0 on success, a negative number otherwise. | ||
| 1124 | --------------------------------------------------------------------------*/ | ||
| 1125 | static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value) | ||
| 1126 | { | ||
| 1127 | int err = 0; | ||
| 1128 | |||
| 1129 | err = w9968cf_write_reg(cam, value, 0x01); | ||
| 1130 | udelay(W9968CF_I2C_BUS_DELAY); | ||
| 1131 | |||
| 1132 | return err; | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | |||
| 1136 | /*-------------------------------------------------------------------------- | ||
| 1137 | Read data from the serial bus control register. | ||
| 1138 | Return 0 on success, a negative number otherwise. | ||
| 1139 | --------------------------------------------------------------------------*/ | ||
| 1140 | static int w9968cf_read_sb(struct w9968cf_device* cam) | ||
| 1141 | { | ||
| 1142 | int v = 0; | ||
| 1143 | |||
| 1144 | v = w9968cf_read_reg(cam, 0x01); | ||
| 1145 | udelay(W9968CF_I2C_BUS_DELAY); | ||
| 1146 | |||
| 1147 | return v; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | |||
| 1151 | /*-------------------------------------------------------------------------- | ||
| 1152 | Upload quantization tables for the JPEG compression. | ||
| 1153 | This function is called by w9968cf_start_transfer(). | ||
| 1154 | Return 0 on success, a negative number otherwise. | ||
| 1155 | --------------------------------------------------------------------------*/ | ||
| 1156 | static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam) | ||
| 1157 | { | ||
| 1158 | u16 a, b; | ||
| 1159 | int err = 0, i, j; | ||
| 1160 | |||
| 1161 | err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */ | ||
| 1162 | |||
| 1163 | for (i = 0, j = 0; i < 32; i++, j += 2) { | ||
| 1164 | a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8); | ||
| 1165 | b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8); | ||
| 1166 | err += w9968cf_write_reg(cam, a, 0x40+i); | ||
| 1167 | err += w9968cf_write_reg(cam, b, 0x60+i); | ||
| 1168 | } | ||
| 1169 | err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */ | ||
| 1170 | |||
| 1171 | return err; | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | |||
| 1175 | |||
| 1176 | /**************************************************************************** | ||
| 1177 | * Low-level I2C I/O functions. * | ||
| 1178 | * The adapter supports the following I2C transfer functions: * | ||
| 1179 | * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) * | ||
| 1180 | * i2c_adap_read_byte_data() * | ||
| 1181 | * i2c_adap_read_byte() * | ||
| 1182 | ****************************************************************************/ | ||
| 1183 | |||
| 1184 | static int w9968cf_smbus_start(struct w9968cf_device* cam) | ||
| 1185 | { | ||
| 1186 | int err = 0; | ||
| 1187 | |||
| 1188 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | ||
| 1189 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | ||
| 1190 | |||
| 1191 | return err; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | |||
| 1195 | static int w9968cf_smbus_stop(struct w9968cf_device* cam) | ||
| 1196 | { | ||
| 1197 | int err = 0; | ||
| 1198 | |||
| 1199 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | ||
| 1200 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ | ||
| 1201 | |||
| 1202 | return err; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | |||
| 1206 | static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v) | ||
| 1207 | { | ||
| 1208 | u8 bit; | ||
| 1209 | int err = 0, sda; | ||
| 1210 | |||
| 1211 | for (bit = 0 ; bit < 8 ; bit++) { | ||
| 1212 | sda = (v & 0x80) ? 2 : 0; | ||
| 1213 | v <<= 1; | ||
| 1214 | /* SDE=1, SDA=sda, SCL=0 */ | ||
| 1215 | err += w9968cf_write_sb(cam, 0x10 | sda); | ||
| 1216 | /* SDE=1, SDA=sda, SCL=1 */ | ||
| 1217 | err += w9968cf_write_sb(cam, 0x11 | sda); | ||
| 1218 | /* SDE=1, SDA=sda, SCL=0 */ | ||
| 1219 | err += w9968cf_write_sb(cam, 0x10 | sda); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | return err; | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | |||
| 1226 | static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v) | ||
| 1227 | { | ||
| 1228 | u8 bit; | ||
| 1229 | int err = 0; | ||
| 1230 | |||
| 1231 | *v = 0; | ||
| 1232 | for (bit = 0 ; bit < 8 ; bit++) { | ||
| 1233 | *v <<= 1; | ||
| 1234 | err += w9968cf_write_sb(cam, 0x0013); | ||
| 1235 | *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0; | ||
| 1236 | err += w9968cf_write_sb(cam, 0x0012); | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | return err; | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | |||
| 1243 | static int w9968cf_smbus_write_ack(struct w9968cf_device* cam) | ||
| 1244 | { | ||
| 1245 | int err = 0; | ||
| 1246 | |||
| 1247 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | ||
| 1248 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | ||
| 1249 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | ||
| 1250 | |||
| 1251 | return err; | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | |||
| 1255 | static int w9968cf_smbus_read_ack(struct w9968cf_device* cam) | ||
| 1256 | { | ||
| 1257 | int err = 0, sda; | ||
| 1258 | |||
| 1259 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ | ||
| 1260 | sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */ | ||
| 1261 | err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */ | ||
| 1262 | if (sda < 0) | ||
| 1263 | err += sda; | ||
| 1264 | if (sda == 1) { | ||
| 1265 | DBG(6, "Couldn't receive the ACK") | ||
| 1266 | err += -1; | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | return err; | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | |||
| 1273 | /* This seems to refresh the communication through the serial bus */ | ||
| 1274 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam) | ||
| 1275 | { | ||
| 1276 | int err = 0, j; | ||
| 1277 | |||
| 1278 | for (j = 1; j <= 10; j++) { | ||
| 1279 | err = w9968cf_write_reg(cam, 0x0020, 0x01); | ||
| 1280 | err += w9968cf_write_reg(cam, 0x0000, 0x01); | ||
| 1281 | if (err) | ||
| 1282 | break; | ||
| 1283 | } | ||
| 1284 | |||
| 1285 | return err; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | |||
| 1289 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ | ||
| 1290 | static int | ||
| 1291 | w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, | ||
| 1292 | u16 address, u8 subaddress,u8 value) | ||
| 1293 | { | ||
| 1294 | u16* data = cam->data_buffer; | ||
| 1295 | int err = 0; | ||
| 1296 | |||
| 1297 | err += w9968cf_smbus_refresh_bus(cam); | ||
| 1298 | |||
| 1299 | /* Enable SBUS outputs */ | ||
| 1300 | err += w9968cf_write_sb(cam, 0x0020); | ||
| 1301 | |||
| 1302 | data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0); | ||
| 1303 | data[0] |= (address & 0x40) ? 0x4000 : 0x0; | ||
| 1304 | data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0); | ||
| 1305 | data[1] |= (address & 0x20) ? 0x0150 : 0x0; | ||
| 1306 | data[1] |= (address & 0x10) ? 0x5400 : 0x0; | ||
| 1307 | data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0); | ||
| 1308 | data[2] |= (address & 0x04) ? 0x0540 : 0x0; | ||
| 1309 | data[2] |= (address & 0x02) ? 0x5000 : 0x0; | ||
| 1310 | data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0); | ||
| 1311 | data[3] |= (address & 0x01) ? 0x0054 : 0x0; | ||
| 1312 | |||
| 1313 | err += w9968cf_write_fsb(cam, data); | ||
| 1314 | |||
| 1315 | data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0); | ||
| 1316 | data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0; | ||
| 1317 | data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0; | ||
| 1318 | data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0); | ||
| 1319 | data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0; | ||
| 1320 | data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0; | ||
| 1321 | data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0; | ||
| 1322 | data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0); | ||
| 1323 | data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0; | ||
| 1324 | data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0; | ||
| 1325 | data[3] = 0x001d; | ||
| 1326 | |||
| 1327 | err += w9968cf_write_fsb(cam, data); | ||
| 1328 | |||
| 1329 | data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); | ||
| 1330 | data[0] |= (value & 0x40) ? 0x0540 : 0x0; | ||
| 1331 | data[0] |= (value & 0x20) ? 0x5000 : 0x0; | ||
| 1332 | data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0); | ||
| 1333 | data[1] |= (value & 0x10) ? 0x0054 : 0x0; | ||
| 1334 | data[1] |= (value & 0x08) ? 0x1500 : 0x0; | ||
| 1335 | data[1] |= (value & 0x04) ? 0x4000 : 0x0; | ||
| 1336 | data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0); | ||
| 1337 | data[2] |= (value & 0x02) ? 0x0150 : 0x0; | ||
| 1338 | data[2] |= (value & 0x01) ? 0x5400 : 0x0; | ||
| 1339 | data[3] = 0xfe1d; | ||
| 1340 | |||
| 1341 | err += w9968cf_write_fsb(cam, data); | ||
| 1342 | |||
| 1343 | /* Disable SBUS outputs */ | ||
| 1344 | err += w9968cf_write_sb(cam, 0x0000); | ||
| 1345 | |||
| 1346 | if (!err) | ||
| 1347 | DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " | ||
| 1348 | "value 0x%02X", address, subaddress, value) | ||
| 1349 | else | ||
| 1350 | DBG(5, "I2C write byte data failed, addr.0x%04X, " | ||
| 1351 | "subaddr.0x%02X, value 0x%02X", | ||
| 1352 | address, subaddress, value) | ||
| 1353 | |||
| 1354 | return err; | ||
| 1355 | } | ||
| 1356 | |||
| 1357 | |||
| 1358 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ | ||
| 1359 | static int | ||
| 1360 | w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, | ||
| 1361 | u16 address, u8 subaddress, | ||
| 1362 | u8* value) | ||
| 1363 | { | ||
| 1364 | int err = 0; | ||
| 1365 | |||
| 1366 | /* Serial data enable */ | ||
| 1367 | err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */ | ||
| 1368 | |||
| 1369 | err += w9968cf_smbus_start(cam); | ||
| 1370 | err += w9968cf_smbus_write_byte(cam, address); | ||
| 1371 | err += w9968cf_smbus_read_ack(cam); | ||
| 1372 | err += w9968cf_smbus_write_byte(cam, subaddress); | ||
| 1373 | err += w9968cf_smbus_read_ack(cam); | ||
| 1374 | err += w9968cf_smbus_stop(cam); | ||
| 1375 | err += w9968cf_smbus_start(cam); | ||
| 1376 | err += w9968cf_smbus_write_byte(cam, address + 1); | ||
| 1377 | err += w9968cf_smbus_read_ack(cam); | ||
| 1378 | err += w9968cf_smbus_read_byte(cam, value); | ||
| 1379 | err += w9968cf_smbus_write_ack(cam); | ||
| 1380 | err += w9968cf_smbus_stop(cam); | ||
| 1381 | |||
| 1382 | /* Serial data disable */ | ||
| 1383 | err += w9968cf_write_sb(cam, 0x0000); | ||
| 1384 | |||
| 1385 | if (!err) | ||
| 1386 | DBG(5, "I2C read byte data done, addr.0x%04X, " | ||
| 1387 | "subaddr.0x%02X, value 0x%02X", | ||
| 1388 | address, subaddress, *value) | ||
| 1389 | else | ||
| 1390 | DBG(5, "I2C read byte data failed, addr.0x%04X, " | ||
| 1391 | "subaddr.0x%02X, wrong value 0x%02X", | ||
| 1392 | address, subaddress, *value) | ||
| 1393 | |||
| 1394 | return err; | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | |||
| 1398 | /* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */ | ||
| 1399 | static int | ||
| 1400 | w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, | ||
| 1401 | u16 address, u8* value) | ||
| 1402 | { | ||
| 1403 | int err = 0; | ||
| 1404 | |||
| 1405 | /* Serial data enable */ | ||
| 1406 | err += w9968cf_write_sb(cam, 0x0013); | ||
| 1407 | |||
| 1408 | err += w9968cf_smbus_start(cam); | ||
| 1409 | err += w9968cf_smbus_write_byte(cam, address + 1); | ||
| 1410 | err += w9968cf_smbus_read_ack(cam); | ||
| 1411 | err += w9968cf_smbus_read_byte(cam, value); | ||
| 1412 | err += w9968cf_smbus_write_ack(cam); | ||
| 1413 | err += w9968cf_smbus_stop(cam); | ||
| 1414 | |||
| 1415 | /* Serial data disable */ | ||
| 1416 | err += w9968cf_write_sb(cam, 0x0000); | ||
| 1417 | |||
| 1418 | if (!err) | ||
| 1419 | DBG(5, "I2C read byte done, addr.0x%04X, " | ||
| 1420 | "value 0x%02X", address, *value) | ||
| 1421 | else | ||
| 1422 | DBG(5, "I2C read byte failed, addr.0x%04X, " | ||
| 1423 | "wrong value 0x%02X", address, *value) | ||
| 1424 | |||
| 1425 | return err; | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | |||
| 1429 | /* SMBus protocol: S Addr Wr [A] Value [A] P */ | ||
| 1430 | static int | ||
| 1431 | w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam, | ||
| 1432 | u16 address, u8 value) | ||
| 1433 | { | ||
| 1434 | DBG(4, "i2c_write_byte() is an unsupported transfer mode") | ||
| 1435 | return -EINVAL; | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | |||
| 1439 | |||
| 1440 | /**************************************************************************** | ||
| 1441 | * I2C interface to kernel * | ||
| 1442 | ****************************************************************************/ | ||
| 1443 | |||
| 1444 | static int | ||
| 1445 | w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, | ||
| 1446 | unsigned short flags, char read_write, u8 command, | ||
| 1447 | int size, union i2c_smbus_data *data) | ||
| 1448 | { | ||
| 1449 | struct w9968cf_device* cam = i2c_get_adapdata(adapter); | ||
| 1450 | u8 i; | ||
| 1451 | int err = 0; | ||
| 1452 | |||
| 1453 | switch (addr) { | ||
| 1454 | case OV6xx0_SID: | ||
| 1455 | case OV7xx0_SID: | ||
| 1456 | break; | ||
| 1457 | default: | ||
| 1458 | DBG(4, "Rejected slave ID 0x%04X", addr) | ||
| 1459 | return -EINVAL; | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | if (size == I2C_SMBUS_BYTE) { | ||
| 1463 | /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */ | ||
| 1464 | addr <<= 1; | ||
| 1465 | |||
| 1466 | if (read_write == I2C_SMBUS_WRITE) | ||
| 1467 | err = w9968cf_i2c_adap_write_byte(cam, addr, command); | ||
| 1468 | else if (read_write == I2C_SMBUS_READ) | ||
| 1469 | err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte); | ||
| 1470 | |||
| 1471 | } else if (size == I2C_SMBUS_BYTE_DATA) { | ||
| 1472 | addr <<= 1; | ||
| 1473 | |||
| 1474 | if (read_write == I2C_SMBUS_WRITE) | ||
| 1475 | err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, | ||
| 1476 | command, data->byte); | ||
| 1477 | else if (read_write == I2C_SMBUS_READ) { | ||
| 1478 | for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { | ||
| 1479 | err = w9968cf_i2c_adap_read_byte_data(cam,addr, | ||
| 1480 | command, &data->byte); | ||
| 1481 | if (err) { | ||
| 1482 | if (w9968cf_smbus_refresh_bus(cam)) { | ||
| 1483 | err = -EIO; | ||
| 1484 | break; | ||
| 1485 | } | ||
| 1486 | } else | ||
| 1487 | break; | ||
| 1488 | } | ||
| 1489 | |||
| 1490 | } else | ||
| 1491 | return -EINVAL; | ||
| 1492 | |||
| 1493 | } else { | ||
| 1494 | DBG(4, "Unsupported I2C transfer mode (%d)", size) | ||
| 1495 | return -EINVAL; | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | return err; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | |||
| 1502 | static u32 w9968cf_i2c_func(struct i2c_adapter* adap) | ||
| 1503 | { | ||
| 1504 | return I2C_FUNC_SMBUS_READ_BYTE | | ||
| 1505 | I2C_FUNC_SMBUS_READ_BYTE_DATA | | ||
| 1506 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | |||
| 1510 | static int w9968cf_i2c_attach_inform(struct i2c_client* client) | ||
| 1511 | { | ||
| 1512 | struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); | ||
| 1513 | int id = client->driver->id, err = 0; | ||
| 1514 | |||
| 1515 | if (id == I2C_DRIVERID_OVCAMCHIP) { | ||
| 1516 | cam->sensor_client = client; | ||
| 1517 | err = w9968cf_sensor_init(cam); | ||
| 1518 | if (err) { | ||
| 1519 | cam->sensor_client = NULL; | ||
| 1520 | return err; | ||
| 1521 | } | ||
| 1522 | } else { | ||
| 1523 | DBG(4, "Rejected client [%s] with driver [%s]", | ||
| 1524 | client->name, client->driver->driver.name) | ||
| 1525 | return -EINVAL; | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | DBG(5, "I2C attach client [%s] with driver [%s]", | ||
| 1529 | client->name, client->driver->driver.name) | ||
| 1530 | |||
| 1531 | return 0; | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | |||
| 1535 | static int w9968cf_i2c_detach_inform(struct i2c_client* client) | ||
| 1536 | { | ||
| 1537 | struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); | ||
| 1538 | |||
| 1539 | if (cam->sensor_client == client) | ||
| 1540 | cam->sensor_client = NULL; | ||
| 1541 | |||
| 1542 | DBG(5, "I2C detach client [%s]", client->name) | ||
| 1543 | |||
| 1544 | return 0; | ||
| 1545 | } | ||
| 1546 | |||
| 1547 | |||
| 1548 | static int | ||
| 1549 | w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd, | ||
| 1550 | unsigned long arg) | ||
| 1551 | { | ||
| 1552 | return 0; | ||
| 1553 | } | ||
| 1554 | |||
| 1555 | |||
| 1556 | static int w9968cf_i2c_init(struct w9968cf_device* cam) | ||
| 1557 | { | ||
| 1558 | int err = 0; | ||
| 1559 | |||
| 1560 | static struct i2c_algorithm algo = { | ||
| 1561 | .smbus_xfer = w9968cf_i2c_smbus_xfer, | ||
| 1562 | .algo_control = w9968cf_i2c_control, | ||
| 1563 | .functionality = w9968cf_i2c_func, | ||
| 1564 | }; | ||
| 1565 | |||
| 1566 | static struct i2c_adapter adap = { | ||
| 1567 | .id = I2C_HW_SMBUS_W9968CF, | ||
| 1568 | .class = I2C_CLASS_CAM_DIGITAL, | ||
| 1569 | .owner = THIS_MODULE, | ||
| 1570 | .client_register = w9968cf_i2c_attach_inform, | ||
| 1571 | .client_unregister = w9968cf_i2c_detach_inform, | ||
| 1572 | .algo = &algo, | ||
| 1573 | }; | ||
| 1574 | |||
| 1575 | memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); | ||
| 1576 | strcpy(cam->i2c_adapter.name, "w9968cf"); | ||
| 1577 | i2c_set_adapdata(&cam->i2c_adapter, cam); | ||
| 1578 | |||
| 1579 | DBG(6, "Registering I2C adapter with kernel...") | ||
| 1580 | |||
| 1581 | err = i2c_add_adapter(&cam->i2c_adapter); | ||
| 1582 | if (err) | ||
| 1583 | DBG(1, "Failed to register the I2C adapter") | ||
| 1584 | else | ||
| 1585 | DBG(5, "I2C adapter registered") | ||
| 1586 | |||
| 1587 | return err; | ||
| 1588 | } | ||
| 1589 | |||
| 1590 | |||
| 1591 | |||
| 1592 | /**************************************************************************** | ||
| 1593 | * Helper functions * | ||
| 1594 | ****************************************************************************/ | ||
| 1595 | |||
| 1596 | /*-------------------------------------------------------------------------- | ||
| 1597 | Turn on the LED on some webcams. A beep should be heard too. | ||
| 1598 | Return 0 on success, a negative number otherwise. | ||
| 1599 | --------------------------------------------------------------------------*/ | ||
| 1600 | static int w9968cf_turn_on_led(struct w9968cf_device* cam) | ||
| 1601 | { | ||
| 1602 | int err = 0; | ||
| 1603 | |||
| 1604 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */ | ||
| 1605 | err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ | ||
| 1606 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ | ||
| 1607 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */ | ||
| 1608 | err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */ | ||
| 1609 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */ | ||
| 1610 | |||
| 1611 | if (err) | ||
| 1612 | DBG(2, "Couldn't turn on the LED") | ||
| 1613 | |||
| 1614 | DBG(5, "LED turned on") | ||
| 1615 | |||
| 1616 | return err; | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | |||
| 1620 | /*-------------------------------------------------------------------------- | ||
| 1621 | Write some registers for the device initialization. | ||
| 1622 | This function is called once on open(). | ||
| 1623 | Return 0 on success, a negative number otherwise. | ||
| 1624 | --------------------------------------------------------------------------*/ | ||
| 1625 | static int w9968cf_init_chip(struct w9968cf_device* cam) | ||
| 1626 | { | ||
| 1627 | unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2, | ||
| 1628 | y0 = 0x0000, | ||
| 1629 | u0 = y0 + hw_bufsize/2, | ||
| 1630 | v0 = u0 + hw_bufsize/4, | ||
| 1631 | y1 = v0 + hw_bufsize/4, | ||
| 1632 | u1 = y1 + hw_bufsize/2, | ||
| 1633 | v1 = u1 + hw_bufsize/4; | ||
| 1634 | int err = 0; | ||
| 1635 | |||
| 1636 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ | ||
| 1637 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ | ||
| 1638 | |||
| 1639 | err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */ | ||
| 1640 | err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */ | ||
| 1641 | |||
| 1642 | err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */ | ||
| 1643 | err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */ | ||
| 1644 | err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */ | ||
| 1645 | err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */ | ||
| 1646 | err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */ | ||
| 1647 | err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */ | ||
| 1648 | |||
| 1649 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */ | ||
| 1650 | err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */ | ||
| 1651 | err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */ | ||
| 1652 | err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */ | ||
| 1653 | err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */ | ||
| 1654 | err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */ | ||
| 1655 | |||
| 1656 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */ | ||
| 1657 | err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */ | ||
| 1658 | |||
| 1659 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */ | ||
| 1660 | err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */ | ||
| 1661 | |||
| 1662 | err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */ | ||
| 1663 | err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/ | ||
| 1664 | err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */ | ||
| 1665 | err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */ | ||
| 1666 | |||
| 1667 | err += w9968cf_set_picture(cam, cam->picture); /* this before */ | ||
| 1668 | err += w9968cf_set_window(cam, cam->window); | ||
| 1669 | |||
| 1670 | if (err) | ||
| 1671 | DBG(1, "Chip initialization failed") | ||
| 1672 | else | ||
| 1673 | DBG(5, "Chip successfully initialized") | ||
| 1674 | |||
| 1675 | return err; | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | |||
| 1679 | /*-------------------------------------------------------------------------- | ||
| 1680 | Return non-zero if the palette is supported, 0 otherwise. | ||
| 1681 | --------------------------------------------------------------------------*/ | ||
| 1682 | static inline u16 w9968cf_valid_palette(u16 palette) | ||
| 1683 | { | ||
| 1684 | u8 i = 0; | ||
| 1685 | while (w9968cf_formatlist[i].palette != 0) { | ||
| 1686 | if (palette == w9968cf_formatlist[i].palette) | ||
| 1687 | return palette; | ||
| 1688 | i++; | ||
| 1689 | } | ||
| 1690 | return 0; | ||
| 1691 | } | ||
| 1692 | |||
| 1693 | |||
| 1694 | /*-------------------------------------------------------------------------- | ||
| 1695 | Return the depth corresponding to the given palette. | ||
| 1696 | Palette _must_ be supported ! | ||
| 1697 | --------------------------------------------------------------------------*/ | ||
| 1698 | static inline u16 w9968cf_valid_depth(u16 palette) | ||
| 1699 | { | ||
| 1700 | u8 i=0; | ||
| 1701 | while (w9968cf_formatlist[i].palette != palette) | ||
| 1702 | i++; | ||
| 1703 | |||
| 1704 | return w9968cf_formatlist[i].depth; | ||
| 1705 | } | ||
| 1706 | |||
| 1707 | |||
| 1708 | /*-------------------------------------------------------------------------- | ||
| 1709 | Return non-zero if the format requires decompression, 0 otherwise. | ||
| 1710 | --------------------------------------------------------------------------*/ | ||
| 1711 | static inline u8 w9968cf_need_decompression(u16 palette) | ||
| 1712 | { | ||
| 1713 | u8 i = 0; | ||
| 1714 | while (w9968cf_formatlist[i].palette != 0) { | ||
| 1715 | if (palette == w9968cf_formatlist[i].palette) | ||
| 1716 | return w9968cf_formatlist[i].compression; | ||
| 1717 | i++; | ||
| 1718 | } | ||
| 1719 | return 0; | ||
| 1720 | } | ||
| 1721 | |||
| 1722 | |||
| 1723 | /*-------------------------------------------------------------------------- | ||
| 1724 | Change the picture settings of the camera. | ||
| 1725 | Return 0 on success, a negative number otherwise. | ||
| 1726 | --------------------------------------------------------------------------*/ | ||
| 1727 | static int | ||
| 1728 | w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) | ||
| 1729 | { | ||
| 1730 | u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; | ||
| 1731 | int err = 0; | ||
| 1732 | |||
| 1733 | /* Make sure we are using a valid depth */ | ||
| 1734 | pict.depth = w9968cf_valid_depth(pict.palette); | ||
| 1735 | |||
| 1736 | fmt = pict.palette; | ||
| 1737 | |||
| 1738 | hw_depth = pict.depth; /* depth used by the winbond chip */ | ||
| 1739 | hw_palette = pict.palette; /* palette used by the winbond chip */ | ||
| 1740 | |||
| 1741 | /* VS & HS polarities */ | ||
| 1742 | reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11); | ||
| 1743 | |||
| 1744 | switch (fmt) | ||
| 1745 | { | ||
| 1746 | case VIDEO_PALETTE_UYVY: | ||
| 1747 | reg_v |= 0x0000; | ||
| 1748 | cam->vpp_flag = VPP_NONE; | ||
| 1749 | break; | ||
| 1750 | case VIDEO_PALETTE_YUV422P: | ||
| 1751 | reg_v |= 0x0002; | ||
| 1752 | cam->vpp_flag = VPP_DECOMPRESSION; | ||
| 1753 | break; | ||
| 1754 | case VIDEO_PALETTE_YUV420: | ||
| 1755 | case VIDEO_PALETTE_YUV420P: | ||
| 1756 | reg_v |= 0x0003; | ||
| 1757 | cam->vpp_flag = VPP_DECOMPRESSION; | ||
| 1758 | break; | ||
| 1759 | case VIDEO_PALETTE_YUYV: | ||
| 1760 | case VIDEO_PALETTE_YUV422: | ||
| 1761 | reg_v |= 0x0000; | ||
| 1762 | cam->vpp_flag = VPP_SWAP_YUV_BYTES; | ||
| 1763 | hw_palette = VIDEO_PALETTE_UYVY; | ||
| 1764 | break; | ||
| 1765 | /* Original video is used instead of RGBX palettes. | ||
| 1766 | Software conversion later. */ | ||
| 1767 | case VIDEO_PALETTE_GREY: | ||
| 1768 | case VIDEO_PALETTE_RGB555: | ||
| 1769 | case VIDEO_PALETTE_RGB565: | ||
| 1770 | case VIDEO_PALETTE_RGB24: | ||
| 1771 | case VIDEO_PALETTE_RGB32: | ||
| 1772 | reg_v |= 0x0000; /* UYVY 16 bit is used */ | ||
| 1773 | hw_depth = 16; | ||
| 1774 | hw_palette = VIDEO_PALETTE_UYVY; | ||
| 1775 | cam->vpp_flag = VPP_UYVY_TO_RGBX; | ||
| 1776 | break; | ||
| 1777 | } | ||
| 1778 | |||
| 1779 | /* NOTE: due to memory issues, it is better to disable the hardware | ||
| 1780 | double buffering during compression */ | ||
| 1781 | if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION)) | ||
| 1782 | reg_v |= 0x0080; | ||
| 1783 | |||
| 1784 | if (cam->clamping) | ||
| 1785 | reg_v |= 0x0020; | ||
| 1786 | |||
| 1787 | if (cam->filter_type == 1) | ||
| 1788 | reg_v |= 0x0008; | ||
| 1789 | else if (cam->filter_type == 2) | ||
| 1790 | reg_v |= 0x000c; | ||
| 1791 | |||
| 1792 | if ((err = w9968cf_write_reg(cam, reg_v, 0x16))) | ||
| 1793 | goto error; | ||
| 1794 | |||
| 1795 | if ((err = w9968cf_sensor_update_picture(cam, pict))) | ||
| 1796 | goto error; | ||
| 1797 | |||
| 1798 | /* If all went well, update the device data structure */ | ||
| 1799 | memcpy(&cam->picture, &pict, sizeof(pict)); | ||
| 1800 | cam->hw_depth = hw_depth; | ||
| 1801 | cam->hw_palette = hw_palette; | ||
| 1802 | |||
| 1803 | /* Settings changed, so we clear the frame buffers */ | ||
| 1804 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); | ||
| 1805 | |||
| 1806 | DBG(4, "Palette is %s, depth is %u bpp", | ||
| 1807 | symbolic(v4l1_plist, pict.palette), pict.depth) | ||
| 1808 | |||
| 1809 | return 0; | ||
| 1810 | |||
| 1811 | error: | ||
| 1812 | DBG(1, "Failed to change picture settings") | ||
| 1813 | return err; | ||
| 1814 | } | ||
| 1815 | |||
| 1816 | |||
| 1817 | /*-------------------------------------------------------------------------- | ||
| 1818 | Change the capture area size of the camera. | ||
| 1819 | This function _must_ be called _after_ w9968cf_set_picture(). | ||
| 1820 | Return 0 on success, a negative number otherwise. | ||
| 1821 | --------------------------------------------------------------------------*/ | ||
| 1822 | static int | ||
| 1823 | w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) | ||
| 1824 | { | ||
| 1825 | u16 x, y, w, h, scx, scy, cw, ch, ax, ay; | ||
| 1826 | unsigned long fw, fh; | ||
| 1827 | struct ovcamchip_window s_win; | ||
| 1828 | int err = 0; | ||
| 1829 | |||
| 1830 | /* Work around to avoid FP arithmetics */ | ||
| 1831 | #define __SC(x) ((x) << 10) | ||
| 1832 | #define __UNSC(x) ((x) >> 10) | ||
| 1833 | |||
| 1834 | /* Make sure we are using a supported resolution */ | ||
| 1835 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, | ||
| 1836 | (u16*)&win.height))) | ||
| 1837 | goto error; | ||
| 1838 | |||
| 1839 | /* Scaling factors */ | ||
| 1840 | fw = __SC(win.width) / cam->maxwidth; | ||
| 1841 | fh = __SC(win.height) / cam->maxheight; | ||
| 1842 | |||
| 1843 | /* Set up the width and height values used by the chip */ | ||
| 1844 | if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) { | ||
| 1845 | cam->vpp_flag |= VPP_UPSCALE; | ||
| 1846 | /* Calculate largest w,h mantaining the same w/h ratio */ | ||
| 1847 | w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; | ||
| 1848 | h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; | ||
| 1849 | if (w < cam->minwidth) /* just in case */ | ||
| 1850 | w = cam->minwidth; | ||
| 1851 | if (h < cam->minheight) /* just in case */ | ||
| 1852 | h = cam->minheight; | ||
| 1853 | } else { | ||
| 1854 | cam->vpp_flag &= ~VPP_UPSCALE; | ||
| 1855 | w = win.width; | ||
| 1856 | h = win.height; | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | /* x,y offsets of the cropped area */ | ||
| 1860 | scx = cam->start_cropx; | ||
| 1861 | scy = cam->start_cropy; | ||
| 1862 | |||
| 1863 | /* Calculate cropped area manteining the right w/h ratio */ | ||
| 1864 | if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) { | ||
| 1865 | cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; | ||
| 1866 | ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; | ||
| 1867 | } else { | ||
| 1868 | cw = w; | ||
| 1869 | ch = h; | ||
| 1870 | } | ||
| 1871 | |||
| 1872 | /* Setup the window of the sensor */ | ||
| 1873 | s_win.format = VIDEO_PALETTE_UYVY; | ||
| 1874 | s_win.width = cam->maxwidth; | ||
| 1875 | s_win.height = cam->maxheight; | ||
| 1876 | s_win.quarter = 0; /* full progressive video */ | ||
| 1877 | |||
| 1878 | /* Center it */ | ||
| 1879 | s_win.x = (s_win.width - cw) / 2; | ||
| 1880 | s_win.y = (s_win.height - ch) / 2; | ||
| 1881 | |||
| 1882 | /* Clock divisor */ | ||
| 1883 | if (cam->clockdiv >= 0) | ||
| 1884 | s_win.clockdiv = cam->clockdiv; /* manual override */ | ||
| 1885 | else | ||
| 1886 | switch (cam->sensor) { | ||
| 1887 | case CC_OV6620: | ||
| 1888 | s_win.clockdiv = 0; | ||
| 1889 | break; | ||
| 1890 | case CC_OV6630: | ||
| 1891 | s_win.clockdiv = 0; | ||
| 1892 | break; | ||
| 1893 | case CC_OV76BE: | ||
| 1894 | case CC_OV7610: | ||
| 1895 | case CC_OV7620: | ||
| 1896 | s_win.clockdiv = 0; | ||
| 1897 | break; | ||
| 1898 | default: | ||
| 1899 | s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR; | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | /* We have to scale win.x and win.y offsets */ | ||
| 1903 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) | ||
| 1904 | || (cam->vpp_flag & VPP_UPSCALE) ) { | ||
| 1905 | ax = __SC(win.x)/fw; | ||
| 1906 | ay = __SC(win.y)/fh; | ||
| 1907 | } else { | ||
| 1908 | ax = win.x; | ||
| 1909 | ay = win.y; | ||
| 1910 | } | ||
| 1911 | |||
| 1912 | if ((ax + cw) > cam->maxwidth) | ||
| 1913 | ax = cam->maxwidth - cw; | ||
| 1914 | |||
| 1915 | if ((ay + ch) > cam->maxheight) | ||
| 1916 | ay = cam->maxheight - ch; | ||
| 1917 | |||
| 1918 | /* Adjust win.x, win.y */ | ||
| 1919 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) | ||
| 1920 | || (cam->vpp_flag & VPP_UPSCALE) ) { | ||
| 1921 | win.x = __UNSC(ax*fw); | ||
| 1922 | win.y = __UNSC(ay*fh); | ||
| 1923 | } else { | ||
| 1924 | win.x = ax; | ||
| 1925 | win.y = ay; | ||
| 1926 | } | ||
| 1927 | |||
| 1928 | /* Offsets used by the chip */ | ||
| 1929 | x = ax + s_win.x; | ||
| 1930 | y = ay + s_win.y; | ||
| 1931 | |||
| 1932 | /* Go ! */ | ||
| 1933 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win))) | ||
| 1934 | goto error; | ||
| 1935 | |||
| 1936 | err += w9968cf_write_reg(cam, scx + x, 0x10); | ||
| 1937 | err += w9968cf_write_reg(cam, scy + y, 0x11); | ||
| 1938 | err += w9968cf_write_reg(cam, scx + x + cw, 0x12); | ||
| 1939 | err += w9968cf_write_reg(cam, scy + y + ch, 0x13); | ||
| 1940 | err += w9968cf_write_reg(cam, w, 0x14); | ||
| 1941 | err += w9968cf_write_reg(cam, h, 0x15); | ||
| 1942 | |||
| 1943 | /* JPEG width & height */ | ||
| 1944 | err += w9968cf_write_reg(cam, w, 0x30); | ||
| 1945 | err += w9968cf_write_reg(cam, h, 0x31); | ||
| 1946 | |||
| 1947 | /* Y & UV frame buffer strides (in WORD) */ | ||
| 1948 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
| 1949 | err += w9968cf_write_reg(cam, w/2, 0x2c); | ||
| 1950 | err += w9968cf_write_reg(cam, w/4, 0x2d); | ||
| 1951 | } else | ||
| 1952 | err += w9968cf_write_reg(cam, w, 0x2c); | ||
| 1953 | |||
| 1954 | if (err) | ||
| 1955 | goto error; | ||
| 1956 | |||
| 1957 | /* If all went well, update the device data structure */ | ||
| 1958 | memcpy(&cam->window, &win, sizeof(win)); | ||
| 1959 | cam->hw_width = w; | ||
| 1960 | cam->hw_height = h; | ||
| 1961 | |||
| 1962 | /* Settings changed, so we clear the frame buffers */ | ||
| 1963 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); | ||
| 1964 | |||
| 1965 | DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", | ||
| 1966 | win.width, win.height, win.x, win.y) | ||
| 1967 | |||
| 1968 | PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, " | ||
| 1969 | "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u", | ||
| 1970 | x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y, | ||
| 1971 | win.width, win.height) | ||
| 1972 | |||
| 1973 | return 0; | ||
| 1974 | |||
| 1975 | error: | ||
| 1976 | DBG(1, "Failed to change the capture area size") | ||
| 1977 | return err; | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | |||
| 1981 | /*-------------------------------------------------------------------------- | ||
| 1982 | Adjust the asked values for window width and height. | ||
| 1983 | Return 0 on success, -1 otherwise. | ||
| 1984 | --------------------------------------------------------------------------*/ | ||
| 1985 | static int | ||
| 1986 | w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height) | ||
| 1987 | { | ||
| 1988 | u16 maxw, maxh; | ||
| 1989 | |||
| 1990 | if ((*width < cam->minwidth) || (*height < cam->minheight)) | ||
| 1991 | return -ERANGE; | ||
| 1992 | |||
| 1993 | maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && | ||
| 1994 | w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) | ||
| 1995 | : cam->maxwidth; | ||
| 1996 | maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && | ||
| 1997 | w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) | ||
| 1998 | : cam->maxheight; | ||
| 1999 | |||
| 2000 | if (*width > maxw) | ||
| 2001 | *width = maxw; | ||
| 2002 | if (*height > maxh) | ||
| 2003 | *height = maxh; | ||
| 2004 | |||
| 2005 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
| 2006 | *width &= ~15L; /* multiple of 16 */ | ||
| 2007 | *height &= ~15L; | ||
| 2008 | } | ||
| 2009 | |||
| 2010 | PDBGG("Window size adjusted w=%u, h=%u ", *width, *height) | ||
| 2011 | |||
| 2012 | return 0; | ||
| 2013 | } | ||
| 2014 | |||
| 2015 | |||
| 2016 | /*-------------------------------------------------------------------------- | ||
| 2017 | Initialize the FIFO list of requested frames. | ||
| 2018 | --------------------------------------------------------------------------*/ | ||
| 2019 | static void w9968cf_init_framelist(struct w9968cf_device* cam) | ||
| 2020 | { | ||
| 2021 | u8 i; | ||
| 2022 | |||
| 2023 | for (i = 0; i < cam->nbuffers; i++) { | ||
| 2024 | cam->requested_frame[i] = NULL; | ||
| 2025 | cam->frame[i].queued = 0; | ||
| 2026 | cam->frame[i].status = F_UNUSED; | ||
| 2027 | } | ||
| 2028 | } | ||
| 2029 | |||
| 2030 | |||
| 2031 | /*-------------------------------------------------------------------------- | ||
| 2032 | Add a frame in the FIFO list of requested frames. | ||
| 2033 | This function is called in process context. | ||
| 2034 | --------------------------------------------------------------------------*/ | ||
| 2035 | static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num) | ||
| 2036 | { | ||
| 2037 | u8 f; | ||
| 2038 | unsigned long lock_flags; | ||
| 2039 | |||
| 2040 | spin_lock_irqsave(&cam->flist_lock, lock_flags); | ||
| 2041 | |||
| 2042 | for (f=0; cam->requested_frame[f] != NULL; f++); | ||
| 2043 | cam->requested_frame[f] = &cam->frame[f_num]; | ||
| 2044 | cam->frame[f_num].queued = 1; | ||
| 2045 | cam->frame[f_num].status = F_UNUSED; /* clear the status */ | ||
| 2046 | |||
| 2047 | spin_unlock_irqrestore(&cam->flist_lock, lock_flags); | ||
| 2048 | |||
| 2049 | DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f) | ||
| 2050 | } | ||
| 2051 | |||
| 2052 | |||
| 2053 | /*-------------------------------------------------------------------------- | ||
| 2054 | Read, store and remove the first pointer in the FIFO list of requested | ||
| 2055 | frames. This function is called in interrupt context. | ||
| 2056 | --------------------------------------------------------------------------*/ | ||
| 2057 | static void | ||
| 2058 | w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep) | ||
| 2059 | { | ||
| 2060 | u8 i; | ||
| 2061 | |||
| 2062 | spin_lock(&cam->flist_lock); | ||
| 2063 | |||
| 2064 | *framep = cam->requested_frame[0]; | ||
| 2065 | |||
| 2066 | /* Shift the list of pointers */ | ||
| 2067 | for (i = 0; i < cam->nbuffers-1; i++) | ||
| 2068 | cam->requested_frame[i] = cam->requested_frame[i+1]; | ||
| 2069 | cam->requested_frame[i] = NULL; | ||
| 2070 | |||
| 2071 | spin_unlock(&cam->flist_lock); | ||
| 2072 | |||
| 2073 | DBG(6,"Popped frame #%d from the list", (*framep)->number) | ||
| 2074 | } | ||
| 2075 | |||
| 2076 | |||
| 2077 | /*-------------------------------------------------------------------------- | ||
| 2078 | High-level video post-processing routine on grabbed frames. | ||
| 2079 | Return 0 on success, a negative number otherwise. | ||
| 2080 | --------------------------------------------------------------------------*/ | ||
| 2081 | static int | ||
| 2082 | w9968cf_postprocess_frame(struct w9968cf_device* cam, | ||
| 2083 | struct w9968cf_frame_t* fr) | ||
| 2084 | { | ||
| 2085 | void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp; | ||
| 2086 | u16 w = cam->window.width, | ||
| 2087 | h = cam->window.height, | ||
| 2088 | d = cam->picture.depth, | ||
| 2089 | fmt = cam->picture.palette, | ||
| 2090 | rgb = cam->force_rgb, | ||
| 2091 | hw_w = cam->hw_width, | ||
| 2092 | hw_h = cam->hw_height, | ||
| 2093 | hw_d = cam->hw_depth; | ||
| 2094 | int err = 0; | ||
| 2095 | |||
| 2096 | #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;} | ||
| 2097 | |||
| 2098 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
| 2099 | memcpy(pOut, pIn, fr->length); | ||
| 2100 | _PSWAP(pIn, pOut) | ||
| 2101 | err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut); | ||
| 2102 | PDBGG("Compressed frame length: %lu",(unsigned long)fr->length) | ||
| 2103 | fr->length = (hw_w*hw_h*hw_d)/8; | ||
| 2104 | _PSWAP(pIn, pOut) | ||
| 2105 | if (err) { | ||
| 2106 | DBG(4, "An error occurred while decoding the frame: " | ||
| 2107 | "%s", symbolic(decoder_errlist, err)) | ||
| 2108 | return err; | ||
| 2109 | } else | ||
| 2110 | DBG(6, "Frame decoded") | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) { | ||
| 2114 | w9968cf_vpp->swap_yuvbytes(pIn, fr->length); | ||
| 2115 | DBG(6, "Original UYVY component ordering changed") | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | if (cam->vpp_flag & VPP_UPSCALE) { | ||
| 2119 | w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h); | ||
| 2120 | fr->length = (w*h*hw_d)/8; | ||
| 2121 | _PSWAP(pIn, pOut) | ||
| 2122 | DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u", | ||
| 2123 | hw_w, hw_h, hw_d, w, h) | ||
| 2124 | } | ||
| 2125 | |||
| 2126 | if (cam->vpp_flag & VPP_UYVY_TO_RGBX) { | ||
| 2127 | w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb); | ||
| 2128 | fr->length = (w*h*d)/8; | ||
| 2129 | _PSWAP(pIn, pOut) | ||
| 2130 | DBG(6, "UYVY-16bit to %s conversion done", | ||
| 2131 | symbolic(v4l1_plist, fmt)) | ||
| 2132 | } | ||
| 2133 | |||
| 2134 | if (pOut == fr->buffer) | ||
| 2135 | memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length); | ||
| 2136 | |||
| 2137 | return 0; | ||
| 2138 | } | ||
| 2139 | |||
| 2140 | |||
| 2141 | |||
| 2142 | /**************************************************************************** | ||
| 2143 | * Image sensor control routines * | ||
| 2144 | ****************************************************************************/ | ||
| 2145 | |||
| 2146 | static int | ||
| 2147 | w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val) | ||
| 2148 | { | ||
| 2149 | struct ovcamchip_control ctl; | ||
| 2150 | int err; | ||
| 2151 | |||
| 2152 | ctl.id = cid; | ||
| 2153 | ctl.value = val; | ||
| 2154 | |||
| 2155 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl); | ||
| 2156 | |||
| 2157 | return err; | ||
| 2158 | } | ||
| 2159 | |||
| 2160 | |||
| 2161 | static int | ||
| 2162 | w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val) | ||
| 2163 | { | ||
| 2164 | struct ovcamchip_control ctl; | ||
| 2165 | int err; | ||
| 2166 | |||
| 2167 | ctl.id = cid; | ||
| 2168 | |||
| 2169 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl); | ||
| 2170 | if (!err) | ||
| 2171 | *val = ctl.value; | ||
| 2172 | |||
| 2173 | return err; | ||
| 2174 | } | ||
| 2175 | |||
| 2176 | |||
| 2177 | static int | ||
| 2178 | w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg) | ||
| 2179 | { | ||
| 2180 | struct i2c_client* c = cam->sensor_client; | ||
| 2181 | int rc = 0; | ||
| 2182 | |||
| 2183 | if (!c || !c->driver || !c->driver->command) | ||
| 2184 | return -EINVAL; | ||
| 2185 | |||
| 2186 | rc = c->driver->command(c, cmd, arg); | ||
| 2187 | /* The I2C driver returns -EPERM on non-supported controls */ | ||
| 2188 | return (rc < 0 && rc != -EPERM) ? rc : 0; | ||
| 2189 | } | ||
| 2190 | |||
| 2191 | |||
| 2192 | /*-------------------------------------------------------------------------- | ||
| 2193 | Update some settings of the image sensor. | ||
| 2194 | Returns: 0 on success, a negative number otherwise. | ||
| 2195 | --------------------------------------------------------------------------*/ | ||
| 2196 | static int w9968cf_sensor_update_settings(struct w9968cf_device* cam) | ||
| 2197 | { | ||
| 2198 | int err = 0; | ||
| 2199 | |||
| 2200 | /* Auto brightness */ | ||
| 2201 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, | ||
| 2202 | cam->auto_brt); | ||
| 2203 | if (err) | ||
| 2204 | return err; | ||
| 2205 | |||
| 2206 | /* Auto exposure */ | ||
| 2207 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, | ||
| 2208 | cam->auto_exp); | ||
| 2209 | if (err) | ||
| 2210 | return err; | ||
| 2211 | |||
| 2212 | /* Banding filter */ | ||
| 2213 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, | ||
| 2214 | cam->bandfilt); | ||
| 2215 | if (err) | ||
| 2216 | return err; | ||
| 2217 | |||
| 2218 | /* Light frequency */ | ||
| 2219 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ, | ||
| 2220 | cam->lightfreq); | ||
| 2221 | if (err) | ||
| 2222 | return err; | ||
| 2223 | |||
| 2224 | /* Back light */ | ||
| 2225 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT, | ||
| 2226 | cam->backlight); | ||
| 2227 | if (err) | ||
| 2228 | return err; | ||
| 2229 | |||
| 2230 | /* Mirror */ | ||
| 2231 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR, | ||
| 2232 | cam->mirror); | ||
| 2233 | if (err) | ||
| 2234 | return err; | ||
| 2235 | |||
| 2236 | return 0; | ||
| 2237 | } | ||
| 2238 | |||
| 2239 | |||
| 2240 | /*-------------------------------------------------------------------------- | ||
| 2241 | Get some current picture settings from the image sensor and update the | ||
| 2242 | internal 'picture' structure of the camera. | ||
| 2243 | Returns: 0 on success, a negative number otherwise. | ||
| 2244 | --------------------------------------------------------------------------*/ | ||
| 2245 | static int w9968cf_sensor_get_picture(struct w9968cf_device* cam) | ||
| 2246 | { | ||
| 2247 | int err, v; | ||
| 2248 | |||
| 2249 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v); | ||
| 2250 | if (err) | ||
| 2251 | return err; | ||
| 2252 | cam->picture.contrast = v; | ||
| 2253 | |||
| 2254 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v); | ||
| 2255 | if (err) | ||
| 2256 | return err; | ||
| 2257 | cam->picture.brightness = v; | ||
| 2258 | |||
| 2259 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v); | ||
| 2260 | if (err) | ||
| 2261 | return err; | ||
| 2262 | cam->picture.colour = v; | ||
| 2263 | |||
| 2264 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v); | ||
| 2265 | if (err) | ||
| 2266 | return err; | ||
| 2267 | cam->picture.hue = v; | ||
| 2268 | |||
| 2269 | DBG(5, "Got picture settings from the image sensor") | ||
| 2270 | |||
| 2271 | PDBGG("Brightness, contrast, hue, colour, whiteness are " | ||
| 2272 | "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast, | ||
| 2273 | cam->picture.hue, cam->picture.colour, cam->picture.whiteness) | ||
| 2274 | |||
| 2275 | return 0; | ||
| 2276 | } | ||
| 2277 | |||
| 2278 | |||
| 2279 | /*-------------------------------------------------------------------------- | ||
| 2280 | Update picture settings of the image sensor. | ||
| 2281 | Returns: 0 on success, a negative number otherwise. | ||
| 2282 | --------------------------------------------------------------------------*/ | ||
| 2283 | static int | ||
| 2284 | w9968cf_sensor_update_picture(struct w9968cf_device* cam, | ||
| 2285 | struct video_picture pict) | ||
| 2286 | { | ||
| 2287 | int err = 0; | ||
| 2288 | |||
| 2289 | if ((!cam->sensor_initialized) | ||
| 2290 | || pict.contrast != cam->picture.contrast) { | ||
| 2291 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT, | ||
| 2292 | pict.contrast); | ||
| 2293 | if (err) | ||
| 2294 | goto fail; | ||
| 2295 | DBG(4, "Contrast changed from %u to %u", | ||
| 2296 | cam->picture.contrast, pict.contrast) | ||
| 2297 | cam->picture.contrast = pict.contrast; | ||
| 2298 | } | ||
| 2299 | |||
| 2300 | if (((!cam->sensor_initialized) || | ||
| 2301 | pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) { | ||
| 2302 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, | ||
| 2303 | pict.brightness); | ||
| 2304 | if (err) | ||
| 2305 | goto fail; | ||
| 2306 | DBG(4, "Brightness changed from %u to %u", | ||
| 2307 | cam->picture.brightness, pict.brightness) | ||
| 2308 | cam->picture.brightness = pict.brightness; | ||
| 2309 | } | ||
| 2310 | |||
| 2311 | if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) { | ||
| 2312 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, | ||
| 2313 | pict.colour); | ||
| 2314 | if (err) | ||
| 2315 | goto fail; | ||
| 2316 | DBG(4, "Colour changed from %u to %u", | ||
| 2317 | cam->picture.colour, pict.colour) | ||
| 2318 | cam->picture.colour = pict.colour; | ||
| 2319 | } | ||
| 2320 | |||
| 2321 | if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) { | ||
| 2322 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, | ||
| 2323 | pict.hue); | ||
| 2324 | if (err) | ||
| 2325 | goto fail; | ||
| 2326 | DBG(4, "Hue changed from %u to %u", | ||
| 2327 | cam->picture.hue, pict.hue) | ||
| 2328 | cam->picture.hue = pict.hue; | ||
| 2329 | } | ||
| 2330 | |||
| 2331 | return 0; | ||
| 2332 | |||
| 2333 | fail: | ||
| 2334 | DBG(4, "Failed to change sensor picture setting") | ||
| 2335 | return err; | ||
| 2336 | } | ||
| 2337 | |||
| 2338 | |||
| 2339 | |||
| 2340 | /**************************************************************************** | ||
| 2341 | * Camera configuration * | ||
| 2342 | ****************************************************************************/ | ||
| 2343 | |||
| 2344 | /*-------------------------------------------------------------------------- | ||
| 2345 | This function is called when a supported image sensor is detected. | ||
| 2346 | Return 0 if the initialization succeeds, a negative number otherwise. | ||
| 2347 | --------------------------------------------------------------------------*/ | ||
| 2348 | static int w9968cf_sensor_init(struct w9968cf_device* cam) | ||
| 2349 | { | ||
| 2350 | int err = 0; | ||
| 2351 | |||
| 2352 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, | ||
| 2353 | &cam->monochrome))) | ||
| 2354 | goto error; | ||
| 2355 | |||
| 2356 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, | ||
| 2357 | &cam->sensor))) | ||
| 2358 | goto error; | ||
| 2359 | |||
| 2360 | /* NOTE: Make sure width and height are a multiple of 16 */ | ||
| 2361 | switch (cam->sensor_client->addr) { | ||
| 2362 | case OV6xx0_SID: | ||
| 2363 | cam->maxwidth = 352; | ||
| 2364 | cam->maxheight = 288; | ||
| 2365 | cam->minwidth = 64; | ||
| 2366 | cam->minheight = 48; | ||
| 2367 | break; | ||
| 2368 | case OV7xx0_SID: | ||
| 2369 | cam->maxwidth = 640; | ||
| 2370 | cam->maxheight = 480; | ||
| 2371 | cam->minwidth = 64; | ||
| 2372 | cam->minheight = 48; | ||
| 2373 | break; | ||
| 2374 | default: | ||
| 2375 | DBG(1, "Not supported image sensor detected for %s", | ||
| 2376 | symbolic(camlist, cam->id)) | ||
| 2377 | return -EINVAL; | ||
| 2378 | } | ||
| 2379 | |||
| 2380 | /* These values depend on the ones in the ovxxx0.c sources */ | ||
| 2381 | switch (cam->sensor) { | ||
| 2382 | case CC_OV7620: | ||
| 2383 | cam->start_cropx = 287; | ||
| 2384 | cam->start_cropy = 35; | ||
| 2385 | /* Seems to work around a bug in the image sensor */ | ||
| 2386 | cam->vs_polarity = 1; | ||
| 2387 | cam->hs_polarity = 1; | ||
| 2388 | break; | ||
| 2389 | default: | ||
| 2390 | cam->start_cropx = 320; | ||
| 2391 | cam->start_cropy = 35; | ||
| 2392 | cam->vs_polarity = 1; | ||
| 2393 | cam->hs_polarity = 0; | ||
| 2394 | } | ||
| 2395 | |||
| 2396 | if ((err = w9968cf_sensor_update_settings(cam))) | ||
| 2397 | goto error; | ||
| 2398 | |||
| 2399 | if ((err = w9968cf_sensor_update_picture(cam, cam->picture))) | ||
| 2400 | goto error; | ||
| 2401 | |||
| 2402 | cam->sensor_initialized = 1; | ||
| 2403 | |||
| 2404 | DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor)) | ||
| 2405 | return 0; | ||
| 2406 | |||
| 2407 | error: | ||
| 2408 | cam->sensor_initialized = 0; | ||
| 2409 | cam->sensor = CC_UNKNOWN; | ||
| 2410 | DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " | ||
| 2411 | "Try to detach and attach this device again", | ||
| 2412 | symbolic(camlist, cam->id), cam->v4ldev->minor) | ||
| 2413 | return err; | ||
| 2414 | } | ||
| 2415 | |||
| 2416 | |||
| 2417 | /*-------------------------------------------------------------------------- | ||
| 2418 | Fill some basic fields in the main device data structure. | ||
| 2419 | This function is called once on w9968cf_usb_probe() for each recognized | ||
| 2420 | camera. | ||
| 2421 | --------------------------------------------------------------------------*/ | ||
| 2422 | static void | ||
| 2423 | w9968cf_configure_camera(struct w9968cf_device* cam, | ||
| 2424 | struct usb_device* udev, | ||
| 2425 | enum w9968cf_model_id mod_id, | ||
| 2426 | const unsigned short dev_nr) | ||
| 2427 | { | ||
| 2428 | mutex_init(&cam->fileop_mutex); | ||
| 2429 | init_waitqueue_head(&cam->open); | ||
| 2430 | spin_lock_init(&cam->urb_lock); | ||
| 2431 | spin_lock_init(&cam->flist_lock); | ||
| 2432 | |||
| 2433 | cam->users = 0; | ||
| 2434 | cam->disconnected = 0; | ||
| 2435 | cam->id = mod_id; | ||
| 2436 | cam->sensor = CC_UNKNOWN; | ||
| 2437 | cam->sensor_initialized = 0; | ||
| 2438 | |||
| 2439 | /* Calculate the alternate setting number (from 1 to 16) | ||
| 2440 | according to the 'packet_size' module parameter */ | ||
| 2441 | if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE) | ||
| 2442 | packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE; | ||
| 2443 | for (cam->altsetting = 1; | ||
| 2444 | packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1]; | ||
| 2445 | cam->altsetting++); | ||
| 2446 | |||
| 2447 | cam->max_buffers = (max_buffers[dev_nr] < 2 || | ||
| 2448 | max_buffers[dev_nr] > W9968CF_MAX_BUFFERS) | ||
| 2449 | ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr]; | ||
| 2450 | |||
| 2451 | cam->double_buffer = (double_buffer[dev_nr] == 0 || | ||
| 2452 | double_buffer[dev_nr] == 1) | ||
| 2453 | ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER; | ||
| 2454 | |||
| 2455 | cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1) | ||
| 2456 | ? (u8)clamping[dev_nr] : W9968CF_CLAMPING; | ||
| 2457 | |||
| 2458 | cam->filter_type = (filter_type[dev_nr] == 0 || | ||
| 2459 | filter_type[dev_nr] == 1 || | ||
| 2460 | filter_type[dev_nr] == 2) | ||
| 2461 | ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE; | ||
| 2462 | |||
| 2463 | cam->capture = 1; | ||
| 2464 | |||
| 2465 | cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1) | ||
| 2466 | ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW; | ||
| 2467 | |||
| 2468 | cam->decompression = (decompression[dev_nr] == 0 || | ||
| 2469 | decompression[dev_nr] == 1 || | ||
| 2470 | decompression[dev_nr] == 2) | ||
| 2471 | ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION; | ||
| 2472 | |||
| 2473 | cam->upscaling = (upscaling[dev_nr] == 0 || | ||
| 2474 | upscaling[dev_nr] == 1) | ||
| 2475 | ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING; | ||
| 2476 | |||
| 2477 | cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1) | ||
| 2478 | ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT; | ||
| 2479 | |||
| 2480 | cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1) | ||
| 2481 | ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP; | ||
| 2482 | |||
| 2483 | cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60) | ||
| 2484 | ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ; | ||
| 2485 | |||
| 2486 | cam->bandfilt = (bandingfilter[dev_nr] == 0 || | ||
| 2487 | bandingfilter[dev_nr] == 1) | ||
| 2488 | ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER; | ||
| 2489 | |||
| 2490 | cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1) | ||
| 2491 | ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT; | ||
| 2492 | |||
| 2493 | cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0) | ||
| 2494 | ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV; | ||
| 2495 | |||
| 2496 | cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1) | ||
| 2497 | ? (u8)mirror[dev_nr] : W9968CF_MIRROR; | ||
| 2498 | |||
| 2499 | cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1) | ||
| 2500 | ? monochrome[dev_nr] : W9968CF_MONOCHROME; | ||
| 2501 | |||
| 2502 | cam->picture.brightness = (u16)brightness[dev_nr]; | ||
| 2503 | cam->picture.hue = (u16)hue[dev_nr]; | ||
| 2504 | cam->picture.colour = (u16)colour[dev_nr]; | ||
| 2505 | cam->picture.contrast = (u16)contrast[dev_nr]; | ||
| 2506 | cam->picture.whiteness = (u16)whiteness[dev_nr]; | ||
| 2507 | if (w9968cf_valid_palette((u16)force_palette[dev_nr])) { | ||
| 2508 | cam->picture.palette = (u16)force_palette[dev_nr]; | ||
| 2509 | cam->force_palette = 1; | ||
| 2510 | } else { | ||
| 2511 | cam->force_palette = 0; | ||
| 2512 | if (cam->decompression == 0) | ||
| 2513 | cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF; | ||
| 2514 | else if (cam->decompression == 1) | ||
| 2515 | cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE; | ||
| 2516 | else | ||
| 2517 | cam->picture.palette = W9968CF_PALETTE_DECOMP_ON; | ||
| 2518 | } | ||
| 2519 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); | ||
| 2520 | |||
| 2521 | cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1) | ||
| 2522 | ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB; | ||
| 2523 | |||
| 2524 | cam->window.x = 0; | ||
| 2525 | cam->window.y = 0; | ||
| 2526 | cam->window.width = W9968CF_WIDTH; | ||
| 2527 | cam->window.height = W9968CF_HEIGHT; | ||
| 2528 | cam->window.chromakey = 0; | ||
| 2529 | cam->window.clipcount = 0; | ||
| 2530 | cam->window.flags = 0; | ||
| 2531 | |||
| 2532 | DBG(3, "%s configured with settings #%u:", | ||
| 2533 | symbolic(camlist, cam->id), dev_nr) | ||
| 2534 | |||
| 2535 | DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes", | ||
| 2536 | wMaxPacketSize[cam->altsetting-1]) | ||
| 2537 | |||
| 2538 | DBG(3, "- Number of requested video frame buffers: %u", | ||
| 2539 | cam->max_buffers) | ||
| 2540 | |||
| 2541 | if (cam->double_buffer) | ||
| 2542 | DBG(3, "- Hardware double buffering enabled") | ||
| 2543 | else | ||
| 2544 | DBG(3, "- Hardware double buffering disabled") | ||
| 2545 | |||
| 2546 | if (cam->filter_type == 0) | ||
| 2547 | DBG(3, "- Video filtering disabled") | ||
| 2548 | else if (cam->filter_type == 1) | ||
| 2549 | DBG(3, "- Video filtering enabled: type 1-2-1") | ||
| 2550 | else if (cam->filter_type == 2) | ||
| 2551 | DBG(3, "- Video filtering enabled: type 2-3-6-3-2") | ||
| 2552 | |||
| 2553 | if (cam->clamping) | ||
| 2554 | DBG(3, "- Video data clamping (CCIR-601 format) enabled") | ||
| 2555 | else | ||
| 2556 | DBG(3, "- Video data clamping (CCIR-601 format) disabled") | ||
| 2557 | |||
| 2558 | if (cam->largeview) | ||
| 2559 | DBG(3, "- Large view enabled") | ||
| 2560 | else | ||
| 2561 | DBG(3, "- Large view disabled") | ||
| 2562 | |||
| 2563 | if ((cam->decompression) == 0 && (!cam->force_palette)) | ||
| 2564 | DBG(3, "- Decompression disabled") | ||
| 2565 | else if ((cam->decompression) == 1 && (!cam->force_palette)) | ||
| 2566 | DBG(3, "- Decompression forced") | ||
| 2567 | else if ((cam->decompression) == 2 && (!cam->force_palette)) | ||
| 2568 | DBG(3, "- Decompression allowed") | ||
| 2569 | |||
| 2570 | if (cam->upscaling) | ||
| 2571 | DBG(3, "- Software image scaling enabled") | ||
| 2572 | else | ||
| 2573 | DBG(3, "- Software image scaling disabled") | ||
| 2574 | |||
| 2575 | if (cam->force_palette) | ||
| 2576 | DBG(3, "- Image palette forced to %s", | ||
| 2577 | symbolic(v4l1_plist, cam->picture.palette)) | ||
| 2578 | |||
| 2579 | if (cam->force_rgb) | ||
| 2580 | DBG(3, "- RGB component ordering will be used instead of BGR") | ||
| 2581 | |||
| 2582 | if (cam->auto_brt) | ||
| 2583 | DBG(3, "- Auto brightness enabled") | ||
| 2584 | else | ||
| 2585 | DBG(3, "- Auto brightness disabled") | ||
| 2586 | |||
| 2587 | if (cam->auto_exp) | ||
| 2588 | DBG(3, "- Auto exposure enabled") | ||
| 2589 | else | ||
| 2590 | DBG(3, "- Auto exposure disabled") | ||
| 2591 | |||
| 2592 | if (cam->backlight) | ||
| 2593 | DBG(3, "- Backlight exposure algorithm enabled") | ||
| 2594 | else | ||
| 2595 | DBG(3, "- Backlight exposure algorithm disabled") | ||
| 2596 | |||
| 2597 | if (cam->mirror) | ||
| 2598 | DBG(3, "- Mirror enabled") | ||
| 2599 | else | ||
| 2600 | DBG(3, "- Mirror disabled") | ||
| 2601 | |||
| 2602 | if (cam->bandfilt) | ||
| 2603 | DBG(3, "- Banding filter enabled") | ||
| 2604 | else | ||
| 2605 | DBG(3, "- Banding filter disabled") | ||
| 2606 | |||
| 2607 | DBG(3, "- Power lighting frequency: %u", cam->lightfreq) | ||
| 2608 | |||
| 2609 | if (cam->clockdiv == -1) | ||
| 2610 | DBG(3, "- Automatic clock divisor enabled") | ||
| 2611 | else | ||
| 2612 | DBG(3, "- Clock divisor: %d", cam->clockdiv) | ||
| 2613 | |||
| 2614 | if (cam->monochrome) | ||
| 2615 | DBG(3, "- Image sensor used as monochrome") | ||
| 2616 | else | ||
| 2617 | DBG(3, "- Image sensor not used as monochrome") | ||
| 2618 | } | ||
| 2619 | |||
| 2620 | |||
| 2621 | /*-------------------------------------------------------------------------- | ||
| 2622 | If the video post-processing module is not loaded, some parameters | ||
| 2623 | must be overridden. | ||
| 2624 | --------------------------------------------------------------------------*/ | ||
| 2625 | static void w9968cf_adjust_configuration(struct w9968cf_device* cam) | ||
| 2626 | { | ||
| 2627 | if (!w9968cf_vpp) { | ||
| 2628 | if (cam->decompression == 1) { | ||
| 2629 | cam->decompression = 2; | ||
| 2630 | DBG(2, "Video post-processing module not found: " | ||
| 2631 | "'decompression' parameter forced to 2") | ||
| 2632 | } | ||
| 2633 | if (cam->upscaling) { | ||
| 2634 | cam->upscaling = 0; | ||
| 2635 | DBG(2, "Video post-processing module not found: " | ||
| 2636 | "'upscaling' parameter forced to 0") | ||
| 2637 | } | ||
| 2638 | if (cam->picture.palette != VIDEO_PALETTE_UYVY) { | ||
| 2639 | cam->force_palette = 0; | ||
| 2640 | DBG(2, "Video post-processing module not found: " | ||
| 2641 | "'force_palette' parameter forced to 0") | ||
| 2642 | } | ||
| 2643 | cam->picture.palette = VIDEO_PALETTE_UYVY; | ||
| 2644 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); | ||
| 2645 | } | ||
| 2646 | } | ||
| 2647 | |||
| 2648 | |||
| 2649 | /*-------------------------------------------------------------------------- | ||
| 2650 | Release the resources used by the driver. | ||
| 2651 | This function is called on disconnect | ||
| 2652 | (or on close if deallocation has been deferred) | ||
| 2653 | --------------------------------------------------------------------------*/ | ||
| 2654 | static void w9968cf_release_resources(struct w9968cf_device* cam) | ||
| 2655 | { | ||
| 2656 | mutex_lock(&w9968cf_devlist_mutex); | ||
| 2657 | |||
| 2658 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) | ||
| 2659 | |||
| 2660 | video_unregister_device(cam->v4ldev); | ||
| 2661 | list_del(&cam->v4llist); | ||
| 2662 | i2c_del_adapter(&cam->i2c_adapter); | ||
| 2663 | w9968cf_deallocate_memory(cam); | ||
| 2664 | kfree(cam->control_buffer); | ||
| 2665 | kfree(cam->data_buffer); | ||
| 2666 | |||
| 2667 | mutex_unlock(&w9968cf_devlist_mutex); | ||
| 2668 | } | ||
| 2669 | |||
| 2670 | |||
| 2671 | |||
| 2672 | /**************************************************************************** | ||
| 2673 | * Video4Linux interface * | ||
| 2674 | ****************************************************************************/ | ||
| 2675 | |||
| 2676 | static int w9968cf_open(struct inode* inode, struct file* filp) | ||
| 2677 | { | ||
| 2678 | struct w9968cf_device* cam; | ||
| 2679 | int err; | ||
| 2680 | |||
| 2681 | /* This the only safe way to prevent race conditions with disconnect */ | ||
| 2682 | if (!down_read_trylock(&w9968cf_disconnect)) | ||
| 2683 | return -ERESTARTSYS; | ||
| 2684 | |||
| 2685 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
| 2686 | |||
| 2687 | mutex_lock(&cam->dev_mutex); | ||
| 2688 | |||
| 2689 | if (cam->sensor == CC_UNKNOWN) { | ||
| 2690 | DBG(2, "No supported image sensor has been detected by the " | ||
| 2691 | "'ovcamchip' module for the %s (/dev/video%d). Make " | ||
| 2692 | "sure it is loaded *before* (re)connecting the camera.", | ||
| 2693 | symbolic(camlist, cam->id), cam->v4ldev->minor) | ||
| 2694 | mutex_unlock(&cam->dev_mutex); | ||
| 2695 | up_read(&w9968cf_disconnect); | ||
| 2696 | return -ENODEV; | ||
| 2697 | } | ||
| 2698 | |||
| 2699 | if (cam->users) { | ||
| 2700 | DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", | ||
| 2701 | symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) | ||
| 2702 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { | ||
| 2703 | mutex_unlock(&cam->dev_mutex); | ||
| 2704 | up_read(&w9968cf_disconnect); | ||
| 2705 | return -EWOULDBLOCK; | ||
| 2706 | } | ||
| 2707 | mutex_unlock(&cam->dev_mutex); | ||
| 2708 | err = wait_event_interruptible_exclusive(cam->open, | ||
| 2709 | cam->disconnected || | ||
| 2710 | !cam->users); | ||
| 2711 | if (err) { | ||
| 2712 | up_read(&w9968cf_disconnect); | ||
| 2713 | return err; | ||
| 2714 | } | ||
| 2715 | if (cam->disconnected) { | ||
| 2716 | up_read(&w9968cf_disconnect); | ||
| 2717 | return -ENODEV; | ||
| 2718 | } | ||
| 2719 | mutex_lock(&cam->dev_mutex); | ||
| 2720 | } | ||
| 2721 | |||
| 2722 | DBG(5, "Opening '%s', /dev/video%d ...", | ||
| 2723 | symbolic(camlist, cam->id), cam->v4ldev->minor) | ||
| 2724 | |||
| 2725 | cam->streaming = 0; | ||
| 2726 | cam->misconfigured = 0; | ||
| 2727 | |||
| 2728 | w9968cf_adjust_configuration(cam); | ||
| 2729 | |||
| 2730 | if ((err = w9968cf_allocate_memory(cam))) | ||
| 2731 | goto deallocate_memory; | ||
| 2732 | |||
| 2733 | if ((err = w9968cf_init_chip(cam))) | ||
| 2734 | goto deallocate_memory; | ||
| 2735 | |||
| 2736 | if ((err = w9968cf_start_transfer(cam))) | ||
| 2737 | goto deallocate_memory; | ||
| 2738 | |||
| 2739 | filp->private_data = cam; | ||
| 2740 | |||
| 2741 | cam->users++; | ||
| 2742 | strcpy(cam->command, current->comm); | ||
| 2743 | |||
| 2744 | init_waitqueue_head(&cam->wait_queue); | ||
| 2745 | |||
| 2746 | DBG(5, "Video device is open") | ||
| 2747 | |||
| 2748 | mutex_unlock(&cam->dev_mutex); | ||
| 2749 | up_read(&w9968cf_disconnect); | ||
| 2750 | |||
| 2751 | return 0; | ||
| 2752 | |||
| 2753 | deallocate_memory: | ||
| 2754 | w9968cf_deallocate_memory(cam); | ||
| 2755 | DBG(2, "Failed to open the video device") | ||
| 2756 | mutex_unlock(&cam->dev_mutex); | ||
| 2757 | up_read(&w9968cf_disconnect); | ||
| 2758 | return err; | ||
| 2759 | } | ||
| 2760 | |||
| 2761 | |||
| 2762 | static int w9968cf_release(struct inode* inode, struct file* filp) | ||
| 2763 | { | ||
| 2764 | struct w9968cf_device* cam; | ||
| 2765 | |||
| 2766 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
| 2767 | |||
| 2768 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ | ||
| 2769 | |||
| 2770 | w9968cf_stop_transfer(cam); | ||
| 2771 | |||
| 2772 | if (cam->disconnected) { | ||
| 2773 | w9968cf_release_resources(cam); | ||
| 2774 | mutex_unlock(&cam->dev_mutex); | ||
| 2775 | kfree(cam); | ||
| 2776 | return 0; | ||
| 2777 | } | ||
| 2778 | |||
| 2779 | cam->users--; | ||
| 2780 | w9968cf_deallocate_memory(cam); | ||
| 2781 | wake_up_interruptible_nr(&cam->open, 1); | ||
| 2782 | |||
| 2783 | DBG(5, "Video device closed") | ||
| 2784 | mutex_unlock(&cam->dev_mutex); | ||
| 2785 | return 0; | ||
| 2786 | } | ||
| 2787 | |||
| 2788 | |||
| 2789 | static ssize_t | ||
| 2790 | w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | ||
| 2791 | { | ||
| 2792 | struct w9968cf_device* cam; | ||
| 2793 | struct w9968cf_frame_t* fr; | ||
| 2794 | int err = 0; | ||
| 2795 | |||
| 2796 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
| 2797 | |||
| 2798 | if (filp->f_flags & O_NONBLOCK) | ||
| 2799 | return -EWOULDBLOCK; | ||
| 2800 | |||
| 2801 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 2802 | return -ERESTARTSYS; | ||
| 2803 | |||
| 2804 | if (cam->disconnected) { | ||
| 2805 | DBG(2, "Device not present") | ||
| 2806 | mutex_unlock(&cam->fileop_mutex); | ||
| 2807 | return -ENODEV; | ||
| 2808 | } | ||
| 2809 | |||
| 2810 | if (cam->misconfigured) { | ||
| 2811 | DBG(2, "The camera is misconfigured. Close and open it again.") | ||
| 2812 | mutex_unlock(&cam->fileop_mutex); | ||
| 2813 | return -EIO; | ||
| 2814 | } | ||
| 2815 | |||
| 2816 | if (!cam->frame[0].queued) | ||
| 2817 | w9968cf_push_frame(cam, 0); | ||
| 2818 | |||
| 2819 | if (!cam->frame[1].queued) | ||
| 2820 | w9968cf_push_frame(cam, 1); | ||
| 2821 | |||
| 2822 | err = wait_event_interruptible(cam->wait_queue, | ||
| 2823 | cam->frame[0].status == F_READY || | ||
| 2824 | cam->frame[1].status == F_READY || | ||
| 2825 | cam->disconnected); | ||
| 2826 | if (err) { | ||
| 2827 | mutex_unlock(&cam->fileop_mutex); | ||
| 2828 | return err; | ||
| 2829 | } | ||
| 2830 | if (cam->disconnected) { | ||
| 2831 | mutex_unlock(&cam->fileop_mutex); | ||
| 2832 | return -ENODEV; | ||
| 2833 | } | ||
| 2834 | |||
| 2835 | fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1]; | ||
| 2836 | |||
| 2837 | if (w9968cf_vpp) | ||
| 2838 | w9968cf_postprocess_frame(cam, fr); | ||
| 2839 | |||
| 2840 | if (count > fr->length) | ||
| 2841 | count = fr->length; | ||
| 2842 | |||
| 2843 | if (copy_to_user(buf, fr->buffer, count)) { | ||
| 2844 | fr->status = F_UNUSED; | ||
| 2845 | mutex_unlock(&cam->fileop_mutex); | ||
| 2846 | return -EFAULT; | ||
| 2847 | } | ||
| 2848 | *f_pos += count; | ||
| 2849 | |||
| 2850 | fr->status = F_UNUSED; | ||
| 2851 | |||
| 2852 | DBG(5, "%zu bytes read", count) | ||
| 2853 | |||
| 2854 | mutex_unlock(&cam->fileop_mutex); | ||
| 2855 | return count; | ||
| 2856 | } | ||
| 2857 | |||
| 2858 | |||
| 2859 | static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma) | ||
| 2860 | { | ||
| 2861 | struct w9968cf_device* cam = (struct w9968cf_device*) | ||
| 2862 | video_get_drvdata(video_devdata(filp)); | ||
| 2863 | unsigned long vsize = vma->vm_end - vma->vm_start, | ||
| 2864 | psize = cam->nbuffers * cam->frame[0].size, | ||
| 2865 | start = vma->vm_start, | ||
| 2866 | pos = (unsigned long)cam->frame[0].buffer, | ||
| 2867 | page; | ||
| 2868 | |||
| 2869 | if (cam->disconnected) { | ||
| 2870 | DBG(2, "Device not present") | ||
| 2871 | return -ENODEV; | ||
| 2872 | } | ||
| 2873 | |||
| 2874 | if (cam->misconfigured) { | ||
| 2875 | DBG(2, "The camera is misconfigured. Close and open it again") | ||
| 2876 | return -EIO; | ||
| 2877 | } | ||
| 2878 | |||
| 2879 | PDBGG("mmapping %lu bytes...", vsize) | ||
| 2880 | |||
| 2881 | if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) | ||
| 2882 | return -EINVAL; | ||
| 2883 | |||
| 2884 | while (vsize > 0) { | ||
| 2885 | page = vmalloc_to_pfn((void *)pos); | ||
| 2886 | if (remap_pfn_range(vma, start, page + vma->vm_pgoff, | ||
| 2887 | PAGE_SIZE, vma->vm_page_prot)) | ||
| 2888 | return -EAGAIN; | ||
| 2889 | start += PAGE_SIZE; | ||
| 2890 | pos += PAGE_SIZE; | ||
| 2891 | vsize -= PAGE_SIZE; | ||
| 2892 | } | ||
| 2893 | |||
| 2894 | DBG(5, "mmap method successfully called") | ||
| 2895 | return 0; | ||
| 2896 | } | ||
| 2897 | |||
| 2898 | |||
| 2899 | static int | ||
| 2900 | w9968cf_ioctl(struct inode* inode, struct file* filp, | ||
| 2901 | unsigned int cmd, unsigned long arg) | ||
| 2902 | { | ||
| 2903 | struct w9968cf_device* cam; | ||
| 2904 | int err; | ||
| 2905 | |||
| 2906 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
| 2907 | |||
| 2908 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 2909 | return -ERESTARTSYS; | ||
| 2910 | |||
| 2911 | if (cam->disconnected) { | ||
| 2912 | DBG(2, "Device not present") | ||
| 2913 | mutex_unlock(&cam->fileop_mutex); | ||
| 2914 | return -ENODEV; | ||
| 2915 | } | ||
| 2916 | |||
| 2917 | if (cam->misconfigured) { | ||
| 2918 | DBG(2, "The camera is misconfigured. Close and open it again.") | ||
| 2919 | mutex_unlock(&cam->fileop_mutex); | ||
| 2920 | return -EIO; | ||
| 2921 | } | ||
| 2922 | |||
| 2923 | err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); | ||
| 2924 | |||
| 2925 | mutex_unlock(&cam->fileop_mutex); | ||
| 2926 | return err; | ||
| 2927 | } | ||
| 2928 | |||
| 2929 | |||
| 2930 | static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, | ||
| 2931 | unsigned int cmd, void __user * arg) | ||
| 2932 | { | ||
| 2933 | struct w9968cf_device* cam; | ||
| 2934 | const char* v4l1_ioctls[] = { | ||
| 2935 | "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", | ||
| 2936 | "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", | ||
| 2937 | "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO", | ||
| 2938 | "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE", | ||
| 2939 | "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", | ||
| 2940 | "GVBIFMT", "SVBIFMT" | ||
| 2941 | }; | ||
| 2942 | |||
| 2943 | #define V4L1_IOCTL(cmd) \ | ||
| 2944 | ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \ | ||
| 2945 | v4l1_ioctls[_IOC_NR((cmd))] : "?") | ||
| 2946 | |||
| 2947 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
| 2948 | |||
| 2949 | switch (cmd) { | ||
| 2950 | |||
| 2951 | case VIDIOCGCAP: /* get video capability */ | ||
| 2952 | { | ||
| 2953 | struct video_capability cap = { | ||
| 2954 | .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, | ||
| 2955 | .channels = 1, | ||
| 2956 | .audios = 0, | ||
| 2957 | .minwidth = cam->minwidth, | ||
| 2958 | .minheight = cam->minheight, | ||
| 2959 | }; | ||
| 2960 | sprintf(cap.name, "W996[87]CF USB Camera #%d", | ||
| 2961 | cam->v4ldev->minor); | ||
| 2962 | cap.maxwidth = (cam->upscaling && w9968cf_vpp) | ||
| 2963 | ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) | ||
| 2964 | : cam->maxwidth; | ||
| 2965 | cap.maxheight = (cam->upscaling && w9968cf_vpp) | ||
| 2966 | ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) | ||
| 2967 | : cam->maxheight; | ||
| 2968 | |||
| 2969 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
| 2970 | return -EFAULT; | ||
| 2971 | |||
| 2972 | DBG(5, "VIDIOCGCAP successfully called") | ||
| 2973 | return 0; | ||
| 2974 | } | ||
| 2975 | |||
| 2976 | case VIDIOCGCHAN: /* get video channel informations */ | ||
| 2977 | { | ||
| 2978 | struct video_channel chan; | ||
| 2979 | if (copy_from_user(&chan, arg, sizeof(chan))) | ||
| 2980 | return -EFAULT; | ||
| 2981 | |||
| 2982 | if (chan.channel != 0) | ||
| 2983 | return -EINVAL; | ||
| 2984 | |||
| 2985 | strcpy(chan.name, "Camera"); | ||
| 2986 | chan.tuners = 0; | ||
| 2987 | chan.flags = 0; | ||
| 2988 | chan.type = VIDEO_TYPE_CAMERA; | ||
| 2989 | chan.norm = VIDEO_MODE_AUTO; | ||
| 2990 | |||
| 2991 | if (copy_to_user(arg, &chan, sizeof(chan))) | ||
| 2992 | return -EFAULT; | ||
| 2993 | |||
| 2994 | DBG(5, "VIDIOCGCHAN successfully called") | ||
| 2995 | return 0; | ||
| 2996 | } | ||
| 2997 | |||
| 2998 | case VIDIOCSCHAN: /* set active channel */ | ||
| 2999 | { | ||
| 3000 | struct video_channel chan; | ||
| 3001 | |||
| 3002 | if (copy_from_user(&chan, arg, sizeof(chan))) | ||
| 3003 | return -EFAULT; | ||
| 3004 | |||
| 3005 | if (chan.channel != 0) | ||
| 3006 | return -EINVAL; | ||
| 3007 | |||
| 3008 | DBG(5, "VIDIOCSCHAN successfully called") | ||
| 3009 | return 0; | ||
| 3010 | } | ||
| 3011 | |||
| 3012 | case VIDIOCGPICT: /* get image properties of the picture */ | ||
| 3013 | { | ||
| 3014 | if (w9968cf_sensor_get_picture(cam)) | ||
| 3015 | return -EIO; | ||
| 3016 | |||
| 3017 | if (copy_to_user(arg, &cam->picture, sizeof(cam->picture))) | ||
| 3018 | return -EFAULT; | ||
| 3019 | |||
| 3020 | DBG(5, "VIDIOCGPICT successfully called") | ||
| 3021 | return 0; | ||
| 3022 | } | ||
| 3023 | |||
| 3024 | case VIDIOCSPICT: /* change picture settings */ | ||
| 3025 | { | ||
| 3026 | struct video_picture pict; | ||
| 3027 | int err = 0; | ||
| 3028 | |||
| 3029 | if (copy_from_user(&pict, arg, sizeof(pict))) | ||
| 3030 | return -EFAULT; | ||
| 3031 | |||
| 3032 | if ( (cam->force_palette || !w9968cf_vpp) | ||
| 3033 | && pict.palette != cam->picture.palette ) { | ||
| 3034 | DBG(4, "Palette %s rejected: only %s is allowed", | ||
| 3035 | symbolic(v4l1_plist, pict.palette), | ||
| 3036 | symbolic(v4l1_plist, cam->picture.palette)) | ||
| 3037 | return -EINVAL; | ||
| 3038 | } | ||
| 3039 | |||
| 3040 | if (!w9968cf_valid_palette(pict.palette)) { | ||
| 3041 | DBG(4, "Palette %s not supported. VIDIOCSPICT failed", | ||
| 3042 | symbolic(v4l1_plist, pict.palette)) | ||
| 3043 | return -EINVAL; | ||
| 3044 | } | ||
| 3045 | |||
| 3046 | if (!cam->force_palette) { | ||
| 3047 | if (cam->decompression == 0) { | ||
| 3048 | if (w9968cf_need_decompression(pict.palette)) { | ||
| 3049 | DBG(4, "Decompression disabled: palette %s is not " | ||
| 3050 | "allowed. VIDIOCSPICT failed", | ||
| 3051 | symbolic(v4l1_plist, pict.palette)) | ||
| 3052 | return -EINVAL; | ||
| 3053 | } | ||
| 3054 | } else if (cam->decompression == 1) { | ||
| 3055 | if (!w9968cf_need_decompression(pict.palette)) { | ||
| 3056 | DBG(4, "Decompression forced: palette %s is not " | ||
| 3057 | "allowed. VIDIOCSPICT failed", | ||
| 3058 | symbolic(v4l1_plist, pict.palette)) | ||
| 3059 | return -EINVAL; | ||
| 3060 | } | ||
| 3061 | } | ||
| 3062 | } | ||
| 3063 | |||
| 3064 | if (pict.depth != w9968cf_valid_depth(pict.palette)) { | ||
| 3065 | DBG(4, "Requested depth %u bpp is not valid for %s " | ||
| 3066 | "palette: ignored and changed to %u bpp", | ||
| 3067 | pict.depth, symbolic(v4l1_plist, pict.palette), | ||
| 3068 | w9968cf_valid_depth(pict.palette)) | ||
| 3069 | pict.depth = w9968cf_valid_depth(pict.palette); | ||
| 3070 | } | ||
| 3071 | |||
| 3072 | if (pict.palette != cam->picture.palette) { | ||
| 3073 | if(*cam->requested_frame | ||
| 3074 | || cam->frame_current->queued) { | ||
| 3075 | err = wait_event_interruptible | ||
| 3076 | ( cam->wait_queue, | ||
| 3077 | cam->disconnected || | ||
| 3078 | (!*cam->requested_frame && | ||
| 3079 | !cam->frame_current->queued) ); | ||
| 3080 | if (err) | ||
| 3081 | return err; | ||
| 3082 | if (cam->disconnected) | ||
| 3083 | return -ENODEV; | ||
| 3084 | } | ||
| 3085 | |||
| 3086 | if (w9968cf_stop_transfer(cam)) | ||
| 3087 | goto ioctl_fail; | ||
| 3088 | |||
| 3089 | if (w9968cf_set_picture(cam, pict)) | ||
| 3090 | goto ioctl_fail; | ||
| 3091 | |||
| 3092 | if (w9968cf_start_transfer(cam)) | ||
| 3093 | goto ioctl_fail; | ||
| 3094 | |||
| 3095 | } else if (w9968cf_sensor_update_picture(cam, pict)) | ||
| 3096 | return -EIO; | ||
| 3097 | |||
| 3098 | |||
| 3099 | DBG(5, "VIDIOCSPICT successfully called") | ||
| 3100 | return 0; | ||
| 3101 | } | ||
| 3102 | |||
| 3103 | case VIDIOCSWIN: /* set capture area */ | ||
| 3104 | { | ||
| 3105 | struct video_window win; | ||
| 3106 | int err = 0; | ||
| 3107 | |||
| 3108 | if (copy_from_user(&win, arg, sizeof(win))) | ||
| 3109 | return -EFAULT; | ||
| 3110 | |||
| 3111 | DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, " | ||
| 3112 | "x=%u, y=%u, %ux%u", win.clipcount, win.flags, | ||
| 3113 | win.x, win.y, win.width, win.height) | ||
| 3114 | |||
| 3115 | if (win.clipcount != 0 || win.flags != 0) | ||
| 3116 | return -EINVAL; | ||
| 3117 | |||
| 3118 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, | ||
| 3119 | (u16*)&win.height))) { | ||
| 3120 | DBG(4, "Resolution not supported (%ux%u). " | ||
| 3121 | "VIDIOCSWIN failed", win.width, win.height) | ||
| 3122 | return err; | ||
| 3123 | } | ||
| 3124 | |||
| 3125 | if (win.x != cam->window.x || | ||
| 3126 | win.y != cam->window.y || | ||
| 3127 | win.width != cam->window.width || | ||
| 3128 | win.height != cam->window.height) { | ||
| 3129 | if(*cam->requested_frame | ||
| 3130 | || cam->frame_current->queued) { | ||
| 3131 | err = wait_event_interruptible | ||
| 3132 | ( cam->wait_queue, | ||
| 3133 | cam->disconnected || | ||
| 3134 | (!*cam->requested_frame && | ||
| 3135 | !cam->frame_current->queued) ); | ||
| 3136 | if (err) | ||
| 3137 | return err; | ||
| 3138 | if (cam->disconnected) | ||
| 3139 | return -ENODEV; | ||
| 3140 | } | ||
| 3141 | |||
| 3142 | if (w9968cf_stop_transfer(cam)) | ||
| 3143 | goto ioctl_fail; | ||
| 3144 | |||
| 3145 | /* This _must_ be called before set_window() */ | ||
| 3146 | if (w9968cf_set_picture(cam, cam->picture)) | ||
| 3147 | goto ioctl_fail; | ||
| 3148 | |||
| 3149 | if (w9968cf_set_window(cam, win)) | ||
| 3150 | goto ioctl_fail; | ||
| 3151 | |||
| 3152 | if (w9968cf_start_transfer(cam)) | ||
| 3153 | goto ioctl_fail; | ||
| 3154 | } | ||
| 3155 | |||
| 3156 | DBG(5, "VIDIOCSWIN successfully called. ") | ||
| 3157 | return 0; | ||
| 3158 | } | ||
| 3159 | |||
| 3160 | case VIDIOCGWIN: /* get current window properties */ | ||
| 3161 | { | ||
| 3162 | if (copy_to_user(arg,&cam->window,sizeof(struct video_window))) | ||
| 3163 | return -EFAULT; | ||
| 3164 | |||
| 3165 | DBG(5, "VIDIOCGWIN successfully called") | ||
| 3166 | return 0; | ||
| 3167 | } | ||
| 3168 | |||
| 3169 | case VIDIOCGMBUF: /* request for memory (mapped) buffer */ | ||
| 3170 | { | ||
| 3171 | struct video_mbuf mbuf; | ||
| 3172 | u8 i; | ||
| 3173 | |||
| 3174 | mbuf.size = cam->nbuffers * cam->frame[0].size; | ||
| 3175 | mbuf.frames = cam->nbuffers; | ||
| 3176 | for (i = 0; i < cam->nbuffers; i++) | ||
| 3177 | mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer - | ||
| 3178 | (unsigned long)cam->frame[0].buffer; | ||
| 3179 | |||
| 3180 | if (copy_to_user(arg, &mbuf, sizeof(mbuf))) | ||
| 3181 | return -EFAULT; | ||
| 3182 | |||
| 3183 | DBG(5, "VIDIOCGMBUF successfully called") | ||
| 3184 | return 0; | ||
| 3185 | } | ||
| 3186 | |||
| 3187 | case VIDIOCMCAPTURE: /* start the capture to a frame */ | ||
| 3188 | { | ||
| 3189 | struct video_mmap mmap; | ||
| 3190 | struct w9968cf_frame_t* fr; | ||
| 3191 | int err = 0; | ||
| 3192 | |||
| 3193 | if (copy_from_user(&mmap, arg, sizeof(mmap))) | ||
| 3194 | return -EFAULT; | ||
| 3195 | |||
| 3196 | DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d", | ||
| 3197 | mmap.frame, symbolic(v4l1_plist, mmap.format), | ||
| 3198 | mmap.width, mmap.height) | ||
| 3199 | |||
| 3200 | if (mmap.frame >= cam->nbuffers) { | ||
| 3201 | DBG(4, "Invalid frame number (%u). " | ||
| 3202 | "VIDIOCMCAPTURE failed", mmap.frame) | ||
| 3203 | return -EINVAL; | ||
| 3204 | } | ||
| 3205 | |||
| 3206 | if (mmap.format!=cam->picture.palette && | ||
| 3207 | (cam->force_palette || !w9968cf_vpp)) { | ||
| 3208 | DBG(4, "Palette %s rejected: only %s is allowed", | ||
| 3209 | symbolic(v4l1_plist, mmap.format), | ||
| 3210 | symbolic(v4l1_plist, cam->picture.palette)) | ||
| 3211 | return -EINVAL; | ||
| 3212 | } | ||
| 3213 | |||
| 3214 | if (!w9968cf_valid_palette(mmap.format)) { | ||
| 3215 | DBG(4, "Palette %s not supported. " | ||
| 3216 | "VIDIOCMCAPTURE failed", | ||
| 3217 | symbolic(v4l1_plist, mmap.format)) | ||
| 3218 | return -EINVAL; | ||
| 3219 | } | ||
| 3220 | |||
| 3221 | if (!cam->force_palette) { | ||
| 3222 | if (cam->decompression == 0) { | ||
| 3223 | if (w9968cf_need_decompression(mmap.format)) { | ||
| 3224 | DBG(4, "Decompression disabled: palette %s is not " | ||
| 3225 | "allowed. VIDIOCSPICT failed", | ||
| 3226 | symbolic(v4l1_plist, mmap.format)) | ||
| 3227 | return -EINVAL; | ||
| 3228 | } | ||
| 3229 | } else if (cam->decompression == 1) { | ||
| 3230 | if (!w9968cf_need_decompression(mmap.format)) { | ||
| 3231 | DBG(4, "Decompression forced: palette %s is not " | ||
| 3232 | "allowed. VIDIOCSPICT failed", | ||
| 3233 | symbolic(v4l1_plist, mmap.format)) | ||
| 3234 | return -EINVAL; | ||
| 3235 | } | ||
| 3236 | } | ||
| 3237 | } | ||
| 3238 | |||
| 3239 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, | ||
| 3240 | (u16*)&mmap.height))) { | ||
| 3241 | DBG(4, "Resolution not supported (%dx%d). " | ||
| 3242 | "VIDIOCMCAPTURE failed", | ||
| 3243 | mmap.width, mmap.height) | ||
| 3244 | return err; | ||
| 3245 | } | ||
| 3246 | |||
| 3247 | fr = &cam->frame[mmap.frame]; | ||
| 3248 | |||
| 3249 | if (mmap.width != cam->window.width || | ||
| 3250 | mmap.height != cam->window.height || | ||
| 3251 | mmap.format != cam->picture.palette) { | ||
| 3252 | |||
| 3253 | struct video_window win; | ||
| 3254 | struct video_picture pict; | ||
| 3255 | |||
| 3256 | if(*cam->requested_frame | ||
| 3257 | || cam->frame_current->queued) { | ||
| 3258 | DBG(6, "VIDIOCMCAPTURE. Change settings for " | ||
| 3259 | "frame #%u: %dx%d, format %s. Wait...", | ||
| 3260 | mmap.frame, mmap.width, mmap.height, | ||
| 3261 | symbolic(v4l1_plist, mmap.format)) | ||
| 3262 | err = wait_event_interruptible | ||
| 3263 | ( cam->wait_queue, | ||
| 3264 | cam->disconnected || | ||
| 3265 | (!*cam->requested_frame && | ||
| 3266 | !cam->frame_current->queued) ); | ||
| 3267 | if (err) | ||
| 3268 | return err; | ||
| 3269 | if (cam->disconnected) | ||
| 3270 | return -ENODEV; | ||
| 3271 | } | ||
| 3272 | |||
| 3273 | memcpy(&win, &cam->window, sizeof(win)); | ||
| 3274 | memcpy(&pict, &cam->picture, sizeof(pict)); | ||
| 3275 | win.width = mmap.width; | ||
| 3276 | win.height = mmap.height; | ||
| 3277 | pict.palette = mmap.format; | ||
| 3278 | |||
| 3279 | if (w9968cf_stop_transfer(cam)) | ||
| 3280 | goto ioctl_fail; | ||
| 3281 | |||
| 3282 | /* This before set_window */ | ||
| 3283 | if (w9968cf_set_picture(cam, pict)) | ||
| 3284 | goto ioctl_fail; | ||
| 3285 | |||
| 3286 | if (w9968cf_set_window(cam, win)) | ||
| 3287 | goto ioctl_fail; | ||
| 3288 | |||
| 3289 | if (w9968cf_start_transfer(cam)) | ||
| 3290 | goto ioctl_fail; | ||
| 3291 | |||
| 3292 | } else if (fr->queued) { | ||
| 3293 | |||
| 3294 | DBG(6, "Wait until frame #%u is free", mmap.frame) | ||
| 3295 | |||
| 3296 | err = wait_event_interruptible(cam->wait_queue, | ||
| 3297 | cam->disconnected || | ||
| 3298 | (!fr->queued)); | ||
| 3299 | if (err) | ||
| 3300 | return err; | ||
| 3301 | if (cam->disconnected) | ||
| 3302 | return -ENODEV; | ||
| 3303 | } | ||
| 3304 | |||
| 3305 | w9968cf_push_frame(cam, mmap.frame); | ||
| 3306 | DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame) | ||
| 3307 | return 0; | ||
| 3308 | } | ||
| 3309 | |||
| 3310 | case VIDIOCSYNC: /* wait until the capture of a frame is finished */ | ||
| 3311 | { | ||
| 3312 | unsigned int f_num; | ||
| 3313 | struct w9968cf_frame_t* fr; | ||
| 3314 | int err = 0; | ||
| 3315 | |||
| 3316 | if (copy_from_user(&f_num, arg, sizeof(f_num))) | ||
| 3317 | return -EFAULT; | ||
| 3318 | |||
| 3319 | if (f_num >= cam->nbuffers) { | ||
| 3320 | DBG(4, "Invalid frame number (%u). " | ||
| 3321 | "VIDIOCMCAPTURE failed", f_num) | ||
| 3322 | return -EINVAL; | ||
| 3323 | } | ||
| 3324 | |||
| 3325 | DBG(6, "VIDIOCSYNC called for frame #%u", f_num) | ||
| 3326 | |||
| 3327 | fr = &cam->frame[f_num]; | ||
| 3328 | |||
| 3329 | switch (fr->status) { | ||
| 3330 | case F_UNUSED: | ||
| 3331 | if (!fr->queued) { | ||
| 3332 | DBG(4, "VIDIOSYNC: Frame #%u not requested!", | ||
| 3333 | f_num) | ||
| 3334 | return -EFAULT; | ||
| 3335 | } | ||
| 3336 | case F_ERROR: | ||
| 3337 | case F_GRABBING: | ||
| 3338 | err = wait_event_interruptible(cam->wait_queue, | ||
| 3339 | (fr->status == F_READY) | ||
| 3340 | || cam->disconnected); | ||
| 3341 | if (err) | ||
| 3342 | return err; | ||
| 3343 | if (cam->disconnected) | ||
| 3344 | return -ENODEV; | ||
| 3345 | break; | ||
| 3346 | case F_READY: | ||
| 3347 | break; | ||
| 3348 | } | ||
| 3349 | |||
| 3350 | if (w9968cf_vpp) | ||
| 3351 | w9968cf_postprocess_frame(cam, fr); | ||
| 3352 | |||
| 3353 | fr->status = F_UNUSED; | ||
| 3354 | |||
| 3355 | DBG(5, "VIDIOCSYNC(%u) successfully called", f_num) | ||
| 3356 | return 0; | ||
| 3357 | } | ||
| 3358 | |||
| 3359 | case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/ | ||
| 3360 | { | ||
| 3361 | struct video_unit unit = { | ||
| 3362 | .video = cam->v4ldev->minor, | ||
| 3363 | .vbi = VIDEO_NO_UNIT, | ||
| 3364 | .radio = VIDEO_NO_UNIT, | ||
| 3365 | .audio = VIDEO_NO_UNIT, | ||
| 3366 | .teletext = VIDEO_NO_UNIT, | ||
| 3367 | }; | ||
| 3368 | |||
| 3369 | if (copy_to_user(arg, &unit, sizeof(unit))) | ||
| 3370 | return -EFAULT; | ||
| 3371 | |||
| 3372 | DBG(5, "VIDIOCGUNIT successfully called") | ||
| 3373 | return 0; | ||
| 3374 | } | ||
| 3375 | |||
| 3376 | case VIDIOCKEY: | ||
| 3377 | return 0; | ||
| 3378 | |||
| 3379 | case VIDIOCGFBUF: | ||
| 3380 | { | ||
| 3381 | if (clear_user(arg, sizeof(struct video_buffer))) | ||
| 3382 | return -EFAULT; | ||
| 3383 | |||
| 3384 | DBG(5, "VIDIOCGFBUF successfully called") | ||
| 3385 | return 0; | ||
| 3386 | } | ||
| 3387 | |||
| 3388 | case VIDIOCGTUNER: | ||
| 3389 | { | ||
| 3390 | struct video_tuner tuner; | ||
| 3391 | if (copy_from_user(&tuner, arg, sizeof(tuner))) | ||
| 3392 | return -EFAULT; | ||
| 3393 | |||
| 3394 | if (tuner.tuner != 0) | ||
| 3395 | return -EINVAL; | ||
| 3396 | |||
| 3397 | strcpy(tuner.name, "no_tuner"); | ||
| 3398 | tuner.rangelow = 0; | ||
| 3399 | tuner.rangehigh = 0; | ||
| 3400 | tuner.flags = VIDEO_TUNER_NORM; | ||
| 3401 | tuner.mode = VIDEO_MODE_AUTO; | ||
| 3402 | tuner.signal = 0xffff; | ||
| 3403 | |||
| 3404 | if (copy_to_user(arg, &tuner, sizeof(tuner))) | ||
| 3405 | return -EFAULT; | ||
| 3406 | |||
| 3407 | DBG(5, "VIDIOCGTUNER successfully called") | ||
| 3408 | return 0; | ||
| 3409 | } | ||
| 3410 | |||
| 3411 | case VIDIOCSTUNER: | ||
| 3412 | { | ||
| 3413 | struct video_tuner tuner; | ||
| 3414 | if (copy_from_user(&tuner, arg, sizeof(tuner))) | ||
| 3415 | return -EFAULT; | ||
| 3416 | |||
| 3417 | if (tuner.tuner != 0) | ||
| 3418 | return -EINVAL; | ||
| 3419 | |||
| 3420 | if (tuner.mode != VIDEO_MODE_AUTO) | ||
| 3421 | return -EINVAL; | ||
| 3422 | |||
| 3423 | DBG(5, "VIDIOCSTUNER successfully called") | ||
| 3424 | return 0; | ||
| 3425 | } | ||
| 3426 | |||
| 3427 | case VIDIOCSFBUF: | ||
| 3428 | case VIDIOCCAPTURE: | ||
| 3429 | case VIDIOCGFREQ: | ||
| 3430 | case VIDIOCSFREQ: | ||
| 3431 | case VIDIOCGAUDIO: | ||
| 3432 | case VIDIOCSAUDIO: | ||
| 3433 | case VIDIOCSPLAYMODE: | ||
| 3434 | case VIDIOCSWRITEMODE: | ||
| 3435 | case VIDIOCGPLAYINFO: | ||
| 3436 | case VIDIOCSMICROCODE: | ||
| 3437 | case VIDIOCGVBIFMT: | ||
| 3438 | case VIDIOCSVBIFMT: | ||
| 3439 | DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s " | ||
| 3440 | "(type 0x%01X, " | ||
| 3441 | "n. 0x%01X, " | ||
| 3442 | "dir. 0x%01X, " | ||
| 3443 | "size 0x%02X)", | ||
| 3444 | V4L1_IOCTL(cmd), | ||
| 3445 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) | ||
| 3446 | |||
| 3447 | return -EINVAL; | ||
| 3448 | |||
| 3449 | default: | ||
| 3450 | DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s " | ||
| 3451 | "type 0x%01X, " | ||
| 3452 | "n. 0x%01X, " | ||
| 3453 | "dir. 0x%01X, " | ||
| 3454 | "size 0x%02X", | ||
| 3455 | V4L1_IOCTL(cmd), | ||
| 3456 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) | ||
| 3457 | |||
| 3458 | return -ENOIOCTLCMD; | ||
| 3459 | |||
| 3460 | } /* end of switch */ | ||
| 3461 | |||
| 3462 | ioctl_fail: | ||
| 3463 | cam->misconfigured = 1; | ||
| 3464 | DBG(1, "VIDIOC%s failed because of hardware problems. " | ||
| 3465 | "To use the camera, close and open it again.", V4L1_IOCTL(cmd)) | ||
| 3466 | return -EFAULT; | ||
| 3467 | } | ||
| 3468 | |||
| 3469 | |||
| 3470 | static struct file_operations w9968cf_fops = { | ||
| 3471 | .owner = THIS_MODULE, | ||
| 3472 | .open = w9968cf_open, | ||
| 3473 | .release = w9968cf_release, | ||
| 3474 | .read = w9968cf_read, | ||
| 3475 | .ioctl = w9968cf_ioctl, | ||
| 3476 | .compat_ioctl = v4l_compat_ioctl32, | ||
| 3477 | .mmap = w9968cf_mmap, | ||
| 3478 | .llseek = no_llseek, | ||
| 3479 | }; | ||
| 3480 | |||
| 3481 | |||
| 3482 | |||
| 3483 | /**************************************************************************** | ||
| 3484 | * USB probe and V4L registration, disconnect and id_table[] definition * | ||
| 3485 | ****************************************************************************/ | ||
| 3486 | |||
| 3487 | static int | ||
| 3488 | w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
| 3489 | { | ||
| 3490 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 3491 | struct w9968cf_device* cam; | ||
| 3492 | int err = 0; | ||
| 3493 | enum w9968cf_model_id mod_id; | ||
| 3494 | struct list_head* ptr; | ||
| 3495 | u8 sc = 0; /* number of simultaneous cameras */ | ||
| 3496 | static unsigned short dev_nr = 0; /* we are handling device number n */ | ||
| 3497 | |||
| 3498 | if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor && | ||
| 3499 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct) | ||
| 3500 | mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */ | ||
| 3501 | else if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[1].idVendor && | ||
| 3502 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct) | ||
| 3503 | mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */ | ||
| 3504 | else | ||
| 3505 | return -ENODEV; | ||
| 3506 | |||
| 3507 | cam = (struct w9968cf_device*) | ||
| 3508 | kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL); | ||
| 3509 | if (!cam) | ||
| 3510 | return -ENOMEM; | ||
| 3511 | |||
| 3512 | mutex_init(&cam->dev_mutex); | ||
| 3513 | mutex_lock(&cam->dev_mutex); | ||
| 3514 | |||
| 3515 | cam->usbdev = udev; | ||
| 3516 | /* NOTE: a local copy is used to avoid possible race conditions */ | ||
| 3517 | memcpy(&cam->dev, &udev->dev, sizeof(struct device)); | ||
| 3518 | |||
| 3519 | DBG(2, "%s detected", symbolic(camlist, mod_id)) | ||
| 3520 | |||
| 3521 | if (simcams > W9968CF_MAX_DEVICES) | ||
| 3522 | simcams = W9968CF_SIMCAMS; | ||
| 3523 | |||
| 3524 | /* How many cameras are connected ? */ | ||
| 3525 | mutex_lock(&w9968cf_devlist_mutex); | ||
| 3526 | list_for_each(ptr, &w9968cf_dev_list) | ||
| 3527 | sc++; | ||
| 3528 | mutex_unlock(&w9968cf_devlist_mutex); | ||
| 3529 | |||
| 3530 | if (sc >= simcams) { | ||
| 3531 | DBG(2, "Device rejected: too many connected cameras " | ||
| 3532 | "(max. %u)", simcams) | ||
| 3533 | err = -EPERM; | ||
| 3534 | goto fail; | ||
| 3535 | } | ||
| 3536 | |||
| 3537 | |||
| 3538 | /* Allocate 2 bytes of memory for camera control USB transfers */ | ||
| 3539 | if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) { | ||
| 3540 | DBG(1,"Couldn't allocate memory for camera control transfers") | ||
| 3541 | err = -ENOMEM; | ||
| 3542 | goto fail; | ||
| 3543 | } | ||
| 3544 | |||
| 3545 | /* Allocate 8 bytes of memory for USB data transfers to the FSB */ | ||
| 3546 | if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) { | ||
| 3547 | DBG(1, "Couldn't allocate memory for data " | ||
| 3548 | "transfers to the FSB") | ||
| 3549 | err = -ENOMEM; | ||
| 3550 | goto fail; | ||
| 3551 | } | ||
| 3552 | |||
| 3553 | /* Register the V4L device */ | ||
| 3554 | cam->v4ldev = video_device_alloc(); | ||
| 3555 | if (!cam->v4ldev) { | ||
| 3556 | DBG(1, "Could not allocate memory for a V4L structure") | ||
| 3557 | err = -ENOMEM; | ||
| 3558 | goto fail; | ||
| 3559 | } | ||
| 3560 | |||
| 3561 | strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); | ||
| 3562 | cam->v4ldev->owner = THIS_MODULE; | ||
| 3563 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
| 3564 | cam->v4ldev->hardware = VID_HARDWARE_W9968CF; | ||
| 3565 | cam->v4ldev->fops = &w9968cf_fops; | ||
| 3566 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
| 3567 | cam->v4ldev->release = video_device_release; | ||
| 3568 | video_set_drvdata(cam->v4ldev, cam); | ||
| 3569 | cam->v4ldev->dev = &cam->dev; | ||
| 3570 | |||
| 3571 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
| 3572 | video_nr[dev_nr]); | ||
| 3573 | if (err) { | ||
| 3574 | DBG(1, "V4L device registration failed") | ||
| 3575 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
| 3576 | DBG(2, "Couldn't find a free /dev/videoX node") | ||
| 3577 | video_nr[dev_nr] = -1; | ||
| 3578 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
| 3579 | goto fail; | ||
| 3580 | } | ||
| 3581 | |||
| 3582 | DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor) | ||
| 3583 | |||
| 3584 | /* Set some basic constants */ | ||
| 3585 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); | ||
| 3586 | |||
| 3587 | /* Add a new entry into the list of V4L registered devices */ | ||
| 3588 | mutex_lock(&w9968cf_devlist_mutex); | ||
| 3589 | list_add(&cam->v4llist, &w9968cf_dev_list); | ||
| 3590 | mutex_unlock(&w9968cf_devlist_mutex); | ||
| 3591 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
| 3592 | |||
| 3593 | w9968cf_turn_on_led(cam); | ||
| 3594 | |||
| 3595 | w9968cf_i2c_init(cam); | ||
| 3596 | |||
| 3597 | usb_set_intfdata(intf, cam); | ||
| 3598 | mutex_unlock(&cam->dev_mutex); | ||
| 3599 | return 0; | ||
| 3600 | |||
| 3601 | fail: /* Free unused memory */ | ||
| 3602 | kfree(cam->control_buffer); | ||
| 3603 | kfree(cam->data_buffer); | ||
| 3604 | if (cam->v4ldev) | ||
| 3605 | video_device_release(cam->v4ldev); | ||
| 3606 | mutex_unlock(&cam->dev_mutex); | ||
| 3607 | kfree(cam); | ||
| 3608 | return err; | ||
| 3609 | } | ||
| 3610 | |||
| 3611 | |||
| 3612 | static void w9968cf_usb_disconnect(struct usb_interface* intf) | ||
| 3613 | { | ||
| 3614 | struct w9968cf_device* cam = | ||
| 3615 | (struct w9968cf_device*)usb_get_intfdata(intf); | ||
| 3616 | |||
| 3617 | down_write(&w9968cf_disconnect); | ||
| 3618 | |||
| 3619 | if (cam) { | ||
| 3620 | /* Prevent concurrent accesses to data */ | ||
| 3621 | mutex_lock(&cam->dev_mutex); | ||
| 3622 | |||
| 3623 | cam->disconnected = 1; | ||
| 3624 | |||
| 3625 | DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id)) | ||
| 3626 | |||
| 3627 | wake_up_interruptible_all(&cam->open); | ||
| 3628 | |||
| 3629 | if (cam->users) { | ||
| 3630 | DBG(2, "The device is open (/dev/video%d)! " | ||
| 3631 | "Process name: %s. Deregistration and memory " | ||
| 3632 | "deallocation are deferred on close.", | ||
| 3633 | cam->v4ldev->minor, cam->command) | ||
| 3634 | cam->misconfigured = 1; | ||
| 3635 | w9968cf_stop_transfer(cam); | ||
| 3636 | wake_up_interruptible(&cam->wait_queue); | ||
| 3637 | } else | ||
| 3638 | w9968cf_release_resources(cam); | ||
| 3639 | |||
| 3640 | mutex_unlock(&cam->dev_mutex); | ||
| 3641 | |||
| 3642 | if (!cam->users) | ||
| 3643 | kfree(cam); | ||
| 3644 | } | ||
| 3645 | |||
| 3646 | up_write(&w9968cf_disconnect); | ||
| 3647 | } | ||
| 3648 | |||
| 3649 | |||
| 3650 | static struct usb_driver w9968cf_usb_driver = { | ||
| 3651 | .name = "w9968cf", | ||
| 3652 | .id_table = winbond_id_table, | ||
| 3653 | .probe = w9968cf_usb_probe, | ||
| 3654 | .disconnect = w9968cf_usb_disconnect, | ||
| 3655 | }; | ||
| 3656 | |||
| 3657 | |||
| 3658 | |||
| 3659 | /**************************************************************************** | ||
| 3660 | * Module init, exit and intermodule communication * | ||
| 3661 | ****************************************************************************/ | ||
| 3662 | |||
| 3663 | static int __init w9968cf_module_init(void) | ||
| 3664 | { | ||
| 3665 | int err; | ||
| 3666 | |||
| 3667 | KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION) | ||
| 3668 | KDBG(3, W9968CF_MODULE_AUTHOR) | ||
| 3669 | |||
| 3670 | if (ovmod_load) | ||
| 3671 | request_module("ovcamchip"); | ||
| 3672 | |||
| 3673 | if ((err = usb_register(&w9968cf_usb_driver))) | ||
| 3674 | return err; | ||
| 3675 | |||
| 3676 | return 0; | ||
| 3677 | } | ||
| 3678 | |||
| 3679 | |||
| 3680 | static void __exit w9968cf_module_exit(void) | ||
| 3681 | { | ||
| 3682 | /* w9968cf_usb_disconnect() will be called */ | ||
| 3683 | usb_deregister(&w9968cf_usb_driver); | ||
| 3684 | |||
| 3685 | KDBG(2, W9968CF_MODULE_NAME" deregistered") | ||
| 3686 | } | ||
| 3687 | |||
| 3688 | |||
| 3689 | module_init(w9968cf_module_init); | ||
| 3690 | module_exit(w9968cf_module_exit); | ||
| 3691 | |||
diff --git a/drivers/usb/media/w9968cf.h b/drivers/usb/media/w9968cf.h deleted file mode 100644 index a87be719a281..000000000000 --- a/drivers/usb/media/w9968cf.h +++ /dev/null | |||
| @@ -1,330 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2002-2004 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 _W9968CF_H_ | ||
| 22 | #define _W9968CF_H_ | ||
| 23 | |||
| 24 | #include <linux/videodev.h> | ||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <linux/i2c.h> | ||
| 27 | #include <linux/device.h> | ||
| 28 | #include <linux/spinlock.h> | ||
| 29 | #include <linux/list.h> | ||
| 30 | #include <linux/wait.h> | ||
| 31 | #include <linux/config.h> | ||
| 32 | #include <linux/param.h> | ||
| 33 | #include <linux/types.h> | ||
| 34 | #include <linux/rwsem.h> | ||
| 35 | #include <linux/mutex.h> | ||
| 36 | |||
| 37 | #include <media/ovcamchip.h> | ||
| 38 | |||
| 39 | #include "w9968cf_vpp.h" | ||
| 40 | |||
| 41 | |||
| 42 | /**************************************************************************** | ||
| 43 | * Default values * | ||
| 44 | ****************************************************************************/ | ||
| 45 | |||
| 46 | #define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */ | ||
| 47 | #define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */ | ||
| 48 | |||
| 49 | /* Comment/uncomment the following line to enable/disable debugging messages */ | ||
| 50 | #define W9968CF_DEBUG | ||
| 51 | |||
| 52 | /* These have effect only if W9968CF_DEBUG is defined */ | ||
| 53 | #define W9968CF_DEBUG_LEVEL 2 /* from 0 to 6. 0 for no debug informations */ | ||
| 54 | #define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */ | ||
| 55 | |||
| 56 | #define W9968CF_MAX_DEVICES 32 | ||
| 57 | #define W9968CF_SIMCAMS W9968CF_MAX_DEVICES /* simultaneous cameras */ | ||
| 58 | |||
| 59 | #define W9968CF_MAX_BUFFERS 32 | ||
| 60 | #define W9968CF_BUFFERS 2 /* n. of frame buffers from 2 to MAX_BUFFERS */ | ||
| 61 | |||
| 62 | /* Maximum data payload sizes in bytes for alternate settings */ | ||
| 63 | static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575, | ||
| 64 | 511, 447, 383, 319, 255, 191, 127, 63}; | ||
| 65 | #define W9968CF_PACKET_SIZE 1023 /* according to wMaxPacketSizes[] */ | ||
| 66 | #define W9968CF_MIN_PACKET_SIZE 63 /* minimum value */ | ||
| 67 | #define W9968CF_ISO_PACKETS 5 /* n.of packets for isochronous transfers */ | ||
| 68 | #define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */ | ||
| 69 | #define W9968CF_URBS 2 /* n. of scheduled URBs for ISO transfer */ | ||
| 70 | |||
| 71 | #define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ | ||
| 72 | #define W9968CF_I2C_RW_RETRIES 15 /* number of max I2C r/w retries */ | ||
| 73 | |||
| 74 | /* Available video formats */ | ||
| 75 | struct w9968cf_format { | ||
| 76 | const u16 palette; | ||
| 77 | const u16 depth; | ||
| 78 | const u8 compression; | ||
| 79 | }; | ||
| 80 | |||
| 81 | static const struct w9968cf_format w9968cf_formatlist[] = { | ||
| 82 | { VIDEO_PALETTE_UYVY, 16, 0 }, /* original video */ | ||
| 83 | { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */ | ||
| 84 | { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */ | ||
| 85 | { VIDEO_PALETTE_YUV420, 12, 1 }, /* same as YUV420P */ | ||
| 86 | { VIDEO_PALETTE_YUYV, 16, 0 }, /* software conversion */ | ||
| 87 | { VIDEO_PALETTE_YUV422, 16, 0 }, /* software conversion */ | ||
| 88 | { VIDEO_PALETTE_GREY, 8, 0 }, /* software conversion */ | ||
| 89 | { VIDEO_PALETTE_RGB555, 16, 0 }, /* software conversion */ | ||
| 90 | { VIDEO_PALETTE_RGB565, 16, 0 }, /* software conversion */ | ||
| 91 | { VIDEO_PALETTE_RGB24, 24, 0 }, /* software conversion */ | ||
| 92 | { VIDEO_PALETTE_RGB32, 32, 0 }, /* software conversion */ | ||
| 93 | { 0, 0, 0 } /* 0 is a terminating entry */ | ||
| 94 | }; | ||
| 95 | |||
| 96 | #define W9968CF_DECOMPRESSION 2 /* decomp:0=disable,1=force,2=any formats */ | ||
| 97 | #define W9968CF_PALETTE_DECOMP_OFF VIDEO_PALETTE_UYVY /* when decomp=0 */ | ||
| 98 | #define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */ | ||
| 99 | #define W9968CF_PALETTE_DECOMP_ON VIDEO_PALETTE_UYVY /* when decomp=2 */ | ||
| 100 | |||
| 101 | #define W9968CF_FORCE_RGB 0 /* read RGB instead of BGR, yes=1/no=0 */ | ||
| 102 | |||
| 103 | #define W9968CF_MAX_WIDTH 800 /* Has effect if up-scaling is on */ | ||
| 104 | #define W9968CF_MAX_HEIGHT 600 /* Has effect if up-scaling is on */ | ||
| 105 | #define W9968CF_WIDTH 320 /* from 128 to 352, multiple of 16 */ | ||
| 106 | #define W9968CF_HEIGHT 240 /* from 96 to 288, multiple of 16 */ | ||
| 107 | |||
| 108 | #define W9968CF_CLAMPING 0 /* 0 disable, 1 enable video data clamping */ | ||
| 109 | #define W9968CF_FILTER_TYPE 0 /* 0 disable 1 (1-2-1), 2 (2-3-6-3-2) */ | ||
| 110 | #define W9968CF_DOUBLE_BUFFER 1 /* 0 disable, 1 enable double buffer */ | ||
| 111 | #define W9968CF_LARGEVIEW 1 /* 0 disable, 1 enable */ | ||
| 112 | #define W9968CF_UPSCALING 0 /* 0 disable, 1 enable */ | ||
| 113 | |||
| 114 | #define W9968CF_MONOCHROME 0 /* 0 not monochrome, 1 monochrome sensor */ | ||
| 115 | #define W9968CF_BRIGHTNESS 31000 /* from 0 to 65535 */ | ||
| 116 | #define W9968CF_HUE 32768 /* from 0 to 65535 */ | ||
| 117 | #define W9968CF_COLOUR 32768 /* from 0 to 65535 */ | ||
| 118 | #define W9968CF_CONTRAST 50000 /* from 0 to 65535 */ | ||
| 119 | #define W9968CF_WHITENESS 32768 /* from 0 to 65535 */ | ||
| 120 | |||
| 121 | #define W9968CF_AUTOBRIGHT 0 /* 0 disable, 1 enable automatic brightness */ | ||
| 122 | #define W9968CF_AUTOEXP 1 /* 0 disable, 1 enable automatic exposure */ | ||
| 123 | #define W9968CF_LIGHTFREQ 50 /* light frequency. 50Hz (Europe) or 60Hz */ | ||
| 124 | #define W9968CF_BANDINGFILTER 0 /* 0 disable, 1 enable banding filter */ | ||
| 125 | #define W9968CF_BACKLIGHT 0 /* 0 or 1, 1=object is lit from behind */ | ||
| 126 | #define W9968CF_MIRROR 0 /* 0 or 1 [don't] reverse image horizontally*/ | ||
| 127 | |||
| 128 | #define W9968CF_CLOCKDIV -1 /* -1 = automatic clock divisor */ | ||
| 129 | #define W9968CF_DEF_CLOCKDIVISOR 0 /* default sensor clock divisor value */ | ||
| 130 | |||
| 131 | |||
| 132 | /**************************************************************************** | ||
| 133 | * Globals * | ||
| 134 | ****************************************************************************/ | ||
| 135 | |||
| 136 | #define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \ | ||
| 137 | "Dual Mode Camera Chip" | ||
| 138 | #define W9968CF_MODULE_VERSION "1:1.33-basic" | ||
| 139 | #define W9968CF_MODULE_AUTHOR "(C) 2002-2004 Luca Risolia" | ||
| 140 | #define W9968CF_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
| 141 | #define W9968CF_MODULE_LICENSE "GPL" | ||
| 142 | |||
| 143 | static const struct usb_device_id winbond_id_table[] = { | ||
| 144 | { | ||
| 145 | /* Creative Labs Video Blaster WebCam Go Plus */ | ||
| 146 | USB_DEVICE(0x041e, 0x4003), | ||
| 147 | .driver_info = (unsigned long)"w9968cf", | ||
| 148 | }, | ||
| 149 | { | ||
| 150 | /* Generic W996[87]CF JPEG USB Dual Mode Camera */ | ||
| 151 | USB_DEVICE(0x1046, 0x9967), | ||
| 152 | .driver_info = (unsigned long)"w9968cf", | ||
| 153 | }, | ||
| 154 | { } /* terminating entry */ | ||
| 155 | }; | ||
| 156 | |||
| 157 | /* W996[87]CF camera models, internal ids: */ | ||
| 158 | enum w9968cf_model_id { | ||
| 159 | W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */ | ||
| 160 | W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/ | ||
| 161 | W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */ | ||
| 162 | W9986CF_MOD_AAU = 31, /* AVerMedia AVerTV USB */ | ||
| 163 | W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */ | ||
| 164 | W9968CF_MOD_LL = 37, /* Lebon LDC-035A */ | ||
| 165 | W9968CF_MOD_EEEMC = 40, /* Ezonics EZ-802 EZMega Cam */ | ||
| 166 | W9968CF_MOD_OOE = 42, /* OmniVision OV8610-EDE */ | ||
| 167 | W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */ | ||
| 168 | W9968CF_MOD_PDPII = 46, /* Pretec Digi Pen-II */ | ||
| 169 | W9968CF_MOD_PDP480 = 49, /* Pretec DigiPen-480 */ | ||
| 170 | }; | ||
| 171 | |||
| 172 | enum w9968cf_frame_status { | ||
| 173 | F_READY, /* finished grabbing & ready to be read/synced */ | ||
| 174 | F_GRABBING, /* in the process of being grabbed into */ | ||
| 175 | F_ERROR, /* something bad happened while processing */ | ||
| 176 | F_UNUSED /* unused (no VIDIOCMCAPTURE) */ | ||
| 177 | }; | ||
| 178 | |||
| 179 | struct w9968cf_frame_t { | ||
| 180 | void* buffer; | ||
| 181 | unsigned long size; | ||
| 182 | u32 length; | ||
| 183 | int number; | ||
| 184 | enum w9968cf_frame_status status; | ||
| 185 | struct w9968cf_frame_t* next; | ||
| 186 | u8 queued; | ||
| 187 | }; | ||
| 188 | |||
| 189 | enum w9968cf_vpp_flag { | ||
| 190 | VPP_NONE = 0x00, | ||
| 191 | VPP_UPSCALE = 0x01, | ||
| 192 | VPP_SWAP_YUV_BYTES = 0x02, | ||
| 193 | VPP_DECOMPRESSION = 0x04, | ||
| 194 | VPP_UYVY_TO_RGBX = 0x08, | ||
| 195 | }; | ||
| 196 | |||
| 197 | /* Main device driver structure */ | ||
| 198 | struct w9968cf_device { | ||
| 199 | struct device dev; /* device structure */ | ||
| 200 | |||
| 201 | enum w9968cf_model_id id; /* private device identifier */ | ||
| 202 | |||
| 203 | struct video_device* v4ldev; /* -> V4L structure */ | ||
| 204 | struct list_head v4llist; /* entry of the list of V4L cameras */ | ||
| 205 | |||
| 206 | struct usb_device* usbdev; /* -> main USB structure */ | ||
| 207 | struct urb* urb[W9968CF_URBS]; /* -> USB request block structs */ | ||
| 208 | void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */ | ||
| 209 | u16* control_buffer; /* -> buffer for control req.*/ | ||
| 210 | u16* data_buffer; /* -> data to send to the FSB */ | ||
| 211 | |||
| 212 | struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS]; | ||
| 213 | struct w9968cf_frame_t frame_tmp; /* temporary frame */ | ||
| 214 | struct w9968cf_frame_t frame_vpp; /* helper frame.*/ | ||
| 215 | struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */ | ||
| 216 | struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS]; | ||
| 217 | |||
| 218 | u8 max_buffers, /* number of requested buffers */ | ||
| 219 | force_palette, /* yes=1/no=0 */ | ||
| 220 | force_rgb, /* read RGB instead of BGR, yes=1, no=0 */ | ||
| 221 | double_buffer, /* hardware double buffering yes=1/no=0 */ | ||
| 222 | clamping, /* video data clamping yes=1/no=0 */ | ||
| 223 | filter_type, /* 0=disabled, 1=3 tap, 2=5 tap filter */ | ||
| 224 | capture, /* 0=disabled, 1=enabled */ | ||
| 225 | largeview, /* 0=disabled, 1=enabled */ | ||
| 226 | decompression, /* 0=disabled, 1=forced, 2=allowed */ | ||
| 227 | upscaling; /* software image scaling, 0=enabled, 1=disabled */ | ||
| 228 | |||
| 229 | struct video_picture picture; /* current picture settings */ | ||
| 230 | struct video_window window; /* current window settings */ | ||
| 231 | |||
| 232 | u16 hw_depth, /* depth (used by the chip) */ | ||
| 233 | hw_palette, /* palette (used by the chip) */ | ||
| 234 | hw_width, /* width (used by the chip) */ | ||
| 235 | hw_height, /* height (used by the chip) */ | ||
| 236 | hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ | ||
| 237 | vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ | ||
| 238 | start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/ | ||
| 239 | start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/ | ||
| 240 | |||
| 241 | enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */ | ||
| 242 | |||
| 243 | u8 nbuffers, /* number of allocated frame buffers */ | ||
| 244 | altsetting, /* camera alternate setting */ | ||
| 245 | disconnected, /* flag: yes=1, no=0 */ | ||
| 246 | misconfigured, /* flag: yes=1, no=0 */ | ||
| 247 | users, /* flag: number of users holding the device */ | ||
| 248 | streaming; /* flag: yes=1, no=0 */ | ||
| 249 | |||
| 250 | u8 sensor_initialized; /* flag: yes=1, no=0 */ | ||
| 251 | |||
| 252 | /* Determined by the image sensor type: */ | ||
| 253 | int sensor, /* type of image sensor chip (CC_*) */ | ||
| 254 | monochrome; /* image sensor is (probably) monochrome */ | ||
| 255 | u16 maxwidth, /* maximum width supported by the image sensor */ | ||
| 256 | maxheight, /* maximum height supported by the image sensor */ | ||
| 257 | minwidth, /* minimum width supported by the image sensor */ | ||
| 258 | minheight; /* minimum height supported by the image sensor */ | ||
| 259 | u8 auto_brt, /* auto brightness enabled flag */ | ||
| 260 | auto_exp, /* auto exposure enabled flag */ | ||
| 261 | backlight, /* backlight exposure algorithm flag */ | ||
| 262 | mirror, /* image is reversed horizontally */ | ||
| 263 | lightfreq, /* power (lighting) frequency */ | ||
| 264 | bandfilt; /* banding filter enabled flag */ | ||
| 265 | s8 clockdiv; /* clock divisor */ | ||
| 266 | |||
| 267 | /* I2C interface to kernel */ | ||
| 268 | struct i2c_adapter i2c_adapter; | ||
| 269 | struct i2c_client* sensor_client; | ||
| 270 | |||
| 271 | /* Locks */ | ||
| 272 | struct mutex dev_mutex, /* for probe, disconnect,open and close */ | ||
| 273 | fileop_mutex; /* for read and ioctl */ | ||
| 274 | spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */ | ||
| 275 | flist_lock; /* for requested frame list accesses */ | ||
| 276 | wait_queue_head_t open, wait_queue; | ||
| 277 | |||
| 278 | char command[16]; /* name of the program holding the device */ | ||
| 279 | }; | ||
| 280 | |||
| 281 | |||
| 282 | /**************************************************************************** | ||
| 283 | * Macros for debugging * | ||
| 284 | ****************************************************************************/ | ||
| 285 | |||
| 286 | #undef DBG | ||
| 287 | #undef KDBG | ||
| 288 | #ifdef W9968CF_DEBUG | ||
| 289 | /* For device specific debugging messages */ | ||
| 290 | # define DBG(level, fmt, args...) \ | ||
| 291 | { \ | ||
| 292 | if ( ((specific_debug) && (debug == (level))) || \ | ||
| 293 | ((!specific_debug) && (debug >= (level))) ) { \ | ||
| 294 | if ((level) == 1) \ | ||
| 295 | dev_err(&cam->dev, fmt "\n", ## args); \ | ||
| 296 | else if ((level) == 2 || (level) == 3) \ | ||
| 297 | dev_info(&cam->dev, fmt "\n", ## args); \ | ||
| 298 | else if ((level) == 4) \ | ||
| 299 | dev_warn(&cam->dev, fmt "\n", ## args); \ | ||
| 300 | else if ((level) >= 5) \ | ||
| 301 | dev_info(&cam->dev, "[%s:%d] " fmt "\n", \ | ||
| 302 | __FUNCTION__, __LINE__ , ## args); \ | ||
| 303 | } \ | ||
| 304 | } | ||
| 305 | /* For generic kernel (not device specific) messages */ | ||
| 306 | # define KDBG(level, fmt, args...) \ | ||
| 307 | { \ | ||
| 308 | if ( ((specific_debug) && (debug == (level))) || \ | ||
| 309 | ((!specific_debug) && (debug >= (level))) ) { \ | ||
| 310 | if ((level) >= 1 && (level) <= 4) \ | ||
| 311 | pr_info("w9968cf: " fmt "\n", ## args); \ | ||
| 312 | else if ((level) >= 5) \ | ||
| 313 | pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
| 314 | __LINE__ , ## args); \ | ||
| 315 | } \ | ||
| 316 | } | ||
| 317 | #else | ||
| 318 | /* Not debugging: nothing */ | ||
| 319 | # define DBG(level, fmt, args...) do {;} while(0); | ||
| 320 | # define KDBG(level, fmt, args...) do {;} while(0); | ||
| 321 | #endif | ||
| 322 | |||
| 323 | #undef PDBG | ||
| 324 | #define PDBG(fmt, args...) \ | ||
| 325 | dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args); | ||
| 326 | |||
| 327 | #undef PDBGG | ||
| 328 | #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */ | ||
| 329 | |||
| 330 | #endif /* _W9968CF_H_ */ | ||
diff --git a/drivers/usb/media/w9968cf_decoder.h b/drivers/usb/media/w9968cf_decoder.h deleted file mode 100644 index 31faccbe8f03..000000000000 --- a/drivers/usb/media/w9968cf_decoder.h +++ /dev/null | |||
| @@ -1,86 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Video decoder for the W996[87]CF driver for Linux. * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2003 2004 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 _W9968CF_DECODER_H_ | ||
| 22 | #define _W9968CF_DECODER_H_ | ||
| 23 | |||
| 24 | /* Comment/uncomment this for high/low quality of compressed video */ | ||
| 25 | #define W9968CF_DEC_FAST_LOWQUALITY_VIDEO | ||
| 26 | |||
| 27 | #ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO | ||
| 28 | static const unsigned char Y_QUANTABLE[64] = { | ||
| 29 | 16, 11, 10, 16, 24, 40, 51, 61, | ||
| 30 | 12, 12, 14, 19, 26, 58, 60, 55, | ||
| 31 | 14, 13, 16, 24, 40, 57, 69, 56, | ||
| 32 | 14, 17, 22, 29, 51, 87, 80, 62, | ||
| 33 | 18, 22, 37, 56, 68, 109, 103, 77, | ||
| 34 | 24, 35, 55, 64, 81, 104, 113, 92, | ||
| 35 | 49, 64, 78, 87, 103, 121, 120, 101, | ||
| 36 | 72, 92, 95, 98, 112, 100, 103, 99 | ||
| 37 | }; | ||
| 38 | |||
| 39 | static const unsigned char UV_QUANTABLE[64] = { | ||
| 40 | 17, 18, 24, 47, 99, 99, 99, 99, | ||
| 41 | 18, 21, 26, 66, 99, 99, 99, 99, | ||
| 42 | 24, 26, 56, 99, 99, 99, 99, 99, | ||
| 43 | 47, 66, 99, 99, 99, 99, 99, 99, | ||
| 44 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
| 45 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
| 46 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
| 47 | 99, 99, 99, 99, 99, 99, 99, 99 | ||
| 48 | }; | ||
| 49 | #else | ||
| 50 | static const unsigned char Y_QUANTABLE[64] = { | ||
| 51 | 8, 5, 5, 8, 12, 20, 25, 30, | ||
| 52 | 6, 6, 7, 9, 13, 29, 30, 27, | ||
| 53 | 7, 6, 8, 12, 20, 28, 34, 28, | ||
| 54 | 7, 8, 11, 14, 25, 43, 40, 31, | ||
| 55 | 9, 11, 18, 28, 34, 54, 51, 38, | ||
| 56 | 12, 17, 27, 32, 40, 52, 56, 46, | ||
| 57 | 24, 32, 39, 43, 51, 60, 60, 50, | ||
| 58 | 36, 46, 47, 49, 56, 50, 51, 49 | ||
| 59 | }; | ||
| 60 | |||
| 61 | static const unsigned char UV_QUANTABLE[64] = { | ||
| 62 | 8, 9, 12, 23, 49, 49, 49, 49, | ||
| 63 | 9, 10, 13, 33, 49, 49, 49, 49, | ||
| 64 | 12, 13, 28, 49, 49, 49, 49, 49, | ||
| 65 | 23, 33, 49, 49, 49, 49, 49, 49, | ||
| 66 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
| 67 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
| 68 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
| 69 | 49, 49, 49, 49, 49, 49, 49, 49 | ||
| 70 | }; | ||
| 71 | #endif | ||
| 72 | |||
| 73 | #define W9968CF_DEC_ERR_CORRUPTED_DATA -1 | ||
| 74 | #define W9968CF_DEC_ERR_BUF_OVERFLOW -2 | ||
| 75 | #define W9968CF_DEC_ERR_NO_SOI -3 | ||
| 76 | #define W9968CF_DEC_ERR_NO_SOF0 -4 | ||
| 77 | #define W9968CF_DEC_ERR_NO_SOS -5 | ||
| 78 | #define W9968CF_DEC_ERR_NO_EOI -6 | ||
| 79 | |||
| 80 | extern void w9968cf_init_decoder(void); | ||
| 81 | extern int w9968cf_check_headers(const unsigned char* Pin, | ||
| 82 | const unsigned long BUF_SIZE); | ||
| 83 | extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE, | ||
| 84 | const unsigned W, const unsigned H, char* Pout); | ||
| 85 | |||
| 86 | #endif /* _W9968CF_DECODER_H_ */ | ||
diff --git a/drivers/usb/media/w9968cf_vpp.h b/drivers/usb/media/w9968cf_vpp.h deleted file mode 100644 index f3b91b782671..000000000000 --- a/drivers/usb/media/w9968cf_vpp.h +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Interface for video post-processing functions for the W996[87]CF driver * | ||
| 3 | * for Linux. * | ||
| 4 | * * | ||
| 5 | * Copyright (C) 2002-2004 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 | #ifndef _W9968CF_VPP_H_ | ||
| 23 | #define _W9968CF_VPP_H_ | ||
| 24 | |||
| 25 | #include <linux/module.h> | ||
| 26 | #include <asm/types.h> | ||
| 27 | |||
| 28 | struct w9968cf_vpp_t { | ||
| 29 | struct module* owner; | ||
| 30 | int (*check_headers)(const unsigned char*, const unsigned long); | ||
| 31 | int (*decode)(const char*, const unsigned long, const unsigned, | ||
| 32 | const unsigned, char*); | ||
| 33 | void (*swap_yuvbytes)(void*, unsigned long); | ||
| 34 | void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8); | ||
| 35 | void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16); | ||
| 36 | |||
| 37 | u8 busy; /* read-only flag: module is/is not in use */ | ||
| 38 | }; | ||
| 39 | |||
| 40 | #endif /* _W9968CF_VPP_H_ */ | ||
diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h deleted file mode 100644 index 8e0655140e60..000000000000 --- a/drivers/usb/media/zc0301.h +++ /dev/null | |||
| @@ -1,192 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * V4L2 driver for ZC0301 Image Processor and Control Chip * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2006 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 _ZC0301_H_ | ||
| 22 | #define _ZC0301_H_ | ||
| 23 | |||
| 24 | #include <linux/version.h> | ||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <linux/videodev2.h> | ||
| 27 | #include <media/v4l2-common.h> | ||
| 28 | #include <linux/device.h> | ||
| 29 | #include <linux/list.h> | ||
| 30 | #include <linux/spinlock.h> | ||
| 31 | #include <linux/time.h> | ||
| 32 | #include <linux/wait.h> | ||
| 33 | #include <linux/types.h> | ||
| 34 | #include <linux/param.h> | ||
| 35 | #include <linux/mutex.h> | ||
| 36 | #include <linux/rwsem.h> | ||
| 37 | #include <linux/stddef.h> | ||
| 38 | #include <linux/string.h> | ||
| 39 | |||
| 40 | #include "zc0301_sensor.h" | ||
| 41 | |||
| 42 | /*****************************************************************************/ | ||
| 43 | |||
| 44 | #define ZC0301_DEBUG | ||
| 45 | #define ZC0301_DEBUG_LEVEL 2 | ||
| 46 | #define ZC0301_MAX_DEVICES 64 | ||
| 47 | #define ZC0301_FORCE_MUNMAP 0 | ||
| 48 | #define ZC0301_MAX_FRAMES 32 | ||
| 49 | #define ZC0301_COMPRESSION_QUALITY 0 | ||
| 50 | #define ZC0301_URBS 2 | ||
| 51 | #define ZC0301_ISO_PACKETS 7 | ||
| 52 | #define ZC0301_ALTERNATE_SETTING 7 | ||
| 53 | #define ZC0301_URB_TIMEOUT msecs_to_jiffies(2 * ZC0301_ISO_PACKETS) | ||
| 54 | #define ZC0301_CTRL_TIMEOUT 100 | ||
| 55 | #define ZC0301_FRAME_TIMEOUT 2 | ||
| 56 | |||
| 57 | /*****************************************************************************/ | ||
| 58 | |||
| 59 | ZC0301_ID_TABLE | ||
| 60 | ZC0301_SENSOR_TABLE | ||
| 61 | |||
| 62 | enum zc0301_frame_state { | ||
| 63 | F_UNUSED, | ||
| 64 | F_QUEUED, | ||
| 65 | F_GRABBING, | ||
| 66 | F_DONE, | ||
| 67 | F_ERROR, | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct zc0301_frame_t { | ||
| 71 | void* bufmem; | ||
| 72 | struct v4l2_buffer buf; | ||
| 73 | enum zc0301_frame_state state; | ||
| 74 | struct list_head frame; | ||
| 75 | unsigned long vma_use_count; | ||
| 76 | }; | ||
| 77 | |||
| 78 | enum zc0301_dev_state { | ||
| 79 | DEV_INITIALIZED = 0x01, | ||
| 80 | DEV_DISCONNECTED = 0x02, | ||
| 81 | DEV_MISCONFIGURED = 0x04, | ||
| 82 | }; | ||
| 83 | |||
| 84 | enum zc0301_io_method { | ||
| 85 | IO_NONE, | ||
| 86 | IO_READ, | ||
| 87 | IO_MMAP, | ||
| 88 | }; | ||
| 89 | |||
| 90 | enum zc0301_stream_state { | ||
| 91 | STREAM_OFF, | ||
| 92 | STREAM_INTERRUPT, | ||
| 93 | STREAM_ON, | ||
| 94 | }; | ||
| 95 | |||
| 96 | struct zc0301_module_param { | ||
| 97 | u8 force_munmap; | ||
| 98 | u16 frame_timeout; | ||
| 99 | }; | ||
| 100 | |||
| 101 | static DECLARE_RWSEM(zc0301_disconnect); | ||
| 102 | |||
| 103 | struct zc0301_device { | ||
| 104 | struct video_device* v4ldev; | ||
| 105 | |||
| 106 | struct zc0301_sensor sensor; | ||
| 107 | |||
| 108 | struct usb_device* usbdev; | ||
| 109 | struct urb* urb[ZC0301_URBS]; | ||
| 110 | void* transfer_buffer[ZC0301_URBS]; | ||
| 111 | u8* control_buffer; | ||
| 112 | |||
| 113 | struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES]; | ||
| 114 | struct list_head inqueue, outqueue; | ||
| 115 | u32 frame_count, nbuffers, nreadbuffers; | ||
| 116 | |||
| 117 | enum zc0301_io_method io; | ||
| 118 | enum zc0301_stream_state stream; | ||
| 119 | |||
| 120 | struct v4l2_jpegcompression compression; | ||
| 121 | |||
| 122 | struct zc0301_module_param module_param; | ||
| 123 | |||
| 124 | enum zc0301_dev_state state; | ||
| 125 | u8 users; | ||
| 126 | |||
| 127 | struct mutex dev_mutex, fileop_mutex; | ||
| 128 | spinlock_t queue_lock; | ||
| 129 | wait_queue_head_t open, wait_frame, wait_stream; | ||
| 130 | }; | ||
| 131 | |||
| 132 | /*****************************************************************************/ | ||
| 133 | |||
| 134 | struct zc0301_device* | ||
| 135 | zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id) | ||
| 136 | { | ||
| 137 | return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; | ||
| 138 | } | ||
| 139 | |||
| 140 | void | ||
| 141 | zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor) | ||
| 142 | { | ||
| 143 | memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor)); | ||
| 144 | } | ||
| 145 | |||
| 146 | /*****************************************************************************/ | ||
| 147 | |||
| 148 | #undef DBG | ||
| 149 | #undef KDBG | ||
| 150 | #ifdef ZC0301_DEBUG | ||
| 151 | # define DBG(level, fmt, args...) \ | ||
| 152 | do { \ | ||
| 153 | if (debug >= (level)) { \ | ||
| 154 | if ((level) == 1) \ | ||
| 155 | dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
| 156 | else if ((level) == 2) \ | ||
| 157 | dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
| 158 | else if ((level) >= 3) \ | ||
| 159 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
| 160 | __FUNCTION__, __LINE__ , ## args); \ | ||
| 161 | } \ | ||
| 162 | } while (0) | ||
| 163 | # define KDBG(level, fmt, args...) \ | ||
| 164 | do { \ | ||
| 165 | if (debug >= (level)) { \ | ||
| 166 | if ((level) == 1 || (level) == 2) \ | ||
| 167 | pr_info("zc0301: " fmt "\n", ## args); \ | ||
| 168 | else if ((level) == 3) \ | ||
| 169 | pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
| 170 | __LINE__ , ## args); \ | ||
| 171 | } \ | ||
| 172 | } while (0) | ||
| 173 | # define V4LDBG(level, name, cmd) \ | ||
| 174 | do { \ | ||
| 175 | if (debug >= (level)) \ | ||
| 176 | v4l_print_ioctl(name, cmd); \ | ||
| 177 | } while (0) | ||
| 178 | #else | ||
| 179 | # define DBG(level, fmt, args...) do {;} while(0) | ||
| 180 | # define KDBG(level, fmt, args...) do {;} while(0) | ||
| 181 | # define V4LDBG(level, name, cmd) do {;} while(0) | ||
| 182 | #endif | ||
| 183 | |||
| 184 | #undef PDBG | ||
| 185 | #define PDBG(fmt, args...) \ | ||
| 186 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
| 187 | __FUNCTION__, __LINE__ , ## args) | ||
| 188 | |||
| 189 | #undef PDBGG | ||
| 190 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ | ||
| 191 | |||
| 192 | #endif /* _ZC0301_H_ */ | ||
diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c deleted file mode 100644 index 4036c6268bff..000000000000 --- a/drivers/usb/media/zc0301_core.c +++ /dev/null | |||
| @@ -1,2055 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Video4Linux2 driver for ZC0301 Image Processor and Control Chip * | ||
| 3 | * * | ||
| 4 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
| 5 | * * | ||
| 6 | * Informations about the chip internals needed to enable the I2C protocol * | ||
| 7 | * have been taken from the documentation of the ZC030x Video4Linux1 * | ||
| 8 | * driver written by Andrew Birkett <andy@nobugs.org> * | ||
| 9 | * * | ||
| 10 | * This program is free software; you can redistribute it and/or modify * | ||
| 11 | * it under the terms of the GNU General Public License as published by * | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or * | ||
| 13 | * (at your option) any later version. * | ||
| 14 | * * | ||
| 15 | * This program is distributed in the hope that it will be useful, * | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 18 | * GNU General Public License for more details. * | ||
| 19 | * * | ||
| 20 | * You should have received a copy of the GNU General Public License * | ||
| 21 | * along with this program; if not, write to the Free Software * | ||
| 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
| 23 | ***************************************************************************/ | ||
| 24 | |||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/param.h> | ||
| 29 | #include <linux/moduleparam.h> | ||
| 30 | #include <linux/errno.h> | ||
| 31 | #include <linux/slab.h> | ||
| 32 | #include <linux/device.h> | ||
| 33 | #include <linux/fs.h> | ||
| 34 | #include <linux/delay.h> | ||
| 35 | #include <linux/compiler.h> | ||
| 36 | #include <linux/ioctl.h> | ||
| 37 | #include <linux/poll.h> | ||
| 38 | #include <linux/stat.h> | ||
| 39 | #include <linux/mm.h> | ||
| 40 | #include <linux/vmalloc.h> | ||
| 41 | #include <linux/page-flags.h> | ||
| 42 | #include <linux/byteorder/generic.h> | ||
| 43 | #include <asm/page.h> | ||
| 44 | #include <asm/uaccess.h> | ||
| 45 | |||
| 46 | #include "zc0301.h" | ||
| 47 | |||
| 48 | /*****************************************************************************/ | ||
| 49 | |||
| 50 | #define ZC0301_MODULE_NAME "V4L2 driver for ZC0301 " \ | ||
| 51 | "Image Processor and Control Chip" | ||
| 52 | #define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia" | ||
| 53 | #define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
| 54 | #define ZC0301_MODULE_LICENSE "GPL" | ||
| 55 | #define ZC0301_MODULE_VERSION "1:1.03" | ||
| 56 | #define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 3) | ||
| 57 | |||
| 58 | /*****************************************************************************/ | ||
| 59 | |||
| 60 | MODULE_DEVICE_TABLE(usb, zc0301_id_table); | ||
| 61 | |||
| 62 | MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL); | ||
| 63 | MODULE_DESCRIPTION(ZC0301_MODULE_NAME); | ||
| 64 | MODULE_VERSION(ZC0301_MODULE_VERSION); | ||
| 65 | MODULE_LICENSE(ZC0301_MODULE_LICENSE); | ||
| 66 | |||
| 67 | static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1}; | ||
| 68 | module_param_array(video_nr, short, NULL, 0444); | ||
| 69 | MODULE_PARM_DESC(video_nr, | ||
| 70 | "\n<-1|n[,...]> Specify V4L2 minor mode number." | ||
| 71 | "\n -1 = use next available (default)" | ||
| 72 | "\n n = use minor number n (integer >= 0)" | ||
| 73 | "\nYou can specify up to " | ||
| 74 | __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way." | ||
| 75 | "\nFor example:" | ||
| 76 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
| 77 | "\nthe second registered camera and use auto for the first" | ||
| 78 | "\none and for every other camera." | ||
| 79 | "\n"); | ||
| 80 | |||
| 81 | static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] = | ||
| 82 | ZC0301_FORCE_MUNMAP}; | ||
| 83 | module_param_array(force_munmap, bool, NULL, 0444); | ||
| 84 | MODULE_PARM_DESC(force_munmap, | ||
| 85 | "\n<0|1[,...]> Force the application to unmap previously" | ||
| 86 | "\nmapped buffer memory before calling any VIDIOC_S_CROP or" | ||
| 87 | "\nVIDIOC_S_FMT ioctl's. Not all the applications support" | ||
| 88 | "\nthis feature. This parameter is specific for each" | ||
| 89 | "\ndetected camera." | ||
| 90 | "\n 0 = do not force memory unmapping" | ||
| 91 | "\n 1 = force memory unmapping (save memory)" | ||
| 92 | "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." | ||
| 93 | "\n"); | ||
| 94 | |||
| 95 | static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] = | ||
| 96 | ZC0301_FRAME_TIMEOUT}; | ||
| 97 | module_param_array(frame_timeout, uint, NULL, 0644); | ||
| 98 | MODULE_PARM_DESC(frame_timeout, | ||
| 99 | "\n<n[,...]> Timeout for a video frame in seconds." | ||
| 100 | "\nThis parameter is specific for each detected camera." | ||
| 101 | "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"." | ||
| 102 | "\n"); | ||
| 103 | |||
| 104 | #ifdef ZC0301_DEBUG | ||
| 105 | static unsigned short debug = ZC0301_DEBUG_LEVEL; | ||
| 106 | module_param(debug, ushort, 0644); | ||
| 107 | MODULE_PARM_DESC(debug, | ||
| 108 | "\n<n> Debugging information level, from 0 to 3:" | ||
| 109 | "\n0 = none (use carefully)" | ||
| 110 | "\n1 = critical errors" | ||
| 111 | "\n2 = significant informations" | ||
| 112 | "\n3 = more verbose messages" | ||
| 113 | "\nLevel 3 is useful for testing only, when only " | ||
| 114 | "one device is used." | ||
| 115 | "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"." | ||
| 116 | "\n"); | ||
| 117 | #endif | ||
| 118 | |||
| 119 | /*****************************************************************************/ | ||
| 120 | |||
| 121 | static u32 | ||
| 122 | zc0301_request_buffers(struct zc0301_device* cam, u32 count, | ||
| 123 | enum zc0301_io_method io) | ||
| 124 | { | ||
| 125 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | ||
| 126 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | ||
| 127 | const size_t imagesize = cam->module_param.force_munmap || | ||
| 128 | io == IO_READ ? | ||
| 129 | (p->width * p->height * p->priv) / 8 : | ||
| 130 | (r->width * r->height * p->priv) / 8; | ||
| 131 | void* buff = NULL; | ||
| 132 | u32 i; | ||
| 133 | |||
| 134 | if (count > ZC0301_MAX_FRAMES) | ||
| 135 | count = ZC0301_MAX_FRAMES; | ||
| 136 | |||
| 137 | cam->nbuffers = count; | ||
| 138 | while (cam->nbuffers > 0) { | ||
| 139 | if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) | ||
| 140 | break; | ||
| 141 | cam->nbuffers--; | ||
| 142 | } | ||
| 143 | |||
| 144 | for (i = 0; i < cam->nbuffers; i++) { | ||
| 145 | cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); | ||
| 146 | cam->frame[i].buf.index = i; | ||
| 147 | cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); | ||
| 148 | cam->frame[i].buf.length = imagesize; | ||
| 149 | cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 150 | cam->frame[i].buf.sequence = 0; | ||
| 151 | cam->frame[i].buf.field = V4L2_FIELD_NONE; | ||
| 152 | cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; | ||
| 153 | cam->frame[i].buf.flags = 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | return cam->nbuffers; | ||
| 157 | } | ||
| 158 | |||
| 159 | |||
| 160 | static void zc0301_release_buffers(struct zc0301_device* cam) | ||
| 161 | { | ||
| 162 | if (cam->nbuffers) { | ||
| 163 | vfree(cam->frame[0].bufmem); | ||
| 164 | cam->nbuffers = 0; | ||
| 165 | } | ||
| 166 | cam->frame_current = NULL; | ||
| 167 | } | ||
| 168 | |||
| 169 | |||
| 170 | static void zc0301_empty_framequeues(struct zc0301_device* cam) | ||
| 171 | { | ||
| 172 | u32 i; | ||
| 173 | |||
| 174 | INIT_LIST_HEAD(&cam->inqueue); | ||
| 175 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 176 | |||
| 177 | for (i = 0; i < ZC0301_MAX_FRAMES; i++) { | ||
| 178 | cam->frame[i].state = F_UNUSED; | ||
| 179 | cam->frame[i].buf.bytesused = 0; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | |||
| 184 | static void zc0301_requeue_outqueue(struct zc0301_device* cam) | ||
| 185 | { | ||
| 186 | struct zc0301_frame_t *i; | ||
| 187 | |||
| 188 | list_for_each_entry(i, &cam->outqueue, frame) { | ||
| 189 | i->state = F_QUEUED; | ||
| 190 | list_add(&i->frame, &cam->inqueue); | ||
| 191 | } | ||
| 192 | |||
| 193 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | static void zc0301_queue_unusedframes(struct zc0301_device* cam) | ||
| 198 | { | ||
| 199 | unsigned long lock_flags; | ||
| 200 | u32 i; | ||
| 201 | |||
| 202 | for (i = 0; i < cam->nbuffers; i++) | ||
| 203 | if (cam->frame[i].state == F_UNUSED) { | ||
| 204 | cam->frame[i].state = F_QUEUED; | ||
| 205 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 206 | list_add_tail(&cam->frame[i].frame, &cam->inqueue); | ||
| 207 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | /*****************************************************************************/ | ||
| 212 | |||
| 213 | int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value) | ||
| 214 | { | ||
| 215 | struct usb_device* udev = cam->usbdev; | ||
| 216 | int res; | ||
| 217 | |||
| 218 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40, | ||
| 219 | value, index, NULL, 0, ZC0301_CTRL_TIMEOUT); | ||
| 220 | if (res < 0) { | ||
| 221 | DBG(3, "Failed to write a register (index 0x%04X, " | ||
| 222 | "value 0x%02X, error %d)",index, value, res); | ||
| 223 | return -1; | ||
| 224 | } | ||
| 225 | |||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | |||
| 230 | int zc0301_read_reg(struct zc0301_device* cam, u16 index) | ||
| 231 | { | ||
| 232 | struct usb_device* udev = cam->usbdev; | ||
| 233 | u8* buff = cam->control_buffer; | ||
| 234 | int res; | ||
| 235 | |||
| 236 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0, | ||
| 237 | 0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT); | ||
| 238 | if (res < 0) | ||
| 239 | DBG(3, "Failed to read a register (index 0x%04X, error %d)", | ||
| 240 | index, res); | ||
| 241 | |||
| 242 | PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff)); | ||
| 243 | |||
| 244 | return (res >= 0) ? (int)(*buff) : -1; | ||
| 245 | } | ||
| 246 | |||
| 247 | |||
| 248 | int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length) | ||
| 249 | { | ||
| 250 | int err = 0, res, r0, r1; | ||
| 251 | |||
| 252 | err += zc0301_write_reg(cam, 0x0092, address); | ||
| 253 | err += zc0301_write_reg(cam, 0x0090, 0x02); | ||
| 254 | |||
| 255 | msleep(1); | ||
| 256 | |||
| 257 | res = zc0301_read_reg(cam, 0x0091); | ||
| 258 | if (res < 0) | ||
| 259 | err += res; | ||
| 260 | r0 = zc0301_read_reg(cam, 0x0095); | ||
| 261 | if (r0 < 0) | ||
| 262 | err += r0; | ||
| 263 | r1 = zc0301_read_reg(cam, 0x0096); | ||
| 264 | if (r1 < 0) | ||
| 265 | err += r1; | ||
| 266 | |||
| 267 | res = (length <= 1) ? r0 : r0 | (r1 << 8); | ||
| 268 | |||
| 269 | if (err) | ||
| 270 | DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X", | ||
| 271 | address, res); | ||
| 272 | |||
| 273 | |||
| 274 | PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res); | ||
| 275 | |||
| 276 | return err ? -1 : res; | ||
| 277 | } | ||
| 278 | |||
| 279 | |||
| 280 | int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value) | ||
| 281 | { | ||
| 282 | int err = 0, res; | ||
| 283 | |||
| 284 | err += zc0301_write_reg(cam, 0x0092, address); | ||
| 285 | err += zc0301_write_reg(cam, 0x0093, value & 0xff); | ||
| 286 | err += zc0301_write_reg(cam, 0x0094, value >> 8); | ||
| 287 | err += zc0301_write_reg(cam, 0x0090, 0x01); | ||
| 288 | |||
| 289 | msleep(1); | ||
| 290 | |||
| 291 | res = zc0301_read_reg(cam, 0x0091); | ||
| 292 | if (res < 0) | ||
| 293 | err += res; | ||
| 294 | |||
| 295 | if (err) | ||
| 296 | DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X", | ||
| 297 | address, value); | ||
| 298 | |||
| 299 | PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value); | ||
| 300 | |||
| 301 | return err ? -1 : 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | /*****************************************************************************/ | ||
| 305 | |||
| 306 | static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs) | ||
| 307 | { | ||
| 308 | struct zc0301_device* cam = urb->context; | ||
| 309 | struct zc0301_frame_t** f; | ||
| 310 | size_t imagesize; | ||
| 311 | u8 i; | ||
| 312 | int err = 0; | ||
| 313 | |||
| 314 | if (urb->status == -ENOENT) | ||
| 315 | return; | ||
| 316 | |||
| 317 | f = &cam->frame_current; | ||
| 318 | |||
| 319 | if (cam->stream == STREAM_INTERRUPT) { | ||
| 320 | cam->stream = STREAM_OFF; | ||
| 321 | if ((*f)) | ||
| 322 | (*f)->state = F_QUEUED; | ||
| 323 | DBG(3, "Stream interrupted"); | ||
| 324 | wake_up(&cam->wait_stream); | ||
| 325 | } | ||
| 326 | |||
| 327 | if (cam->state & DEV_DISCONNECTED) | ||
| 328 | return; | ||
| 329 | |||
| 330 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 331 | wake_up_interruptible(&cam->wait_frame); | ||
| 332 | return; | ||
| 333 | } | ||
| 334 | |||
| 335 | if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) | ||
| 336 | goto resubmit_urb; | ||
| 337 | |||
| 338 | if (!(*f)) | ||
| 339 | (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t, | ||
| 340 | frame); | ||
| 341 | |||
| 342 | imagesize = (cam->sensor.pix_format.width * | ||
| 343 | cam->sensor.pix_format.height * | ||
| 344 | cam->sensor.pix_format.priv) / 8; | ||
| 345 | |||
| 346 | for (i = 0; i < urb->number_of_packets; i++) { | ||
| 347 | unsigned int len, status; | ||
| 348 | void *pos; | ||
| 349 | u16* soi; | ||
| 350 | u8 sof; | ||
| 351 | |||
| 352 | len = urb->iso_frame_desc[i].actual_length; | ||
| 353 | status = urb->iso_frame_desc[i].status; | ||
| 354 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
| 355 | |||
| 356 | if (status) { | ||
| 357 | DBG(3, "Error in isochronous frame"); | ||
| 358 | (*f)->state = F_ERROR; | ||
| 359 | continue; | ||
| 360 | } | ||
| 361 | |||
| 362 | sof = (*(soi = pos) == 0xd8ff); | ||
| 363 | |||
| 364 | PDBGG("Isochrnous frame: length %u, #%u i,", len, i); | ||
| 365 | |||
| 366 | if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) | ||
| 367 | start_of_frame: | ||
| 368 | if (sof) { | ||
| 369 | (*f)->state = F_GRABBING; | ||
| 370 | (*f)->buf.bytesused = 0; | ||
| 371 | do_gettimeofday(&(*f)->buf.timestamp); | ||
| 372 | DBG(3, "SOF detected: new video frame"); | ||
| 373 | } | ||
| 374 | |||
| 375 | if ((*f)->state == F_GRABBING) { | ||
| 376 | if (sof && (*f)->buf.bytesused) | ||
| 377 | goto end_of_frame; | ||
| 378 | |||
| 379 | if ((*f)->buf.bytesused + len > imagesize) { | ||
| 380 | DBG(3, "Video frame size exceeded"); | ||
| 381 | (*f)->state = F_ERROR; | ||
| 382 | continue; | ||
| 383 | } | ||
| 384 | |||
| 385 | memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len); | ||
| 386 | (*f)->buf.bytesused += len; | ||
| 387 | |||
| 388 | if ((*f)->buf.bytesused == imagesize) { | ||
| 389 | u32 b; | ||
| 390 | end_of_frame: | ||
| 391 | b = (*f)->buf.bytesused; | ||
| 392 | (*f)->state = F_DONE; | ||
| 393 | (*f)->buf.sequence= ++cam->frame_count; | ||
| 394 | spin_lock(&cam->queue_lock); | ||
| 395 | list_move_tail(&(*f)->frame, &cam->outqueue); | ||
| 396 | if (!list_empty(&cam->inqueue)) | ||
| 397 | (*f) = list_entry(cam->inqueue.next, | ||
| 398 | struct zc0301_frame_t, | ||
| 399 | frame); | ||
| 400 | else | ||
| 401 | (*f) = NULL; | ||
| 402 | spin_unlock(&cam->queue_lock); | ||
| 403 | DBG(3, "Video frame captured: : %lu bytes", | ||
| 404 | (unsigned long)(b)); | ||
| 405 | |||
| 406 | if (!(*f)) | ||
| 407 | goto resubmit_urb; | ||
| 408 | |||
| 409 | if (sof) | ||
| 410 | goto start_of_frame; | ||
| 411 | } | ||
| 412 | } | ||
| 413 | } | ||
| 414 | |||
| 415 | resubmit_urb: | ||
| 416 | urb->dev = cam->usbdev; | ||
| 417 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 418 | if (err < 0 && err != -EPERM) { | ||
| 419 | cam->state |= DEV_MISCONFIGURED; | ||
| 420 | DBG(1, "usb_submit_urb() failed"); | ||
| 421 | } | ||
| 422 | |||
| 423 | wake_up_interruptible(&cam->wait_frame); | ||
| 424 | } | ||
| 425 | |||
| 426 | |||
| 427 | static int zc0301_start_transfer(struct zc0301_device* cam) | ||
| 428 | { | ||
| 429 | struct usb_device *udev = cam->usbdev; | ||
| 430 | struct urb* urb; | ||
| 431 | const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384, | ||
| 432 | 512, 768, 1023}; | ||
| 433 | const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING]; | ||
| 434 | s8 i, j; | ||
| 435 | int err = 0; | ||
| 436 | |||
| 437 | for (i = 0; i < ZC0301_URBS; i++) { | ||
| 438 | cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz, | ||
| 439 | GFP_KERNEL); | ||
| 440 | if (!cam->transfer_buffer[i]) { | ||
| 441 | err = -ENOMEM; | ||
| 442 | DBG(1, "Not enough memory"); | ||
| 443 | goto free_buffers; | ||
| 444 | } | ||
| 445 | } | ||
| 446 | |||
| 447 | for (i = 0; i < ZC0301_URBS; i++) { | ||
| 448 | urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL); | ||
| 449 | cam->urb[i] = urb; | ||
| 450 | if (!urb) { | ||
| 451 | err = -ENOMEM; | ||
| 452 | DBG(1, "usb_alloc_urb() failed"); | ||
| 453 | goto free_urbs; | ||
| 454 | } | ||
| 455 | urb->dev = udev; | ||
| 456 | urb->context = cam; | ||
| 457 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
| 458 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 459 | urb->number_of_packets = ZC0301_ISO_PACKETS; | ||
| 460 | urb->complete = zc0301_urb_complete; | ||
| 461 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
| 462 | urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS; | ||
| 463 | urb->interval = 1; | ||
| 464 | for (j = 0; j < ZC0301_ISO_PACKETS; j++) { | ||
| 465 | urb->iso_frame_desc[j].offset = psz * j; | ||
| 466 | urb->iso_frame_desc[j].length = psz; | ||
| 467 | } | ||
| 468 | } | ||
| 469 | |||
| 470 | err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING); | ||
| 471 | if (err) { | ||
| 472 | DBG(1, "usb_set_interface() failed"); | ||
| 473 | goto free_urbs; | ||
| 474 | } | ||
| 475 | |||
| 476 | cam->frame_current = NULL; | ||
| 477 | |||
| 478 | for (i = 0; i < ZC0301_URBS; i++) { | ||
| 479 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
| 480 | if (err) { | ||
| 481 | for (j = i-1; j >= 0; j--) | ||
| 482 | usb_kill_urb(cam->urb[j]); | ||
| 483 | DBG(1, "usb_submit_urb() failed, error %d", err); | ||
| 484 | goto free_urbs; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | return 0; | ||
| 489 | |||
| 490 | free_urbs: | ||
| 491 | for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++) | ||
| 492 | usb_free_urb(cam->urb[i]); | ||
| 493 | |||
| 494 | free_buffers: | ||
| 495 | for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++) | ||
| 496 | kfree(cam->transfer_buffer[i]); | ||
| 497 | |||
| 498 | return err; | ||
| 499 | } | ||
| 500 | |||
| 501 | |||
| 502 | static int zc0301_stop_transfer(struct zc0301_device* cam) | ||
| 503 | { | ||
| 504 | struct usb_device *udev = cam->usbdev; | ||
| 505 | s8 i; | ||
| 506 | int err = 0; | ||
| 507 | |||
| 508 | if (cam->state & DEV_DISCONNECTED) | ||
| 509 | return 0; | ||
| 510 | |||
| 511 | for (i = ZC0301_URBS-1; i >= 0; i--) { | ||
| 512 | usb_kill_urb(cam->urb[i]); | ||
| 513 | usb_free_urb(cam->urb[i]); | ||
| 514 | kfree(cam->transfer_buffer[i]); | ||
| 515 | } | ||
| 516 | |||
| 517 | err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
| 518 | if (err) | ||
| 519 | DBG(3, "usb_set_interface() failed"); | ||
| 520 | |||
| 521 | return err; | ||
| 522 | } | ||
| 523 | |||
| 524 | |||
| 525 | static int zc0301_stream_interrupt(struct zc0301_device* cam) | ||
| 526 | { | ||
| 527 | long timeout; | ||
| 528 | |||
| 529 | cam->stream = STREAM_INTERRUPT; | ||
| 530 | timeout = wait_event_timeout(cam->wait_stream, | ||
| 531 | (cam->stream == STREAM_OFF) || | ||
| 532 | (cam->state & DEV_DISCONNECTED), | ||
| 533 | ZC0301_URB_TIMEOUT); | ||
| 534 | if (cam->state & DEV_DISCONNECTED) | ||
| 535 | return -ENODEV; | ||
| 536 | else if (cam->stream != STREAM_OFF) { | ||
| 537 | cam->state |= DEV_MISCONFIGURED; | ||
| 538 | DBG(1, "URB timeout reached. The camera is misconfigured. To " | ||
| 539 | "use it, close and open /dev/video%d again.", | ||
| 540 | cam->v4ldev->minor); | ||
| 541 | return -EIO; | ||
| 542 | } | ||
| 543 | |||
| 544 | return 0; | ||
| 545 | } | ||
| 546 | |||
| 547 | /*****************************************************************************/ | ||
| 548 | |||
| 549 | static int | ||
| 550 | zc0301_set_compression(struct zc0301_device* cam, | ||
| 551 | struct v4l2_jpegcompression* compression) | ||
| 552 | { | ||
| 553 | int r, err = 0; | ||
| 554 | |||
| 555 | if ((r = zc0301_read_reg(cam, 0x0008)) < 0) | ||
| 556 | err += r; | ||
| 557 | err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality); | ||
| 558 | |||
| 559 | return err ? -EIO : 0; | ||
| 560 | } | ||
| 561 | |||
| 562 | |||
| 563 | static int zc0301_init(struct zc0301_device* cam) | ||
| 564 | { | ||
| 565 | struct zc0301_sensor* s = &cam->sensor; | ||
| 566 | struct v4l2_control ctrl; | ||
| 567 | struct v4l2_queryctrl *qctrl; | ||
| 568 | struct v4l2_rect* rect; | ||
| 569 | u8 i = 0; | ||
| 570 | int err = 0; | ||
| 571 | |||
| 572 | if (!(cam->state & DEV_INITIALIZED)) { | ||
| 573 | init_waitqueue_head(&cam->open); | ||
| 574 | qctrl = s->qctrl; | ||
| 575 | rect = &(s->cropcap.defrect); | ||
| 576 | cam->compression.quality = ZC0301_COMPRESSION_QUALITY; | ||
| 577 | } else { /* use current values */ | ||
| 578 | qctrl = s->_qctrl; | ||
| 579 | rect = &(s->_rect); | ||
| 580 | } | ||
| 581 | |||
| 582 | if (s->init) { | ||
| 583 | err = s->init(cam); | ||
| 584 | if (err) { | ||
| 585 | DBG(3, "Sensor initialization failed"); | ||
| 586 | return err; | ||
| 587 | } | ||
| 588 | } | ||
| 589 | |||
| 590 | if ((err = zc0301_set_compression(cam, &cam->compression))) { | ||
| 591 | DBG(3, "set_compression() failed"); | ||
| 592 | return err; | ||
| 593 | } | ||
| 594 | |||
| 595 | if (s->set_crop) | ||
| 596 | if ((err = s->set_crop(cam, rect))) { | ||
| 597 | DBG(3, "set_crop() failed"); | ||
| 598 | return err; | ||
| 599 | } | ||
| 600 | |||
| 601 | if (s->set_ctrl) { | ||
| 602 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 603 | if (s->qctrl[i].id != 0 && | ||
| 604 | !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { | ||
| 605 | ctrl.id = s->qctrl[i].id; | ||
| 606 | ctrl.value = qctrl[i].default_value; | ||
| 607 | err = s->set_ctrl(cam, &ctrl); | ||
| 608 | if (err) { | ||
| 609 | DBG(3, "Set %s control failed", | ||
| 610 | s->qctrl[i].name); | ||
| 611 | return err; | ||
| 612 | } | ||
| 613 | DBG(3, "Image sensor supports '%s' control", | ||
| 614 | s->qctrl[i].name); | ||
| 615 | } | ||
| 616 | } | ||
| 617 | |||
| 618 | if (!(cam->state & DEV_INITIALIZED)) { | ||
| 619 | mutex_init(&cam->fileop_mutex); | ||
| 620 | spin_lock_init(&cam->queue_lock); | ||
| 621 | init_waitqueue_head(&cam->wait_frame); | ||
| 622 | init_waitqueue_head(&cam->wait_stream); | ||
| 623 | cam->nreadbuffers = 2; | ||
| 624 | memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); | ||
| 625 | memcpy(&(s->_rect), &(s->cropcap.defrect), | ||
| 626 | sizeof(struct v4l2_rect)); | ||
| 627 | cam->state |= DEV_INITIALIZED; | ||
| 628 | } | ||
| 629 | |||
| 630 | DBG(2, "Initialization succeeded"); | ||
| 631 | return 0; | ||
| 632 | } | ||
| 633 | |||
| 634 | |||
| 635 | static void zc0301_release_resources(struct zc0301_device* cam) | ||
| 636 | { | ||
| 637 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); | ||
| 638 | video_set_drvdata(cam->v4ldev, NULL); | ||
| 639 | video_unregister_device(cam->v4ldev); | ||
| 640 | kfree(cam->control_buffer); | ||
| 641 | } | ||
| 642 | |||
| 643 | /*****************************************************************************/ | ||
| 644 | |||
| 645 | static int zc0301_open(struct inode* inode, struct file* filp) | ||
| 646 | { | ||
| 647 | struct zc0301_device* cam; | ||
| 648 | int err = 0; | ||
| 649 | |||
| 650 | /* | ||
| 651 | This is the only safe way to prevent race conditions with | ||
| 652 | disconnect | ||
| 653 | */ | ||
| 654 | if (!down_read_trylock(&zc0301_disconnect)) | ||
| 655 | return -ERESTARTSYS; | ||
| 656 | |||
| 657 | cam = video_get_drvdata(video_devdata(filp)); | ||
| 658 | |||
| 659 | if (mutex_lock_interruptible(&cam->dev_mutex)) { | ||
| 660 | up_read(&zc0301_disconnect); | ||
| 661 | return -ERESTARTSYS; | ||
| 662 | } | ||
| 663 | |||
| 664 | if (cam->users) { | ||
| 665 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); | ||
| 666 | if ((filp->f_flags & O_NONBLOCK) || | ||
| 667 | (filp->f_flags & O_NDELAY)) { | ||
| 668 | err = -EWOULDBLOCK; | ||
| 669 | goto out; | ||
| 670 | } | ||
| 671 | mutex_unlock(&cam->dev_mutex); | ||
| 672 | err = wait_event_interruptible_exclusive(cam->open, | ||
| 673 | cam->state & DEV_DISCONNECTED | ||
| 674 | || !cam->users); | ||
| 675 | if (err) { | ||
| 676 | up_read(&zc0301_disconnect); | ||
| 677 | return err; | ||
| 678 | } | ||
| 679 | if (cam->state & DEV_DISCONNECTED) { | ||
| 680 | up_read(&zc0301_disconnect); | ||
| 681 | return -ENODEV; | ||
| 682 | } | ||
| 683 | mutex_lock(&cam->dev_mutex); | ||
| 684 | } | ||
| 685 | |||
| 686 | |||
| 687 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 688 | err = zc0301_init(cam); | ||
| 689 | if (err) { | ||
| 690 | DBG(1, "Initialization failed again. " | ||
| 691 | "I will retry on next open()."); | ||
| 692 | goto out; | ||
| 693 | } | ||
| 694 | cam->state &= ~DEV_MISCONFIGURED; | ||
| 695 | } | ||
| 696 | |||
| 697 | if ((err = zc0301_start_transfer(cam))) | ||
| 698 | goto out; | ||
| 699 | |||
| 700 | filp->private_data = cam; | ||
| 701 | cam->users++; | ||
| 702 | cam->io = IO_NONE; | ||
| 703 | cam->stream = STREAM_OFF; | ||
| 704 | cam->nbuffers = 0; | ||
| 705 | cam->frame_count = 0; | ||
| 706 | zc0301_empty_framequeues(cam); | ||
| 707 | |||
| 708 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); | ||
| 709 | |||
| 710 | out: | ||
| 711 | mutex_unlock(&cam->dev_mutex); | ||
| 712 | up_read(&zc0301_disconnect); | ||
| 713 | return err; | ||
| 714 | } | ||
| 715 | |||
| 716 | |||
| 717 | static int zc0301_release(struct inode* inode, struct file* filp) | ||
| 718 | { | ||
| 719 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 720 | |||
| 721 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ | ||
| 722 | |||
| 723 | zc0301_stop_transfer(cam); | ||
| 724 | |||
| 725 | zc0301_release_buffers(cam); | ||
| 726 | |||
| 727 | if (cam->state & DEV_DISCONNECTED) { | ||
| 728 | zc0301_release_resources(cam); | ||
| 729 | usb_put_dev(cam->usbdev); | ||
| 730 | mutex_unlock(&cam->dev_mutex); | ||
| 731 | kfree(cam); | ||
| 732 | return 0; | ||
| 733 | } | ||
| 734 | |||
| 735 | cam->users--; | ||
| 736 | wake_up_interruptible_nr(&cam->open, 1); | ||
| 737 | |||
| 738 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); | ||
| 739 | |||
| 740 | mutex_unlock(&cam->dev_mutex); | ||
| 741 | |||
| 742 | return 0; | ||
| 743 | } | ||
| 744 | |||
| 745 | |||
| 746 | static ssize_t | ||
| 747 | zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | ||
| 748 | { | ||
| 749 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 750 | struct zc0301_frame_t* f, * i; | ||
| 751 | unsigned long lock_flags; | ||
| 752 | long timeout; | ||
| 753 | int err = 0; | ||
| 754 | |||
| 755 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 756 | return -ERESTARTSYS; | ||
| 757 | |||
| 758 | if (cam->state & DEV_DISCONNECTED) { | ||
| 759 | DBG(1, "Device not present"); | ||
| 760 | mutex_unlock(&cam->fileop_mutex); | ||
| 761 | return -ENODEV; | ||
| 762 | } | ||
| 763 | |||
| 764 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 765 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 766 | "again."); | ||
| 767 | mutex_unlock(&cam->fileop_mutex); | ||
| 768 | return -EIO; | ||
| 769 | } | ||
| 770 | |||
| 771 | if (cam->io == IO_MMAP) { | ||
| 772 | DBG(3, "Close and open the device again to choose the read " | ||
| 773 | "method"); | ||
| 774 | mutex_unlock(&cam->fileop_mutex); | ||
| 775 | return -EINVAL; | ||
| 776 | } | ||
| 777 | |||
| 778 | if (cam->io == IO_NONE) { | ||
| 779 | if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) { | ||
| 780 | DBG(1, "read() failed, not enough memory"); | ||
| 781 | mutex_unlock(&cam->fileop_mutex); | ||
| 782 | return -ENOMEM; | ||
| 783 | } | ||
| 784 | cam->io = IO_READ; | ||
| 785 | cam->stream = STREAM_ON; | ||
| 786 | } | ||
| 787 | |||
| 788 | if (list_empty(&cam->inqueue)) { | ||
| 789 | if (!list_empty(&cam->outqueue)) | ||
| 790 | zc0301_empty_framequeues(cam); | ||
| 791 | zc0301_queue_unusedframes(cam); | ||
| 792 | } | ||
| 793 | |||
| 794 | if (!count) { | ||
| 795 | mutex_unlock(&cam->fileop_mutex); | ||
| 796 | return 0; | ||
| 797 | } | ||
| 798 | |||
| 799 | if (list_empty(&cam->outqueue)) { | ||
| 800 | if (filp->f_flags & O_NONBLOCK) { | ||
| 801 | mutex_unlock(&cam->fileop_mutex); | ||
| 802 | return -EAGAIN; | ||
| 803 | } | ||
| 804 | timeout = wait_event_interruptible_timeout | ||
| 805 | ( cam->wait_frame, | ||
| 806 | (!list_empty(&cam->outqueue)) || | ||
| 807 | (cam->state & DEV_DISCONNECTED) || | ||
| 808 | (cam->state & DEV_MISCONFIGURED), | ||
| 809 | cam->module_param.frame_timeout * | ||
| 810 | 1000 * msecs_to_jiffies(1) ); | ||
| 811 | if (timeout < 0) { | ||
| 812 | mutex_unlock(&cam->fileop_mutex); | ||
| 813 | return timeout; | ||
| 814 | } | ||
| 815 | if (cam->state & DEV_DISCONNECTED) { | ||
| 816 | mutex_unlock(&cam->fileop_mutex); | ||
| 817 | return -ENODEV; | ||
| 818 | } | ||
| 819 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) { | ||
| 820 | mutex_unlock(&cam->fileop_mutex); | ||
| 821 | return -EIO; | ||
| 822 | } | ||
| 823 | } | ||
| 824 | |||
| 825 | f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame); | ||
| 826 | |||
| 827 | if (count > f->buf.bytesused) | ||
| 828 | count = f->buf.bytesused; | ||
| 829 | |||
| 830 | if (copy_to_user(buf, f->bufmem, count)) { | ||
| 831 | err = -EFAULT; | ||
| 832 | goto exit; | ||
| 833 | } | ||
| 834 | *f_pos += count; | ||
| 835 | |||
| 836 | exit: | ||
| 837 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 838 | list_for_each_entry(i, &cam->outqueue, frame) | ||
| 839 | i->state = F_UNUSED; | ||
| 840 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 841 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 842 | |||
| 843 | zc0301_queue_unusedframes(cam); | ||
| 844 | |||
| 845 | PDBGG("Frame #%lu, bytes read: %zu", | ||
| 846 | (unsigned long)f->buf.index, count); | ||
| 847 | |||
| 848 | mutex_unlock(&cam->fileop_mutex); | ||
| 849 | |||
| 850 | return err ? err : count; | ||
| 851 | } | ||
| 852 | |||
| 853 | |||
| 854 | static unsigned int zc0301_poll(struct file *filp, poll_table *wait) | ||
| 855 | { | ||
| 856 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 857 | struct zc0301_frame_t* f; | ||
| 858 | unsigned long lock_flags; | ||
| 859 | unsigned int mask = 0; | ||
| 860 | |||
| 861 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 862 | return POLLERR; | ||
| 863 | |||
| 864 | if (cam->state & DEV_DISCONNECTED) { | ||
| 865 | DBG(1, "Device not present"); | ||
| 866 | goto error; | ||
| 867 | } | ||
| 868 | |||
| 869 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 870 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 871 | "again."); | ||
| 872 | goto error; | ||
| 873 | } | ||
| 874 | |||
| 875 | if (cam->io == IO_NONE) { | ||
| 876 | if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) { | ||
| 877 | DBG(1, "poll() failed, not enough memory"); | ||
| 878 | goto error; | ||
| 879 | } | ||
| 880 | cam->io = IO_READ; | ||
| 881 | cam->stream = STREAM_ON; | ||
| 882 | } | ||
| 883 | |||
| 884 | if (cam->io == IO_READ) { | ||
| 885 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 886 | list_for_each_entry(f, &cam->outqueue, frame) | ||
| 887 | f->state = F_UNUSED; | ||
| 888 | INIT_LIST_HEAD(&cam->outqueue); | ||
| 889 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 890 | zc0301_queue_unusedframes(cam); | ||
| 891 | } | ||
| 892 | |||
| 893 | poll_wait(filp, &cam->wait_frame, wait); | ||
| 894 | |||
| 895 | if (!list_empty(&cam->outqueue)) | ||
| 896 | mask |= POLLIN | POLLRDNORM; | ||
| 897 | |||
| 898 | mutex_unlock(&cam->fileop_mutex); | ||
| 899 | |||
| 900 | return mask; | ||
| 901 | |||
| 902 | error: | ||
| 903 | mutex_unlock(&cam->fileop_mutex); | ||
| 904 | return POLLERR; | ||
| 905 | } | ||
| 906 | |||
| 907 | |||
| 908 | static void zc0301_vm_open(struct vm_area_struct* vma) | ||
| 909 | { | ||
| 910 | struct zc0301_frame_t* f = vma->vm_private_data; | ||
| 911 | f->vma_use_count++; | ||
| 912 | } | ||
| 913 | |||
| 914 | |||
| 915 | static void zc0301_vm_close(struct vm_area_struct* vma) | ||
| 916 | { | ||
| 917 | /* NOTE: buffers are not freed here */ | ||
| 918 | struct zc0301_frame_t* f = vma->vm_private_data; | ||
| 919 | f->vma_use_count--; | ||
| 920 | } | ||
| 921 | |||
| 922 | |||
| 923 | static struct vm_operations_struct zc0301_vm_ops = { | ||
| 924 | .open = zc0301_vm_open, | ||
| 925 | .close = zc0301_vm_close, | ||
| 926 | }; | ||
| 927 | |||
| 928 | |||
| 929 | static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma) | ||
| 930 | { | ||
| 931 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 932 | unsigned long size = vma->vm_end - vma->vm_start, | ||
| 933 | start = vma->vm_start; | ||
| 934 | void *pos; | ||
| 935 | u32 i; | ||
| 936 | |||
| 937 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 938 | return -ERESTARTSYS; | ||
| 939 | |||
| 940 | if (cam->state & DEV_DISCONNECTED) { | ||
| 941 | DBG(1, "Device not present"); | ||
| 942 | mutex_unlock(&cam->fileop_mutex); | ||
| 943 | return -ENODEV; | ||
| 944 | } | ||
| 945 | |||
| 946 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 947 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 948 | "again."); | ||
| 949 | mutex_unlock(&cam->fileop_mutex); | ||
| 950 | return -EIO; | ||
| 951 | } | ||
| 952 | |||
| 953 | if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | ||
| 954 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | ||
| 955 | mutex_unlock(&cam->fileop_mutex); | ||
| 956 | return -EINVAL; | ||
| 957 | } | ||
| 958 | |||
| 959 | for (i = 0; i < cam->nbuffers; i++) { | ||
| 960 | if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) | ||
| 961 | break; | ||
| 962 | } | ||
| 963 | if (i == cam->nbuffers) { | ||
| 964 | mutex_unlock(&cam->fileop_mutex); | ||
| 965 | return -EINVAL; | ||
| 966 | } | ||
| 967 | |||
| 968 | vma->vm_flags |= VM_IO; | ||
| 969 | vma->vm_flags |= VM_RESERVED; | ||
| 970 | |||
| 971 | pos = cam->frame[i].bufmem; | ||
| 972 | while (size > 0) { /* size is page-aligned */ | ||
| 973 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { | ||
| 974 | mutex_unlock(&cam->fileop_mutex); | ||
| 975 | return -EAGAIN; | ||
| 976 | } | ||
| 977 | start += PAGE_SIZE; | ||
| 978 | pos += PAGE_SIZE; | ||
| 979 | size -= PAGE_SIZE; | ||
| 980 | } | ||
| 981 | |||
| 982 | vma->vm_ops = &zc0301_vm_ops; | ||
| 983 | vma->vm_private_data = &cam->frame[i]; | ||
| 984 | |||
| 985 | zc0301_vm_open(vma); | ||
| 986 | |||
| 987 | mutex_unlock(&cam->fileop_mutex); | ||
| 988 | |||
| 989 | return 0; | ||
| 990 | } | ||
| 991 | |||
| 992 | /*****************************************************************************/ | ||
| 993 | |||
| 994 | static int | ||
| 995 | zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg) | ||
| 996 | { | ||
| 997 | struct v4l2_capability cap = { | ||
| 998 | .driver = "zc0301", | ||
| 999 | .version = ZC0301_MODULE_VERSION_CODE, | ||
| 1000 | .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
| 1001 | V4L2_CAP_STREAMING, | ||
| 1002 | }; | ||
| 1003 | |||
| 1004 | strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); | ||
| 1005 | if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) | ||
| 1006 | strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, | ||
| 1007 | sizeof(cap.bus_info)); | ||
| 1008 | |||
| 1009 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
| 1010 | return -EFAULT; | ||
| 1011 | |||
| 1012 | return 0; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | |||
| 1016 | static int | ||
| 1017 | zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg) | ||
| 1018 | { | ||
| 1019 | struct v4l2_input i; | ||
| 1020 | |||
| 1021 | if (copy_from_user(&i, arg, sizeof(i))) | ||
| 1022 | return -EFAULT; | ||
| 1023 | |||
| 1024 | if (i.index) | ||
| 1025 | return -EINVAL; | ||
| 1026 | |||
| 1027 | memset(&i, 0, sizeof(i)); | ||
| 1028 | strcpy(i.name, "Camera"); | ||
| 1029 | i.type = V4L2_INPUT_TYPE_CAMERA; | ||
| 1030 | |||
| 1031 | if (copy_to_user(arg, &i, sizeof(i))) | ||
| 1032 | return -EFAULT; | ||
| 1033 | |||
| 1034 | return 0; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | |||
| 1038 | static int | ||
| 1039 | zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg) | ||
| 1040 | { | ||
| 1041 | int index = 0; | ||
| 1042 | |||
| 1043 | if (copy_to_user(arg, &index, sizeof(index))) | ||
| 1044 | return -EFAULT; | ||
| 1045 | |||
| 1046 | return 0; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | |||
| 1050 | static int | ||
| 1051 | zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg) | ||
| 1052 | { | ||
| 1053 | int index; | ||
| 1054 | |||
| 1055 | if (copy_from_user(&index, arg, sizeof(index))) | ||
| 1056 | return -EFAULT; | ||
| 1057 | |||
| 1058 | if (index != 0) | ||
| 1059 | return -EINVAL; | ||
| 1060 | |||
| 1061 | return 0; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | |||
| 1065 | static int | ||
| 1066 | zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg) | ||
| 1067 | { | ||
| 1068 | struct zc0301_sensor* s = &cam->sensor; | ||
| 1069 | struct v4l2_queryctrl qc; | ||
| 1070 | u8 i; | ||
| 1071 | |||
| 1072 | if (copy_from_user(&qc, arg, sizeof(qc))) | ||
| 1073 | return -EFAULT; | ||
| 1074 | |||
| 1075 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1076 | if (qc.id && qc.id == s->qctrl[i].id) { | ||
| 1077 | memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); | ||
| 1078 | if (copy_to_user(arg, &qc, sizeof(qc))) | ||
| 1079 | return -EFAULT; | ||
| 1080 | return 0; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | return -EINVAL; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | |||
| 1087 | static int | ||
| 1088 | zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg) | ||
| 1089 | { | ||
| 1090 | struct zc0301_sensor* s = &cam->sensor; | ||
| 1091 | struct v4l2_control ctrl; | ||
| 1092 | int err = 0; | ||
| 1093 | u8 i; | ||
| 1094 | |||
| 1095 | if (!s->get_ctrl && !s->set_ctrl) | ||
| 1096 | return -EINVAL; | ||
| 1097 | |||
| 1098 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
| 1099 | return -EFAULT; | ||
| 1100 | |||
| 1101 | if (!s->get_ctrl) { | ||
| 1102 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1103 | if (ctrl.id == s->qctrl[i].id) { | ||
| 1104 | ctrl.value = s->_qctrl[i].default_value; | ||
| 1105 | goto exit; | ||
| 1106 | } | ||
| 1107 | return -EINVAL; | ||
| 1108 | } else | ||
| 1109 | err = s->get_ctrl(cam, &ctrl); | ||
| 1110 | |||
| 1111 | exit: | ||
| 1112 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) | ||
| 1113 | return -EFAULT; | ||
| 1114 | |||
| 1115 | return err; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | |||
| 1119 | static int | ||
| 1120 | zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg) | ||
| 1121 | { | ||
| 1122 | struct zc0301_sensor* s = &cam->sensor; | ||
| 1123 | struct v4l2_control ctrl; | ||
| 1124 | u8 i; | ||
| 1125 | int err = 0; | ||
| 1126 | |||
| 1127 | if (!s->set_ctrl) | ||
| 1128 | return -EINVAL; | ||
| 1129 | |||
| 1130 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
| 1131 | return -EFAULT; | ||
| 1132 | |||
| 1133 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
| 1134 | if (ctrl.id == s->qctrl[i].id) { | ||
| 1135 | if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) | ||
| 1136 | return -EINVAL; | ||
| 1137 | if (ctrl.value < s->qctrl[i].minimum || | ||
| 1138 | ctrl.value > s->qctrl[i].maximum) | ||
| 1139 | return -ERANGE; | ||
| 1140 | ctrl.value -= ctrl.value % s->qctrl[i].step; | ||
| 1141 | break; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | if ((err = s->set_ctrl(cam, &ctrl))) | ||
| 1145 | return err; | ||
| 1146 | |||
| 1147 | s->_qctrl[i].default_value = ctrl.value; | ||
| 1148 | |||
| 1149 | return 0; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | |||
| 1153 | static int | ||
| 1154 | zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg) | ||
| 1155 | { | ||
| 1156 | struct v4l2_cropcap* cc = &(cam->sensor.cropcap); | ||
| 1157 | |||
| 1158 | cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 1159 | cc->pixelaspect.numerator = 1; | ||
| 1160 | cc->pixelaspect.denominator = 1; | ||
| 1161 | |||
| 1162 | if (copy_to_user(arg, cc, sizeof(*cc))) | ||
| 1163 | return -EFAULT; | ||
| 1164 | |||
| 1165 | return 0; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | |||
| 1169 | static int | ||
| 1170 | zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg) | ||
| 1171 | { | ||
| 1172 | struct zc0301_sensor* s = &cam->sensor; | ||
| 1173 | struct v4l2_crop crop = { | ||
| 1174 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
| 1175 | }; | ||
| 1176 | |||
| 1177 | memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); | ||
| 1178 | |||
| 1179 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
| 1180 | return -EFAULT; | ||
| 1181 | |||
| 1182 | return 0; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | |||
| 1186 | static int | ||
| 1187 | zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) | ||
| 1188 | { | ||
| 1189 | struct zc0301_sensor* s = &cam->sensor; | ||
| 1190 | struct v4l2_crop crop; | ||
| 1191 | struct v4l2_rect* rect; | ||
| 1192 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
| 1193 | const enum zc0301_stream_state stream = cam->stream; | ||
| 1194 | const u32 nbuffers = cam->nbuffers; | ||
| 1195 | u32 i; | ||
| 1196 | int err = 0; | ||
| 1197 | |||
| 1198 | if (copy_from_user(&crop, arg, sizeof(crop))) | ||
| 1199 | return -EFAULT; | ||
| 1200 | |||
| 1201 | rect = &(crop.c); | ||
| 1202 | |||
| 1203 | if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1204 | return -EINVAL; | ||
| 1205 | |||
| 1206 | if (cam->module_param.force_munmap) | ||
| 1207 | for (i = 0; i < cam->nbuffers; i++) | ||
| 1208 | if (cam->frame[i].vma_use_count) { | ||
| 1209 | DBG(3, "VIDIOC_S_CROP failed. " | ||
| 1210 | "Unmap the buffers first."); | ||
| 1211 | return -EINVAL; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | if (!s->set_crop) { | ||
| 1215 | memcpy(rect, &(s->_rect), sizeof(*rect)); | ||
| 1216 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
| 1217 | return -EFAULT; | ||
| 1218 | return 0; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | rect->left &= ~7L; | ||
| 1222 | rect->top &= ~7L; | ||
| 1223 | if (rect->width < 8) | ||
| 1224 | rect->width = 8; | ||
| 1225 | if (rect->height < 8) | ||
| 1226 | rect->height = 8; | ||
| 1227 | if (rect->width > bounds->width) | ||
| 1228 | rect->width = bounds->width; | ||
| 1229 | if (rect->height > bounds->height) | ||
| 1230 | rect->height = bounds->height; | ||
| 1231 | if (rect->left < bounds->left) | ||
| 1232 | rect->left = bounds->left; | ||
| 1233 | if (rect->top < bounds->top) | ||
| 1234 | rect->top = bounds->top; | ||
| 1235 | if (rect->left + rect->width > bounds->left + bounds->width) | ||
| 1236 | rect->left = bounds->left+bounds->width - rect->width; | ||
| 1237 | if (rect->top + rect->height > bounds->top + bounds->height) | ||
| 1238 | rect->top = bounds->top+bounds->height - rect->height; | ||
| 1239 | rect->width &= ~7L; | ||
| 1240 | rect->height &= ~7L; | ||
| 1241 | |||
| 1242 | if (cam->stream == STREAM_ON) | ||
| 1243 | if ((err = zc0301_stream_interrupt(cam))) | ||
| 1244 | return err; | ||
| 1245 | |||
| 1246 | if (copy_to_user(arg, &crop, sizeof(crop))) { | ||
| 1247 | cam->stream = stream; | ||
| 1248 | return -EFAULT; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
| 1252 | zc0301_release_buffers(cam); | ||
| 1253 | |||
| 1254 | if (s->set_crop) | ||
| 1255 | err += s->set_crop(cam, rect); | ||
| 1256 | |||
| 1257 | if (err) { /* atomic, no rollback in ioctl() */ | ||
| 1258 | cam->state |= DEV_MISCONFIGURED; | ||
| 1259 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | ||
| 1260 | "use the camera, close and open /dev/video%d again.", | ||
| 1261 | cam->v4ldev->minor); | ||
| 1262 | return -EIO; | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | s->pix_format.width = rect->width; | ||
| 1266 | s->pix_format.height = rect->height; | ||
| 1267 | memcpy(&(s->_rect), rect, sizeof(*rect)); | ||
| 1268 | |||
| 1269 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
| 1270 | nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { | ||
| 1271 | cam->state |= DEV_MISCONFIGURED; | ||
| 1272 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | ||
| 1273 | "use the camera, close and open /dev/video%d again.", | ||
| 1274 | cam->v4ldev->minor); | ||
| 1275 | return -ENOMEM; | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | if (cam->io == IO_READ) | ||
| 1279 | zc0301_empty_framequeues(cam); | ||
| 1280 | else if (cam->module_param.force_munmap) | ||
| 1281 | zc0301_requeue_outqueue(cam); | ||
| 1282 | |||
| 1283 | cam->stream = stream; | ||
| 1284 | |||
| 1285 | return 0; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | |||
| 1289 | static int | ||
| 1290 | zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg) | ||
| 1291 | { | ||
| 1292 | struct v4l2_fmtdesc fmtd; | ||
| 1293 | |||
| 1294 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) | ||
| 1295 | return -EFAULT; | ||
| 1296 | |||
| 1297 | if (fmtd.index == 0) { | ||
| 1298 | strcpy(fmtd.description, "JPEG"); | ||
| 1299 | fmtd.pixelformat = V4L2_PIX_FMT_JPEG; | ||
| 1300 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; | ||
| 1301 | } else | ||
| 1302 | return -EINVAL; | ||
| 1303 | |||
| 1304 | fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 1305 | memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); | ||
| 1306 | |||
| 1307 | if (copy_to_user(arg, &fmtd, sizeof(fmtd))) | ||
| 1308 | return -EFAULT; | ||
| 1309 | |||
| 1310 | return 0; | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | |||
| 1314 | static int | ||
| 1315 | zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg) | ||
| 1316 | { | ||
| 1317 | struct v4l2_format format; | ||
| 1318 | struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); | ||
| 1319 | |||
| 1320 | if (copy_from_user(&format, arg, sizeof(format))) | ||
| 1321 | return -EFAULT; | ||
| 1322 | |||
| 1323 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1324 | return -EINVAL; | ||
| 1325 | |||
| 1326 | pfmt->bytesperline = 0; | ||
| 1327 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | ||
| 1328 | pfmt->field = V4L2_FIELD_NONE; | ||
| 1329 | memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); | ||
| 1330 | |||
| 1331 | if (copy_to_user(arg, &format, sizeof(format))) | ||
| 1332 | return -EFAULT; | ||
| 1333 | |||
| 1334 | return 0; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | |||
| 1338 | static int | ||
| 1339 | zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, | ||
| 1340 | void __user * arg) | ||
| 1341 | { | ||
| 1342 | struct zc0301_sensor* s = &cam->sensor; | ||
| 1343 | struct v4l2_format format; | ||
| 1344 | struct v4l2_pix_format* pix; | ||
| 1345 | struct v4l2_pix_format* pfmt = &(s->pix_format); | ||
| 1346 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
| 1347 | struct v4l2_rect rect; | ||
| 1348 | const enum zc0301_stream_state stream = cam->stream; | ||
| 1349 | const u32 nbuffers = cam->nbuffers; | ||
| 1350 | u32 i; | ||
| 1351 | int err = 0; | ||
| 1352 | |||
| 1353 | if (copy_from_user(&format, arg, sizeof(format))) | ||
| 1354 | return -EFAULT; | ||
| 1355 | |||
| 1356 | pix = &(format.fmt.pix); | ||
| 1357 | |||
| 1358 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1359 | return -EINVAL; | ||
| 1360 | |||
| 1361 | memcpy(&rect, &(s->_rect), sizeof(rect)); | ||
| 1362 | |||
| 1363 | if (!s->set_crop) { | ||
| 1364 | pix->width = rect.width; | ||
| 1365 | pix->height = rect.height; | ||
| 1366 | } else { | ||
| 1367 | rect.width = pix->width; | ||
| 1368 | rect.height = pix->height; | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | if (rect.width < 8) | ||
| 1372 | rect.width = 8; | ||
| 1373 | if (rect.height < 8) | ||
| 1374 | rect.height = 8; | ||
| 1375 | if (rect.width > bounds->left + bounds->width - rect.left) | ||
| 1376 | rect.width = bounds->left + bounds->width - rect.left; | ||
| 1377 | if (rect.height > bounds->top + bounds->height - rect.top) | ||
| 1378 | rect.height = bounds->top + bounds->height - rect.top; | ||
| 1379 | rect.width &= ~7L; | ||
| 1380 | rect.height &= ~7L; | ||
| 1381 | |||
| 1382 | pix->width = rect.width; | ||
| 1383 | pix->height = rect.height; | ||
| 1384 | pix->pixelformat = pfmt->pixelformat; | ||
| 1385 | pix->priv = pfmt->priv; | ||
| 1386 | pix->colorspace = pfmt->colorspace; | ||
| 1387 | pix->bytesperline = 0; | ||
| 1388 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); | ||
| 1389 | pix->field = V4L2_FIELD_NONE; | ||
| 1390 | |||
| 1391 | if (cmd == VIDIOC_TRY_FMT) { | ||
| 1392 | if (copy_to_user(arg, &format, sizeof(format))) | ||
| 1393 | return -EFAULT; | ||
| 1394 | return 0; | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | if (cam->module_param.force_munmap) | ||
| 1398 | for (i = 0; i < cam->nbuffers; i++) | ||
| 1399 | if (cam->frame[i].vma_use_count) { | ||
| 1400 | DBG(3, "VIDIOC_S_FMT failed. " | ||
| 1401 | "Unmap the buffers first."); | ||
| 1402 | return -EINVAL; | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | if (cam->stream == STREAM_ON) | ||
| 1406 | if ((err = zc0301_stream_interrupt(cam))) | ||
| 1407 | return err; | ||
| 1408 | |||
| 1409 | if (copy_to_user(arg, &format, sizeof(format))) { | ||
| 1410 | cam->stream = stream; | ||
| 1411 | return -EFAULT; | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
| 1415 | zc0301_release_buffers(cam); | ||
| 1416 | |||
| 1417 | if (s->set_crop) | ||
| 1418 | err += s->set_crop(cam, &rect); | ||
| 1419 | |||
| 1420 | if (err) { /* atomic, no rollback in ioctl() */ | ||
| 1421 | cam->state |= DEV_MISCONFIGURED; | ||
| 1422 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | ||
| 1423 | "use the camera, close and open /dev/video%d again.", | ||
| 1424 | cam->v4ldev->minor); | ||
| 1425 | return -EIO; | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | memcpy(pfmt, pix, sizeof(*pix)); | ||
| 1429 | memcpy(&(s->_rect), &rect, sizeof(rect)); | ||
| 1430 | |||
| 1431 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
| 1432 | nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { | ||
| 1433 | cam->state |= DEV_MISCONFIGURED; | ||
| 1434 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | ||
| 1435 | "use the camera, close and open /dev/video%d again.", | ||
| 1436 | cam->v4ldev->minor); | ||
| 1437 | return -ENOMEM; | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | if (cam->io == IO_READ) | ||
| 1441 | zc0301_empty_framequeues(cam); | ||
| 1442 | else if (cam->module_param.force_munmap) | ||
| 1443 | zc0301_requeue_outqueue(cam); | ||
| 1444 | |||
| 1445 | cam->stream = stream; | ||
| 1446 | |||
| 1447 | return 0; | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | |||
| 1451 | static int | ||
| 1452 | zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg) | ||
| 1453 | { | ||
| 1454 | if (copy_to_user(arg, &cam->compression, sizeof(cam->compression))) | ||
| 1455 | return -EFAULT; | ||
| 1456 | |||
| 1457 | return 0; | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | |||
| 1461 | static int | ||
| 1462 | zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg) | ||
| 1463 | { | ||
| 1464 | struct v4l2_jpegcompression jc; | ||
| 1465 | const enum zc0301_stream_state stream = cam->stream; | ||
| 1466 | int err = 0; | ||
| 1467 | |||
| 1468 | if (copy_from_user(&jc, arg, sizeof(jc))) | ||
| 1469 | return -EFAULT; | ||
| 1470 | |||
| 1471 | if (jc.quality != 0) | ||
| 1472 | return -EINVAL; | ||
| 1473 | |||
| 1474 | if (cam->stream == STREAM_ON) | ||
| 1475 | if ((err = zc0301_stream_interrupt(cam))) | ||
| 1476 | return err; | ||
| 1477 | |||
| 1478 | err += zc0301_set_compression(cam, &jc); | ||
| 1479 | if (err) { /* atomic, no rollback in ioctl() */ | ||
| 1480 | cam->state |= DEV_MISCONFIGURED; | ||
| 1481 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | ||
| 1482 | "problems. To use the camera, close and open " | ||
| 1483 | "/dev/video%d again.", cam->v4ldev->minor); | ||
| 1484 | return -EIO; | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | cam->compression.quality = jc.quality; | ||
| 1488 | |||
| 1489 | cam->stream = stream; | ||
| 1490 | |||
| 1491 | return 0; | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | |||
| 1495 | static int | ||
| 1496 | zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg) | ||
| 1497 | { | ||
| 1498 | struct v4l2_requestbuffers rb; | ||
| 1499 | u32 i; | ||
| 1500 | int err; | ||
| 1501 | |||
| 1502 | if (copy_from_user(&rb, arg, sizeof(rb))) | ||
| 1503 | return -EFAULT; | ||
| 1504 | |||
| 1505 | if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
| 1506 | rb.memory != V4L2_MEMORY_MMAP) | ||
| 1507 | return -EINVAL; | ||
| 1508 | |||
| 1509 | if (cam->io == IO_READ) { | ||
| 1510 | DBG(3, "Close and open the device again to choose the mmap " | ||
| 1511 | "I/O method"); | ||
| 1512 | return -EINVAL; | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | for (i = 0; i < cam->nbuffers; i++) | ||
| 1516 | if (cam->frame[i].vma_use_count) { | ||
| 1517 | DBG(3, "VIDIOC_REQBUFS failed. " | ||
| 1518 | "Previous buffers are still mapped."); | ||
| 1519 | return -EINVAL; | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | if (cam->stream == STREAM_ON) | ||
| 1523 | if ((err = zc0301_stream_interrupt(cam))) | ||
| 1524 | return err; | ||
| 1525 | |||
| 1526 | zc0301_empty_framequeues(cam); | ||
| 1527 | |||
| 1528 | zc0301_release_buffers(cam); | ||
| 1529 | if (rb.count) | ||
| 1530 | rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP); | ||
| 1531 | |||
| 1532 | if (copy_to_user(arg, &rb, sizeof(rb))) { | ||
| 1533 | zc0301_release_buffers(cam); | ||
| 1534 | cam->io = IO_NONE; | ||
| 1535 | return -EFAULT; | ||
| 1536 | } | ||
| 1537 | |||
| 1538 | cam->io = rb.count ? IO_MMAP : IO_NONE; | ||
| 1539 | |||
| 1540 | return 0; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | |||
| 1544 | static int | ||
| 1545 | zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg) | ||
| 1546 | { | ||
| 1547 | struct v4l2_buffer b; | ||
| 1548 | |||
| 1549 | if (copy_from_user(&b, arg, sizeof(b))) | ||
| 1550 | return -EFAULT; | ||
| 1551 | |||
| 1552 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
| 1553 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
| 1554 | return -EINVAL; | ||
| 1555 | |||
| 1556 | memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); | ||
| 1557 | |||
| 1558 | if (cam->frame[b.index].vma_use_count) | ||
| 1559 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
| 1560 | |||
| 1561 | if (cam->frame[b.index].state == F_DONE) | ||
| 1562 | b.flags |= V4L2_BUF_FLAG_DONE; | ||
| 1563 | else if (cam->frame[b.index].state != F_UNUSED) | ||
| 1564 | b.flags |= V4L2_BUF_FLAG_QUEUED; | ||
| 1565 | |||
| 1566 | if (copy_to_user(arg, &b, sizeof(b))) | ||
| 1567 | return -EFAULT; | ||
| 1568 | |||
| 1569 | return 0; | ||
| 1570 | } | ||
| 1571 | |||
| 1572 | |||
| 1573 | static int | ||
| 1574 | zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg) | ||
| 1575 | { | ||
| 1576 | struct v4l2_buffer b; | ||
| 1577 | unsigned long lock_flags; | ||
| 1578 | |||
| 1579 | if (copy_from_user(&b, arg, sizeof(b))) | ||
| 1580 | return -EFAULT; | ||
| 1581 | |||
| 1582 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
| 1583 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
| 1584 | return -EINVAL; | ||
| 1585 | |||
| 1586 | if (cam->frame[b.index].state != F_UNUSED) | ||
| 1587 | return -EINVAL; | ||
| 1588 | |||
| 1589 | cam->frame[b.index].state = F_QUEUED; | ||
| 1590 | |||
| 1591 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 1592 | list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); | ||
| 1593 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 1594 | |||
| 1595 | PDBGG("Frame #%lu queued", (unsigned long)b.index); | ||
| 1596 | |||
| 1597 | return 0; | ||
| 1598 | } | ||
| 1599 | |||
| 1600 | |||
| 1601 | static int | ||
| 1602 | zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp, | ||
| 1603 | void __user * arg) | ||
| 1604 | { | ||
| 1605 | struct v4l2_buffer b; | ||
| 1606 | struct zc0301_frame_t *f; | ||
| 1607 | unsigned long lock_flags; | ||
| 1608 | long timeout; | ||
| 1609 | |||
| 1610 | if (copy_from_user(&b, arg, sizeof(b))) | ||
| 1611 | return -EFAULT; | ||
| 1612 | |||
| 1613 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) | ||
| 1614 | return -EINVAL; | ||
| 1615 | |||
| 1616 | if (list_empty(&cam->outqueue)) { | ||
| 1617 | if (cam->stream == STREAM_OFF) | ||
| 1618 | return -EINVAL; | ||
| 1619 | if (filp->f_flags & O_NONBLOCK) | ||
| 1620 | return -EAGAIN; | ||
| 1621 | timeout = wait_event_interruptible_timeout | ||
| 1622 | ( cam->wait_frame, | ||
| 1623 | (!list_empty(&cam->outqueue)) || | ||
| 1624 | (cam->state & DEV_DISCONNECTED) || | ||
| 1625 | (cam->state & DEV_MISCONFIGURED), | ||
| 1626 | cam->module_param.frame_timeout * | ||
| 1627 | 1000 * msecs_to_jiffies(1) ); | ||
| 1628 | if (timeout < 0) | ||
| 1629 | return timeout; | ||
| 1630 | if (cam->state & DEV_DISCONNECTED) | ||
| 1631 | return -ENODEV; | ||
| 1632 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) | ||
| 1633 | return -EIO; | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
| 1637 | f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame); | ||
| 1638 | list_del(cam->outqueue.next); | ||
| 1639 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
| 1640 | |||
| 1641 | f->state = F_UNUSED; | ||
| 1642 | |||
| 1643 | memcpy(&b, &f->buf, sizeof(b)); | ||
| 1644 | if (f->vma_use_count) | ||
| 1645 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
| 1646 | |||
| 1647 | if (copy_to_user(arg, &b, sizeof(b))) | ||
| 1648 | return -EFAULT; | ||
| 1649 | |||
| 1650 | PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); | ||
| 1651 | |||
| 1652 | return 0; | ||
| 1653 | } | ||
| 1654 | |||
| 1655 | |||
| 1656 | static int | ||
| 1657 | zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg) | ||
| 1658 | { | ||
| 1659 | int type; | ||
| 1660 | |||
| 1661 | if (copy_from_user(&type, arg, sizeof(type))) | ||
| 1662 | return -EFAULT; | ||
| 1663 | |||
| 1664 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
| 1665 | return -EINVAL; | ||
| 1666 | |||
| 1667 | if (list_empty(&cam->inqueue)) | ||
| 1668 | return -EINVAL; | ||
| 1669 | |||
| 1670 | cam->stream = STREAM_ON; | ||
| 1671 | |||
| 1672 | DBG(3, "Stream on"); | ||
| 1673 | |||
| 1674 | return 0; | ||
| 1675 | } | ||
| 1676 | |||
| 1677 | |||
| 1678 | static int | ||
| 1679 | zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg) | ||
| 1680 | { | ||
| 1681 | int type, err; | ||
| 1682 | |||
| 1683 | if (copy_from_user(&type, arg, sizeof(type))) | ||
| 1684 | return -EFAULT; | ||
| 1685 | |||
| 1686 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
| 1687 | return -EINVAL; | ||
| 1688 | |||
| 1689 | if (cam->stream == STREAM_ON) | ||
| 1690 | if ((err = zc0301_stream_interrupt(cam))) | ||
| 1691 | return err; | ||
| 1692 | |||
| 1693 | zc0301_empty_framequeues(cam); | ||
| 1694 | |||
| 1695 | DBG(3, "Stream off"); | ||
| 1696 | |||
| 1697 | return 0; | ||
| 1698 | } | ||
| 1699 | |||
| 1700 | |||
| 1701 | static int | ||
| 1702 | zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg) | ||
| 1703 | { | ||
| 1704 | struct v4l2_streamparm sp; | ||
| 1705 | |||
| 1706 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
| 1707 | return -EFAULT; | ||
| 1708 | |||
| 1709 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1710 | return -EINVAL; | ||
| 1711 | |||
| 1712 | sp.parm.capture.extendedmode = 0; | ||
| 1713 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
| 1714 | |||
| 1715 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
| 1716 | return -EFAULT; | ||
| 1717 | |||
| 1718 | return 0; | ||
| 1719 | } | ||
| 1720 | |||
| 1721 | |||
| 1722 | static int | ||
| 1723 | zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg) | ||
| 1724 | { | ||
| 1725 | struct v4l2_streamparm sp; | ||
| 1726 | |||
| 1727 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
| 1728 | return -EFAULT; | ||
| 1729 | |||
| 1730 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1731 | return -EINVAL; | ||
| 1732 | |||
| 1733 | sp.parm.capture.extendedmode = 0; | ||
| 1734 | |||
| 1735 | if (sp.parm.capture.readbuffers == 0) | ||
| 1736 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
| 1737 | |||
| 1738 | if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES) | ||
| 1739 | sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES; | ||
| 1740 | |||
| 1741 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
| 1742 | return -EFAULT; | ||
| 1743 | |||
| 1744 | cam->nreadbuffers = sp.parm.capture.readbuffers; | ||
| 1745 | |||
| 1746 | return 0; | ||
| 1747 | } | ||
| 1748 | |||
| 1749 | |||
| 1750 | static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp, | ||
| 1751 | unsigned int cmd, void __user * arg) | ||
| 1752 | { | ||
| 1753 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1754 | |||
| 1755 | switch (cmd) { | ||
| 1756 | |||
| 1757 | case VIDIOC_QUERYCAP: | ||
| 1758 | return zc0301_vidioc_querycap(cam, arg); | ||
| 1759 | |||
| 1760 | case VIDIOC_ENUMINPUT: | ||
| 1761 | return zc0301_vidioc_enuminput(cam, arg); | ||
| 1762 | |||
| 1763 | case VIDIOC_G_INPUT: | ||
| 1764 | return zc0301_vidioc_g_input(cam, arg); | ||
| 1765 | |||
| 1766 | case VIDIOC_S_INPUT: | ||
| 1767 | return zc0301_vidioc_s_input(cam, arg); | ||
| 1768 | |||
| 1769 | case VIDIOC_QUERYCTRL: | ||
| 1770 | return zc0301_vidioc_query_ctrl(cam, arg); | ||
| 1771 | |||
| 1772 | case VIDIOC_G_CTRL: | ||
| 1773 | return zc0301_vidioc_g_ctrl(cam, arg); | ||
| 1774 | |||
| 1775 | case VIDIOC_S_CTRL_OLD: | ||
| 1776 | case VIDIOC_S_CTRL: | ||
| 1777 | return zc0301_vidioc_s_ctrl(cam, arg); | ||
| 1778 | |||
| 1779 | case VIDIOC_CROPCAP_OLD: | ||
| 1780 | case VIDIOC_CROPCAP: | ||
| 1781 | return zc0301_vidioc_cropcap(cam, arg); | ||
| 1782 | |||
| 1783 | case VIDIOC_G_CROP: | ||
| 1784 | return zc0301_vidioc_g_crop(cam, arg); | ||
| 1785 | |||
| 1786 | case VIDIOC_S_CROP: | ||
| 1787 | return zc0301_vidioc_s_crop(cam, arg); | ||
| 1788 | |||
| 1789 | case VIDIOC_ENUM_FMT: | ||
| 1790 | return zc0301_vidioc_enum_fmt(cam, arg); | ||
| 1791 | |||
| 1792 | case VIDIOC_G_FMT: | ||
| 1793 | return zc0301_vidioc_g_fmt(cam, arg); | ||
| 1794 | |||
| 1795 | case VIDIOC_TRY_FMT: | ||
| 1796 | case VIDIOC_S_FMT: | ||
| 1797 | return zc0301_vidioc_try_s_fmt(cam, cmd, arg); | ||
| 1798 | |||
| 1799 | case VIDIOC_G_JPEGCOMP: | ||
| 1800 | return zc0301_vidioc_g_jpegcomp(cam, arg); | ||
| 1801 | |||
| 1802 | case VIDIOC_S_JPEGCOMP: | ||
| 1803 | return zc0301_vidioc_s_jpegcomp(cam, arg); | ||
| 1804 | |||
| 1805 | case VIDIOC_REQBUFS: | ||
| 1806 | return zc0301_vidioc_reqbufs(cam, arg); | ||
| 1807 | |||
| 1808 | case VIDIOC_QUERYBUF: | ||
| 1809 | return zc0301_vidioc_querybuf(cam, arg); | ||
| 1810 | |||
| 1811 | case VIDIOC_QBUF: | ||
| 1812 | return zc0301_vidioc_qbuf(cam, arg); | ||
| 1813 | |||
| 1814 | case VIDIOC_DQBUF: | ||
| 1815 | return zc0301_vidioc_dqbuf(cam, filp, arg); | ||
| 1816 | |||
| 1817 | case VIDIOC_STREAMON: | ||
| 1818 | return zc0301_vidioc_streamon(cam, arg); | ||
| 1819 | |||
| 1820 | case VIDIOC_STREAMOFF: | ||
| 1821 | return zc0301_vidioc_streamoff(cam, arg); | ||
| 1822 | |||
| 1823 | case VIDIOC_G_PARM: | ||
| 1824 | return zc0301_vidioc_g_parm(cam, arg); | ||
| 1825 | |||
| 1826 | case VIDIOC_S_PARM_OLD: | ||
| 1827 | case VIDIOC_S_PARM: | ||
| 1828 | return zc0301_vidioc_s_parm(cam, arg); | ||
| 1829 | |||
| 1830 | case VIDIOC_G_STD: | ||
| 1831 | case VIDIOC_S_STD: | ||
| 1832 | case VIDIOC_QUERYSTD: | ||
| 1833 | case VIDIOC_ENUMSTD: | ||
| 1834 | case VIDIOC_QUERYMENU: | ||
| 1835 | return -EINVAL; | ||
| 1836 | |||
| 1837 | default: | ||
| 1838 | return -EINVAL; | ||
| 1839 | |||
| 1840 | } | ||
| 1841 | } | ||
| 1842 | |||
| 1843 | |||
| 1844 | static int zc0301_ioctl(struct inode* inode, struct file* filp, | ||
| 1845 | unsigned int cmd, unsigned long arg) | ||
| 1846 | { | ||
| 1847 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
| 1848 | int err = 0; | ||
| 1849 | |||
| 1850 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
| 1851 | return -ERESTARTSYS; | ||
| 1852 | |||
| 1853 | if (cam->state & DEV_DISCONNECTED) { | ||
| 1854 | DBG(1, "Device not present"); | ||
| 1855 | mutex_unlock(&cam->fileop_mutex); | ||
| 1856 | return -ENODEV; | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | if (cam->state & DEV_MISCONFIGURED) { | ||
| 1860 | DBG(1, "The camera is misconfigured. Close and open it " | ||
| 1861 | "again."); | ||
| 1862 | mutex_unlock(&cam->fileop_mutex); | ||
| 1863 | return -EIO; | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | V4LDBG(3, "zc0301", cmd); | ||
| 1867 | |||
| 1868 | err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); | ||
| 1869 | |||
| 1870 | mutex_unlock(&cam->fileop_mutex); | ||
| 1871 | |||
| 1872 | return err; | ||
| 1873 | } | ||
| 1874 | |||
| 1875 | |||
| 1876 | static struct file_operations zc0301_fops = { | ||
| 1877 | .owner = THIS_MODULE, | ||
| 1878 | .open = zc0301_open, | ||
| 1879 | .release = zc0301_release, | ||
| 1880 | .ioctl = zc0301_ioctl, | ||
| 1881 | .read = zc0301_read, | ||
| 1882 | .poll = zc0301_poll, | ||
| 1883 | .mmap = zc0301_mmap, | ||
| 1884 | .llseek = no_llseek, | ||
| 1885 | }; | ||
| 1886 | |||
| 1887 | /*****************************************************************************/ | ||
| 1888 | |||
| 1889 | static int | ||
| 1890 | zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
| 1891 | { | ||
| 1892 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 1893 | struct zc0301_device* cam; | ||
| 1894 | static unsigned int dev_nr = 0; | ||
| 1895 | unsigned int i; | ||
| 1896 | int err = 0; | ||
| 1897 | |||
| 1898 | if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL))) | ||
| 1899 | return -ENOMEM; | ||
| 1900 | |||
| 1901 | cam->usbdev = udev; | ||
| 1902 | |||
| 1903 | if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) { | ||
| 1904 | DBG(1, "kmalloc() failed"); | ||
| 1905 | err = -ENOMEM; | ||
| 1906 | goto fail; | ||
| 1907 | } | ||
| 1908 | |||
| 1909 | if (!(cam->v4ldev = video_device_alloc())) { | ||
| 1910 | DBG(1, "video_device_alloc() failed"); | ||
| 1911 | err = -ENOMEM; | ||
| 1912 | goto fail; | ||
| 1913 | } | ||
| 1914 | |||
| 1915 | mutex_init(&cam->dev_mutex); | ||
| 1916 | |||
| 1917 | DBG(2, "ZC0301 Image Processor and Control Chip detected " | ||
| 1918 | "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct); | ||
| 1919 | |||
| 1920 | for (i = 0; zc0301_sensor_table[i]; i++) { | ||
| 1921 | err = zc0301_sensor_table[i](cam); | ||
| 1922 | if (!err) | ||
| 1923 | break; | ||
| 1924 | } | ||
| 1925 | |||
| 1926 | if (!err) | ||
| 1927 | DBG(2, "%s image sensor detected", cam->sensor.name); | ||
| 1928 | else { | ||
| 1929 | DBG(1, "No supported image sensor detected"); | ||
| 1930 | err = -ENODEV; | ||
| 1931 | goto fail; | ||
| 1932 | } | ||
| 1933 | |||
| 1934 | if (zc0301_init(cam)) { | ||
| 1935 | DBG(1, "Initialization failed. I will retry on open()."); | ||
| 1936 | cam->state |= DEV_MISCONFIGURED; | ||
| 1937 | } | ||
| 1938 | |||
| 1939 | strcpy(cam->v4ldev->name, "ZC0301 PC Camera"); | ||
| 1940 | cam->v4ldev->owner = THIS_MODULE; | ||
| 1941 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
| 1942 | cam->v4ldev->hardware = 0; | ||
| 1943 | cam->v4ldev->fops = &zc0301_fops; | ||
| 1944 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
| 1945 | cam->v4ldev->release = video_device_release; | ||
| 1946 | video_set_drvdata(cam->v4ldev, cam); | ||
| 1947 | |||
| 1948 | mutex_lock(&cam->dev_mutex); | ||
| 1949 | |||
| 1950 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
| 1951 | video_nr[dev_nr]); | ||
| 1952 | if (err) { | ||
| 1953 | DBG(1, "V4L2 device registration failed"); | ||
| 1954 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
| 1955 | DBG(1, "Free /dev/videoX node not found"); | ||
| 1956 | video_nr[dev_nr] = -1; | ||
| 1957 | dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
| 1958 | mutex_unlock(&cam->dev_mutex); | ||
| 1959 | goto fail; | ||
| 1960 | } | ||
| 1961 | |||
| 1962 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); | ||
| 1963 | |||
| 1964 | cam->module_param.force_munmap = force_munmap[dev_nr]; | ||
| 1965 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; | ||
| 1966 | |||
| 1967 | dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
| 1968 | |||
| 1969 | usb_set_intfdata(intf, cam); | ||
| 1970 | |||
| 1971 | mutex_unlock(&cam->dev_mutex); | ||
| 1972 | |||
| 1973 | return 0; | ||
| 1974 | |||
| 1975 | fail: | ||
| 1976 | if (cam) { | ||
| 1977 | kfree(cam->control_buffer); | ||
| 1978 | if (cam->v4ldev) | ||
| 1979 | video_device_release(cam->v4ldev); | ||
| 1980 | kfree(cam); | ||
| 1981 | } | ||
| 1982 | return err; | ||
| 1983 | } | ||
| 1984 | |||
| 1985 | |||
| 1986 | static void zc0301_usb_disconnect(struct usb_interface* intf) | ||
| 1987 | { | ||
| 1988 | struct zc0301_device* cam = usb_get_intfdata(intf); | ||
| 1989 | |||
| 1990 | if (!cam) | ||
| 1991 | return; | ||
| 1992 | |||
| 1993 | down_write(&zc0301_disconnect); | ||
| 1994 | |||
| 1995 | mutex_lock(&cam->dev_mutex); | ||
| 1996 | |||
| 1997 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | ||
| 1998 | |||
| 1999 | wake_up_interruptible_all(&cam->open); | ||
| 2000 | |||
| 2001 | if (cam->users) { | ||
| 2002 | DBG(2, "Device /dev/video%d is open! Deregistration and " | ||
| 2003 | "memory deallocation are deferred on close.", | ||
| 2004 | cam->v4ldev->minor); | ||
| 2005 | cam->state |= DEV_MISCONFIGURED; | ||
| 2006 | zc0301_stop_transfer(cam); | ||
| 2007 | cam->state |= DEV_DISCONNECTED; | ||
| 2008 | wake_up_interruptible(&cam->wait_frame); | ||
| 2009 | wake_up(&cam->wait_stream); | ||
| 2010 | usb_get_dev(cam->usbdev); | ||
| 2011 | } else { | ||
| 2012 | cam->state |= DEV_DISCONNECTED; | ||
| 2013 | zc0301_release_resources(cam); | ||
| 2014 | } | ||
| 2015 | |||
| 2016 | mutex_unlock(&cam->dev_mutex); | ||
| 2017 | |||
| 2018 | if (!cam->users) | ||
| 2019 | kfree(cam); | ||
| 2020 | |||
| 2021 | up_write(&zc0301_disconnect); | ||
| 2022 | } | ||
| 2023 | |||
| 2024 | |||
| 2025 | static struct usb_driver zc0301_usb_driver = { | ||
| 2026 | .name = "zc0301", | ||
| 2027 | .id_table = zc0301_id_table, | ||
| 2028 | .probe = zc0301_usb_probe, | ||
| 2029 | .disconnect = zc0301_usb_disconnect, | ||
| 2030 | }; | ||
| 2031 | |||
| 2032 | /*****************************************************************************/ | ||
| 2033 | |||
| 2034 | static int __init zc0301_module_init(void) | ||
| 2035 | { | ||
| 2036 | int err = 0; | ||
| 2037 | |||
| 2038 | KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION); | ||
| 2039 | KDBG(3, ZC0301_MODULE_AUTHOR); | ||
| 2040 | |||
| 2041 | if ((err = usb_register(&zc0301_usb_driver))) | ||
| 2042 | KDBG(1, "usb_register() failed"); | ||
| 2043 | |||
| 2044 | return err; | ||
| 2045 | } | ||
| 2046 | |||
| 2047 | |||
| 2048 | static void __exit zc0301_module_exit(void) | ||
| 2049 | { | ||
| 2050 | usb_deregister(&zc0301_usb_driver); | ||
| 2051 | } | ||
| 2052 | |||
| 2053 | |||
| 2054 | module_init(zc0301_module_init); | ||
| 2055 | module_exit(zc0301_module_exit); | ||
diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c deleted file mode 100644 index 9d282a22c15f..000000000000 --- a/drivers/usb/media/zc0301_pas202bcb.c +++ /dev/null | |||
| @@ -1,361 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Plug-in for PAS202BCB image sensor connected to the ZC030! Image * | ||
| 3 | * Processor and Control Chip * | ||
| 4 | * * | ||
| 5 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
| 6 | * * | ||
| 7 | * Initialization values of the ZC0301 have been taken from the SPCA5XX * | ||
| 8 | * driver maintained by Michel Xhaard <mxhaard@magic.fr> * | ||
| 9 | * * | ||
| 10 | * This program is free software; you can redistribute it and/or modify * | ||
| 11 | * it under the terms of the GNU General Public License as published by * | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or * | ||
| 13 | * (at your option) any later version. * | ||
| 14 | * * | ||
| 15 | * This program is distributed in the hope that it will be useful, * | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 18 | * GNU General Public License for more details. * | ||
| 19 | * * | ||
| 20 | * You should have received a copy of the GNU General Public License * | ||
| 21 | * along with this program; if not, write to the Free Software * | ||
| 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
| 23 | ***************************************************************************/ | ||
| 24 | |||
| 25 | /* | ||
| 26 | NOTE: Sensor controls are disabled for now, becouse changing them while | ||
| 27 | streaming sometimes results in out-of-sync video frames. We'll use | ||
| 28 | the default initialization, until we know how to stop and start video | ||
| 29 | in the chip. However, the image quality still looks good under various | ||
| 30 | light conditions. | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <linux/delay.h> | ||
| 34 | #include "zc0301_sensor.h" | ||
| 35 | |||
| 36 | |||
| 37 | static struct zc0301_sensor pas202bcb; | ||
| 38 | |||
| 39 | |||
| 40 | static int pas202bcb_init(struct zc0301_device* cam) | ||
| 41 | { | ||
| 42 | int err = 0; | ||
| 43 | |||
| 44 | err += zc0301_write_reg(cam, 0x0002, 0x00); | ||
| 45 | err += zc0301_write_reg(cam, 0x0003, 0x02); | ||
| 46 | err += zc0301_write_reg(cam, 0x0004, 0x80); | ||
| 47 | err += zc0301_write_reg(cam, 0x0005, 0x01); | ||
| 48 | err += zc0301_write_reg(cam, 0x0006, 0xE0); | ||
| 49 | err += zc0301_write_reg(cam, 0x0098, 0x00); | ||
| 50 | err += zc0301_write_reg(cam, 0x009A, 0x03); | ||
| 51 | err += zc0301_write_reg(cam, 0x011A, 0x00); | ||
| 52 | err += zc0301_write_reg(cam, 0x011C, 0x03); | ||
| 53 | err += zc0301_write_reg(cam, 0x009B, 0x01); | ||
| 54 | err += zc0301_write_reg(cam, 0x009C, 0xE6); | ||
| 55 | err += zc0301_write_reg(cam, 0x009D, 0x02); | ||
| 56 | err += zc0301_write_reg(cam, 0x009E, 0x86); | ||
| 57 | |||
| 58 | err += zc0301_i2c_write(cam, 0x02, 0x02); | ||
| 59 | err += zc0301_i2c_write(cam, 0x0A, 0x01); | ||
| 60 | err += zc0301_i2c_write(cam, 0x0B, 0x01); | ||
| 61 | err += zc0301_i2c_write(cam, 0x0D, 0x00); | ||
| 62 | err += zc0301_i2c_write(cam, 0x12, 0x05); | ||
| 63 | err += zc0301_i2c_write(cam, 0x13, 0x63); | ||
| 64 | err += zc0301_i2c_write(cam, 0x15, 0x70); | ||
| 65 | |||
| 66 | err += zc0301_write_reg(cam, 0x0101, 0xB7); | ||
| 67 | err += zc0301_write_reg(cam, 0x0100, 0x0D); | ||
| 68 | err += zc0301_write_reg(cam, 0x0189, 0x06); | ||
| 69 | err += zc0301_write_reg(cam, 0x01AD, 0x00); | ||
| 70 | err += zc0301_write_reg(cam, 0x01C5, 0x03); | ||
| 71 | err += zc0301_write_reg(cam, 0x01CB, 0x13); | ||
| 72 | err += zc0301_write_reg(cam, 0x0250, 0x08); | ||
| 73 | err += zc0301_write_reg(cam, 0x0301, 0x08); | ||
| 74 | err += zc0301_write_reg(cam, 0x018D, 0x70); | ||
| 75 | err += zc0301_write_reg(cam, 0x0008, 0x03); | ||
| 76 | err += zc0301_write_reg(cam, 0x01C6, 0x04); | ||
| 77 | err += zc0301_write_reg(cam, 0x01CB, 0x07); | ||
| 78 | err += zc0301_write_reg(cam, 0x0120, 0x11); | ||
| 79 | err += zc0301_write_reg(cam, 0x0121, 0x37); | ||
| 80 | err += zc0301_write_reg(cam, 0x0122, 0x58); | ||
| 81 | err += zc0301_write_reg(cam, 0x0123, 0x79); | ||
| 82 | err += zc0301_write_reg(cam, 0x0124, 0x91); | ||
| 83 | err += zc0301_write_reg(cam, 0x0125, 0xA6); | ||
| 84 | err += zc0301_write_reg(cam, 0x0126, 0xB8); | ||
| 85 | err += zc0301_write_reg(cam, 0x0127, 0xC7); | ||
| 86 | err += zc0301_write_reg(cam, 0x0128, 0xD3); | ||
| 87 | err += zc0301_write_reg(cam, 0x0129, 0xDE); | ||
| 88 | err += zc0301_write_reg(cam, 0x012A, 0xE6); | ||
| 89 | err += zc0301_write_reg(cam, 0x012B, 0xED); | ||
| 90 | err += zc0301_write_reg(cam, 0x012C, 0xF3); | ||
| 91 | err += zc0301_write_reg(cam, 0x012D, 0xF8); | ||
| 92 | err += zc0301_write_reg(cam, 0x012E, 0xFB); | ||
| 93 | err += zc0301_write_reg(cam, 0x012F, 0xFF); | ||
| 94 | err += zc0301_write_reg(cam, 0x0130, 0x26); | ||
| 95 | err += zc0301_write_reg(cam, 0x0131, 0x23); | ||
| 96 | err += zc0301_write_reg(cam, 0x0132, 0x20); | ||
| 97 | err += zc0301_write_reg(cam, 0x0133, 0x1C); | ||
| 98 | err += zc0301_write_reg(cam, 0x0134, 0x16); | ||
| 99 | err += zc0301_write_reg(cam, 0x0135, 0x13); | ||
| 100 | err += zc0301_write_reg(cam, 0x0136, 0x10); | ||
| 101 | err += zc0301_write_reg(cam, 0x0137, 0x0D); | ||
| 102 | err += zc0301_write_reg(cam, 0x0138, 0x0B); | ||
| 103 | err += zc0301_write_reg(cam, 0x0139, 0x09); | ||
| 104 | err += zc0301_write_reg(cam, 0x013A, 0x07); | ||
| 105 | err += zc0301_write_reg(cam, 0x013B, 0x06); | ||
| 106 | err += zc0301_write_reg(cam, 0x013C, 0x05); | ||
| 107 | err += zc0301_write_reg(cam, 0x013D, 0x04); | ||
| 108 | err += zc0301_write_reg(cam, 0x013E, 0x03); | ||
| 109 | err += zc0301_write_reg(cam, 0x013F, 0x02); | ||
| 110 | err += zc0301_write_reg(cam, 0x010A, 0x4C); | ||
| 111 | err += zc0301_write_reg(cam, 0x010B, 0xF5); | ||
| 112 | err += zc0301_write_reg(cam, 0x010C, 0xFF); | ||
| 113 | err += zc0301_write_reg(cam, 0x010D, 0xF9); | ||
| 114 | err += zc0301_write_reg(cam, 0x010E, 0x51); | ||
| 115 | err += zc0301_write_reg(cam, 0x010F, 0xF5); | ||
| 116 | err += zc0301_write_reg(cam, 0x0110, 0xFB); | ||
| 117 | err += zc0301_write_reg(cam, 0x0111, 0xED); | ||
| 118 | err += zc0301_write_reg(cam, 0x0112, 0x5F); | ||
| 119 | err += zc0301_write_reg(cam, 0x0180, 0x00); | ||
| 120 | err += zc0301_write_reg(cam, 0x0019, 0x00); | ||
| 121 | err += zc0301_write_reg(cam, 0x0087, 0x20); | ||
| 122 | err += zc0301_write_reg(cam, 0x0088, 0x21); | ||
| 123 | |||
| 124 | err += zc0301_i2c_write(cam, 0x20, 0x02); | ||
| 125 | err += zc0301_i2c_write(cam, 0x21, 0x1B); | ||
| 126 | err += zc0301_i2c_write(cam, 0x03, 0x44); | ||
| 127 | err += zc0301_i2c_write(cam, 0x0E, 0x01); | ||
| 128 | err += zc0301_i2c_write(cam, 0x0F, 0x00); | ||
| 129 | |||
| 130 | err += zc0301_write_reg(cam, 0x01A9, 0x14); | ||
| 131 | err += zc0301_write_reg(cam, 0x01AA, 0x24); | ||
| 132 | err += zc0301_write_reg(cam, 0x0190, 0x00); | ||
| 133 | err += zc0301_write_reg(cam, 0x0191, 0x02); | ||
| 134 | err += zc0301_write_reg(cam, 0x0192, 0x1B); | ||
| 135 | err += zc0301_write_reg(cam, 0x0195, 0x00); | ||
| 136 | err += zc0301_write_reg(cam, 0x0196, 0x00); | ||
| 137 | err += zc0301_write_reg(cam, 0x0197, 0x4D); | ||
| 138 | err += zc0301_write_reg(cam, 0x018C, 0x10); | ||
| 139 | err += zc0301_write_reg(cam, 0x018F, 0x20); | ||
| 140 | err += zc0301_write_reg(cam, 0x001D, 0x44); | ||
| 141 | err += zc0301_write_reg(cam, 0x001E, 0x6F); | ||
| 142 | err += zc0301_write_reg(cam, 0x001F, 0xAD); | ||
| 143 | err += zc0301_write_reg(cam, 0x0020, 0xEB); | ||
| 144 | err += zc0301_write_reg(cam, 0x0087, 0x0F); | ||
| 145 | err += zc0301_write_reg(cam, 0x0088, 0x0E); | ||
| 146 | err += zc0301_write_reg(cam, 0x0180, 0x40); | ||
| 147 | err += zc0301_write_reg(cam, 0x0192, 0x1B); | ||
| 148 | err += zc0301_write_reg(cam, 0x0191, 0x02); | ||
| 149 | err += zc0301_write_reg(cam, 0x0190, 0x00); | ||
| 150 | err += zc0301_write_reg(cam, 0x0116, 0x1D); | ||
| 151 | err += zc0301_write_reg(cam, 0x0117, 0x40); | ||
| 152 | err += zc0301_write_reg(cam, 0x0118, 0x99); | ||
| 153 | err += zc0301_write_reg(cam, 0x0180, 0x42); | ||
| 154 | err += zc0301_write_reg(cam, 0x0116, 0x1D); | ||
| 155 | err += zc0301_write_reg(cam, 0x0117, 0x40); | ||
| 156 | err += zc0301_write_reg(cam, 0x0118, 0x99); | ||
| 157 | err += zc0301_write_reg(cam, 0x0007, 0x00); | ||
| 158 | |||
| 159 | err += zc0301_i2c_write(cam, 0x11, 0x01); | ||
| 160 | |||
| 161 | msleep(100); | ||
| 162 | |||
| 163 | return err; | ||
| 164 | } | ||
| 165 | |||
| 166 | |||
| 167 | static int pas202bcb_get_ctrl(struct zc0301_device* cam, | ||
| 168 | struct v4l2_control* ctrl) | ||
| 169 | { | ||
| 170 | switch (ctrl->id) { | ||
| 171 | case V4L2_CID_EXPOSURE: | ||
| 172 | { | ||
| 173 | int r1 = zc0301_i2c_read(cam, 0x04, 1), | ||
| 174 | r2 = zc0301_i2c_read(cam, 0x05, 1); | ||
| 175 | if (r1 < 0 || r2 < 0) | ||
| 176 | return -EIO; | ||
| 177 | ctrl->value = (r1 << 6) | (r2 & 0x3f); | ||
| 178 | } | ||
| 179 | return 0; | ||
| 180 | case V4L2_CID_RED_BALANCE: | ||
| 181 | if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0) | ||
| 182 | return -EIO; | ||
| 183 | ctrl->value &= 0x0f; | ||
| 184 | return 0; | ||
| 185 | case V4L2_CID_BLUE_BALANCE: | ||
| 186 | if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0) | ||
| 187 | return -EIO; | ||
| 188 | ctrl->value &= 0x0f; | ||
| 189 | return 0; | ||
| 190 | case V4L2_CID_GAIN: | ||
| 191 | if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0) | ||
| 192 | return -EIO; | ||
| 193 | ctrl->value &= 0x1f; | ||
| 194 | return 0; | ||
| 195 | case ZC0301_V4L2_CID_GREEN_BALANCE: | ||
| 196 | if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0) | ||
| 197 | return -EIO; | ||
| 198 | ctrl->value &= 0x0f; | ||
| 199 | return 0; | ||
| 200 | case ZC0301_V4L2_CID_DAC_MAGNITUDE: | ||
| 201 | if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0) | ||
| 202 | return -EIO; | ||
| 203 | return 0; | ||
| 204 | default: | ||
| 205 | return -EINVAL; | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | |||
| 210 | static int pas202bcb_set_ctrl(struct zc0301_device* cam, | ||
| 211 | const struct v4l2_control* ctrl) | ||
| 212 | { | ||
| 213 | int err = 0; | ||
| 214 | |||
| 215 | switch (ctrl->id) { | ||
| 216 | case V4L2_CID_EXPOSURE: | ||
| 217 | err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6); | ||
| 218 | err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f); | ||
| 219 | break; | ||
| 220 | case V4L2_CID_RED_BALANCE: | ||
| 221 | err += zc0301_i2c_write(cam, 0x09, ctrl->value); | ||
| 222 | break; | ||
| 223 | case V4L2_CID_BLUE_BALANCE: | ||
| 224 | err += zc0301_i2c_write(cam, 0x07, ctrl->value); | ||
| 225 | break; | ||
| 226 | case V4L2_CID_GAIN: | ||
| 227 | err += zc0301_i2c_write(cam, 0x10, ctrl->value); | ||
| 228 | break; | ||
| 229 | case ZC0301_V4L2_CID_GREEN_BALANCE: | ||
| 230 | err += zc0301_i2c_write(cam, 0x08, ctrl->value); | ||
| 231 | break; | ||
| 232 | case ZC0301_V4L2_CID_DAC_MAGNITUDE: | ||
| 233 | err += zc0301_i2c_write(cam, 0x0c, ctrl->value); | ||
| 234 | break; | ||
| 235 | default: | ||
| 236 | return -EINVAL; | ||
| 237 | } | ||
| 238 | err += zc0301_i2c_write(cam, 0x11, 0x01); | ||
| 239 | |||
| 240 | return err ? -EIO : 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | |||
| 244 | static struct zc0301_sensor pas202bcb = { | ||
| 245 | .name = "PAS202BCB", | ||
| 246 | .init = &pas202bcb_init, | ||
| 247 | .qctrl = { | ||
| 248 | { | ||
| 249 | .id = V4L2_CID_EXPOSURE, | ||
| 250 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 251 | .name = "exposure", | ||
| 252 | .minimum = 0x01e5, | ||
| 253 | .maximum = 0x3fff, | ||
| 254 | .step = 0x0001, | ||
| 255 | .default_value = 0x01e5, | ||
| 256 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
| 257 | }, | ||
| 258 | { | ||
| 259 | .id = V4L2_CID_GAIN, | ||
| 260 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 261 | .name = "global gain", | ||
| 262 | .minimum = 0x00, | ||
| 263 | .maximum = 0x1f, | ||
| 264 | .step = 0x01, | ||
| 265 | .default_value = 0x0c, | ||
| 266 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
| 267 | }, | ||
| 268 | { | ||
| 269 | .id = ZC0301_V4L2_CID_DAC_MAGNITUDE, | ||
| 270 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 271 | .name = "DAC magnitude", | ||
| 272 | .minimum = 0x00, | ||
| 273 | .maximum = 0xff, | ||
| 274 | .step = 0x01, | ||
| 275 | .default_value = 0x00, | ||
| 276 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
| 277 | }, | ||
| 278 | { | ||
| 279 | .id = V4L2_CID_RED_BALANCE, | ||
| 280 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 281 | .name = "red balance", | ||
| 282 | .minimum = 0x00, | ||
| 283 | .maximum = 0x0f, | ||
| 284 | .step = 0x01, | ||
| 285 | .default_value = 0x01, | ||
| 286 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
| 287 | }, | ||
| 288 | { | ||
| 289 | .id = V4L2_CID_BLUE_BALANCE, | ||
| 290 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 291 | .name = "blue balance", | ||
| 292 | .minimum = 0x00, | ||
| 293 | .maximum = 0x0f, | ||
| 294 | .step = 0x01, | ||
| 295 | .default_value = 0x05, | ||
| 296 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
| 297 | }, | ||
| 298 | { | ||
| 299 | .id = ZC0301_V4L2_CID_GREEN_BALANCE, | ||
| 300 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 301 | .name = "green balance", | ||
| 302 | .minimum = 0x00, | ||
| 303 | .maximum = 0x0f, | ||
| 304 | .step = 0x01, | ||
| 305 | .default_value = 0x00, | ||
| 306 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
| 307 | }, | ||
| 308 | }, | ||
| 309 | .get_ctrl = &pas202bcb_get_ctrl, | ||
| 310 | .set_ctrl = &pas202bcb_set_ctrl, | ||
| 311 | .cropcap = { | ||
| 312 | .bounds = { | ||
| 313 | .left = 0, | ||
| 314 | .top = 0, | ||
| 315 | .width = 640, | ||
| 316 | .height = 480, | ||
| 317 | }, | ||
| 318 | .defrect = { | ||
| 319 | .left = 0, | ||
| 320 | .top = 0, | ||
| 321 | .width = 640, | ||
| 322 | .height = 480, | ||
| 323 | }, | ||
| 324 | }, | ||
| 325 | .pix_format = { | ||
| 326 | .width = 640, | ||
| 327 | .height = 480, | ||
| 328 | .pixelformat = V4L2_PIX_FMT_JPEG, | ||
| 329 | .priv = 8, | ||
| 330 | }, | ||
| 331 | }; | ||
| 332 | |||
| 333 | |||
| 334 | int zc0301_probe_pas202bcb(struct zc0301_device* cam) | ||
| 335 | { | ||
| 336 | int r0 = 0, r1 = 0, err = 0; | ||
| 337 | unsigned int pid = 0; | ||
| 338 | |||
| 339 | err += zc0301_write_reg(cam, 0x0000, 0x01); | ||
| 340 | err += zc0301_write_reg(cam, 0x0010, 0x0e); | ||
| 341 | err += zc0301_write_reg(cam, 0x0001, 0x01); | ||
| 342 | err += zc0301_write_reg(cam, 0x0012, 0x03); | ||
| 343 | err += zc0301_write_reg(cam, 0x0012, 0x01); | ||
| 344 | err += zc0301_write_reg(cam, 0x008d, 0x08); | ||
| 345 | |||
| 346 | msleep(10); | ||
| 347 | |||
| 348 | r0 = zc0301_i2c_read(cam, 0x00, 1); | ||
| 349 | r1 = zc0301_i2c_read(cam, 0x01, 1); | ||
| 350 | |||
| 351 | if (r0 < 0 || r1 < 0 || err) | ||
| 352 | return -EIO; | ||
| 353 | |||
| 354 | pid = (r0 << 4) | ((r1 & 0xf0) >> 4); | ||
| 355 | if (pid != 0x017) | ||
| 356 | return -ENODEV; | ||
| 357 | |||
| 358 | zc0301_attach_sensor(cam, &pas202bcb); | ||
| 359 | |||
| 360 | return 0; | ||
| 361 | } | ||
diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h deleted file mode 100644 index cf0965a81d01..000000000000 --- a/drivers/usb/media/zc0301_sensor.h +++ /dev/null | |||
| @@ -1,103 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * API for image sensors connected to the ZC030! Image Processor and * | ||
| 3 | * Control Chip * | ||
| 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 | #ifndef _ZC0301_SENSOR_H_ | ||
| 23 | #define _ZC0301_SENSOR_H_ | ||
| 24 | |||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <linux/videodev.h> | ||
| 27 | #include <linux/device.h> | ||
| 28 | #include <linux/stddef.h> | ||
| 29 | #include <linux/errno.h> | ||
| 30 | #include <asm/types.h> | ||
| 31 | |||
| 32 | struct zc0301_device; | ||
| 33 | struct zc0301_sensor; | ||
| 34 | |||
| 35 | /*****************************************************************************/ | ||
| 36 | |||
| 37 | extern int zc0301_probe_pas202bcb(struct zc0301_device* cam); | ||
| 38 | |||
| 39 | #define ZC0301_SENSOR_TABLE \ | ||
| 40 | /* Weak detections must go at the end of the list */ \ | ||
| 41 | static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \ | ||
| 42 | &zc0301_probe_pas202bcb, \ | ||
| 43 | NULL, \ | ||
| 44 | }; | ||
| 45 | |||
| 46 | extern struct zc0301_device* | ||
| 47 | zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id); | ||
| 48 | |||
| 49 | extern void | ||
| 50 | zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor); | ||
| 51 | |||
| 52 | #define ZC0301_USB_DEVICE(vend, prod, intclass) \ | ||
| 53 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | ||
| 54 | USB_DEVICE_ID_MATCH_INT_CLASS, \ | ||
| 55 | .idVendor = (vend), \ | ||
| 56 | .idProduct = (prod), \ | ||
| 57 | .bInterfaceClass = (intclass) | ||
| 58 | |||
| 59 | #define ZC0301_ID_TABLE \ | ||
| 60 | static const struct usb_device_id zc0301_id_table[] = { \ | ||
| 61 | { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, \ | ||
| 62 | { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \ | ||
| 63 | { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */ \ | ||
| 64 | { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \ | ||
| 65 | { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \ | ||
| 66 | { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */ \ | ||
| 67 | { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \ | ||
| 68 | { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */ \ | ||
| 69 | { } \ | ||
| 70 | }; | ||
| 71 | |||
| 72 | /*****************************************************************************/ | ||
| 73 | |||
| 74 | extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value); | ||
| 75 | extern int zc0301_read_reg(struct zc0301_device*, u16 index); | ||
| 76 | extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value); | ||
| 77 | extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length); | ||
| 78 | |||
| 79 | /*****************************************************************************/ | ||
| 80 | |||
| 81 | #define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 | ||
| 82 | #define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE | ||
| 83 | #define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 | ||
| 84 | |||
| 85 | struct zc0301_sensor { | ||
| 86 | char name[32]; | ||
| 87 | |||
| 88 | struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS]; | ||
| 89 | struct v4l2_cropcap cropcap; | ||
| 90 | struct v4l2_pix_format pix_format; | ||
| 91 | |||
| 92 | int (*init)(struct zc0301_device*); | ||
| 93 | int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl); | ||
| 94 | int (*set_ctrl)(struct zc0301_device*, | ||
| 95 | const struct v4l2_control* ctrl); | ||
| 96 | int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect); | ||
| 97 | |||
| 98 | /* Private */ | ||
| 99 | struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS]; | ||
| 100 | struct v4l2_rect _rect; | ||
| 101 | }; | ||
| 102 | |||
| 103 | #endif /* _ZC0301_SENSOR_H_ */ | ||
